2017-05-23 19:15:33 +02:00
|
|
|
/* PipeWire
|
|
|
|
|
*
|
2018-11-05 17:48:52 +01:00
|
|
|
* Copyright © 2018 Wim Taymans
|
2017-05-23 19:15:33 +02:00
|
|
|
*
|
2018-11-05 17:48:52 +01:00
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
|
|
|
* to deal in the Software without restriction, including without limitation
|
|
|
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
|
* Software is furnished to do so, subject to the following conditions:
|
2017-05-23 19:15:33 +02:00
|
|
|
*
|
2018-11-05 17:48:52 +01:00
|
|
|
* The above copyright notice and this permission notice (including the next
|
|
|
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
|
|
|
* Software.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
|
* DEALINGS IN THE SOFTWARE.
|
2017-05-23 19:15:33 +02:00
|
|
|
*/
|
|
|
|
|
|
2017-06-19 12:19:22 +02:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
|
#include "config.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
2017-05-23 19:15:33 +02:00
|
|
|
#include <unistd.h>
|
2017-05-29 10:28:19 +02:00
|
|
|
#include <limits.h>
|
2017-05-23 19:15:33 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <sys/prctl.h>
|
|
|
|
|
#include <pwd.h>
|
2017-06-14 11:48:41 +02:00
|
|
|
#include <errno.h>
|
|
|
|
|
#include <dlfcn.h>
|
2017-05-23 19:15:33 +02:00
|
|
|
|
2017-12-18 12:41:47 +01:00
|
|
|
#include <spa/support/dbus.h>
|
2019-01-07 15:02:18 +01:00
|
|
|
#include <spa/support/cpu.h>
|
2017-12-18 12:41:47 +01:00
|
|
|
|
2018-07-17 10:31:17 +02:00
|
|
|
#include "pipewire.h"
|
|
|
|
|
#include "private.h"
|
2017-05-23 19:15:33 +02:00
|
|
|
|
2018-04-20 16:27:19 +02:00
|
|
|
#define MAX_SUPPORT 32
|
2017-05-29 10:28:19 +02:00
|
|
|
|
2018-04-20 16:27:19 +02:00
|
|
|
struct plugin {
|
|
|
|
|
int ref;
|
|
|
|
|
struct spa_list link;
|
|
|
|
|
char *filename;
|
2017-06-14 11:48:41 +02:00
|
|
|
void *hnd;
|
|
|
|
|
spa_handle_factory_enum_func_t enum_func;
|
2018-04-20 16:27:19 +02:00
|
|
|
struct spa_list handles;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct handle {
|
|
|
|
|
int ref;
|
|
|
|
|
struct spa_list link;
|
|
|
|
|
struct plugin *plugin;
|
|
|
|
|
const char *factory_name;
|
|
|
|
|
struct spa_handle *handle;
|
|
|
|
|
struct spa_list interfaces;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct interface {
|
|
|
|
|
int ref;
|
|
|
|
|
struct spa_list link;
|
|
|
|
|
struct handle *handle;
|
2018-08-23 17:47:57 +02:00
|
|
|
uint32_t type;
|
2018-04-20 16:27:19 +02:00
|
|
|
void *iface;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct registry {
|
|
|
|
|
struct spa_list plugins;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct support {
|
|
|
|
|
char **categories;
|
|
|
|
|
const char *plugin_dir;
|
|
|
|
|
struct plugin *support_plugin;
|
|
|
|
|
struct spa_support support[MAX_SUPPORT];
|
2017-06-14 11:48:41 +02:00
|
|
|
uint32_t n_support;
|
2018-04-20 16:27:19 +02:00
|
|
|
struct registry *registry;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct registry global_registry;
|
|
|
|
|
static struct support global_support;
|
2017-06-14 11:48:41 +02:00
|
|
|
|
2018-04-20 16:27:19 +02:00
|
|
|
static struct plugin *
|
|
|
|
|
find_plugin(struct registry *registry, const char *filename)
|
2017-06-14 11:48:41 +02:00
|
|
|
{
|
2018-04-20 16:27:19 +02:00
|
|
|
struct plugin *p;
|
|
|
|
|
spa_list_for_each(p, ®istry->plugins, link) {
|
|
|
|
|
if (!strcmp(p->filename, filename))
|
|
|
|
|
return p;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct plugin *
|
|
|
|
|
open_plugin(struct registry *registry,
|
|
|
|
|
const char *path,
|
|
|
|
|
const char *lib)
|
|
|
|
|
{
|
|
|
|
|
struct plugin *plugin;
|
2017-06-19 12:19:22 +02:00
|
|
|
char *filename;
|
2018-04-20 16:27:19 +02:00
|
|
|
void *hnd;
|
|
|
|
|
spa_handle_factory_enum_func_t enum_func;
|
2017-06-19 12:19:22 +02:00
|
|
|
|
2017-07-04 12:21:01 +02:00
|
|
|
if (asprintf(&filename, "%s/%s.so", path, lib) < 0)
|
|
|
|
|
goto no_filename;
|
2017-06-19 12:19:22 +02:00
|
|
|
|
2018-04-20 16:27:19 +02:00
|
|
|
if ((plugin = find_plugin(registry, filename)) != NULL) {
|
|
|
|
|
free(filename);
|
|
|
|
|
plugin->ref++;
|
|
|
|
|
return plugin;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((hnd = dlopen(filename, RTLD_NOW)) == NULL) {
|
2017-06-19 12:19:22 +02:00
|
|
|
fprintf(stderr, "can't load %s: %s\n", filename, dlerror());
|
|
|
|
|
goto open_failed;
|
2017-06-14 11:48:41 +02:00
|
|
|
}
|
2018-04-20 16:27:19 +02:00
|
|
|
if ((enum_func = dlsym(hnd, SPA_HANDLE_FACTORY_ENUM_FUNC_NAME)) == NULL) {
|
2017-06-14 11:48:41 +02:00
|
|
|
fprintf(stderr, "can't find enum function\n");
|
|
|
|
|
goto no_symbol;
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-20 16:27:19 +02:00
|
|
|
if ((plugin = calloc(1, sizeof(struct plugin))) == NULL)
|
|
|
|
|
goto alloc_failed;
|
|
|
|
|
|
|
|
|
|
plugin->ref = 1;
|
|
|
|
|
plugin->filename = filename;
|
|
|
|
|
plugin->hnd = hnd;
|
|
|
|
|
plugin->enum_func = enum_func;
|
|
|
|
|
spa_list_init(&plugin->handles);
|
|
|
|
|
|
|
|
|
|
spa_list_append(®istry->plugins, &plugin->link);
|
|
|
|
|
|
|
|
|
|
return plugin;
|
|
|
|
|
|
|
|
|
|
alloc_failed:
|
2017-06-14 11:48:41 +02:00
|
|
|
no_symbol:
|
2018-04-20 16:27:19 +02:00
|
|
|
dlclose(hnd);
|
2017-06-19 12:19:22 +02:00
|
|
|
open_failed:
|
|
|
|
|
free(filename);
|
2018-04-20 16:27:19 +02:00
|
|
|
no_filename:
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
unref_plugin(struct plugin *plugin)
|
|
|
|
|
{
|
|
|
|
|
if (--plugin->ref == 0) {
|
|
|
|
|
spa_list_remove(&plugin->link);
|
|
|
|
|
dlclose(plugin->hnd);
|
|
|
|
|
free(plugin->filename);
|
|
|
|
|
free(plugin);
|
|
|
|
|
}
|
2017-06-14 11:48:41 +02:00
|
|
|
}
|
|
|
|
|
|
2018-04-20 16:27:19 +02:00
|
|
|
static const struct spa_handle_factory *find_factory(struct plugin *plugin, const char *factory_name)
|
2017-12-18 12:41:47 +01:00
|
|
|
{
|
|
|
|
|
int res;
|
|
|
|
|
uint32_t index;
|
|
|
|
|
const struct spa_handle_factory *factory;
|
|
|
|
|
|
|
|
|
|
for (index = 0;;) {
|
2018-04-20 16:27:19 +02:00
|
|
|
if ((res = plugin->enum_func(&factory, &index)) <= 0) {
|
2017-12-18 12:41:47 +01:00
|
|
|
if (res != 0)
|
|
|
|
|
fprintf(stderr, "can't enumerate factories: %s\n", spa_strerror(res));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (strcmp(factory->name, factory_name) == 0)
|
|
|
|
|
return factory;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-20 16:27:19 +02:00
|
|
|
static struct handle *
|
|
|
|
|
load_handle(struct plugin *plugin,
|
|
|
|
|
const char *factory_name,
|
2018-04-26 09:48:19 +02:00
|
|
|
const struct spa_dict *info,
|
2018-04-20 16:27:19 +02:00
|
|
|
uint32_t n_support,
|
|
|
|
|
struct spa_support support[n_support])
|
2017-06-14 11:48:41 +02:00
|
|
|
{
|
|
|
|
|
int res;
|
2018-04-20 16:27:19 +02:00
|
|
|
struct handle *handle;
|
|
|
|
|
struct spa_handle *hnd;
|
2017-06-14 11:48:41 +02:00
|
|
|
const struct spa_handle_factory *factory;
|
|
|
|
|
|
2018-04-20 16:27:19 +02:00
|
|
|
factory = find_factory(plugin, factory_name);
|
2017-06-14 16:10:07 +02:00
|
|
|
if (factory == NULL)
|
|
|
|
|
goto not_found;
|
2017-06-14 11:48:41 +02:00
|
|
|
|
2018-04-20 16:27:19 +02:00
|
|
|
hnd = calloc(1, spa_handle_factory_get_size(factory, NULL));
|
|
|
|
|
if (hnd == NULL)
|
|
|
|
|
goto alloc_failed;
|
|
|
|
|
|
2017-06-14 11:48:41 +02:00
|
|
|
if ((res = spa_handle_factory_init(factory,
|
2018-04-26 09:48:19 +02:00
|
|
|
hnd, info,
|
2018-04-20 16:27:19 +02:00
|
|
|
support, n_support)) < 0) {
|
2018-06-01 11:19:54 +02:00
|
|
|
fprintf(stderr, "can't make factory instance %s: %d\n", factory_name, res);
|
2017-06-14 11:48:41 +02:00
|
|
|
goto init_failed;
|
|
|
|
|
}
|
2017-06-14 16:10:07 +02:00
|
|
|
|
2018-04-20 16:27:19 +02:00
|
|
|
if ((handle = calloc(1, sizeof(struct handle))) == NULL)
|
|
|
|
|
goto handle_failed;
|
|
|
|
|
|
|
|
|
|
handle->ref = 1;
|
|
|
|
|
handle->plugin = plugin;
|
|
|
|
|
handle->factory_name = factory_name;
|
|
|
|
|
handle->handle = hnd;
|
|
|
|
|
spa_list_init(&handle->interfaces);
|
|
|
|
|
|
|
|
|
|
spa_list_append(&plugin->handles, &handle->link);
|
|
|
|
|
|
|
|
|
|
return handle;
|
|
|
|
|
|
|
|
|
|
handle_failed:
|
|
|
|
|
spa_handle_clear(hnd);
|
|
|
|
|
init_failed:
|
|
|
|
|
free(hnd);
|
|
|
|
|
alloc_failed:
|
|
|
|
|
not_found:
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void unref_handle(struct handle *handle)
|
|
|
|
|
{
|
|
|
|
|
if (--handle->ref == 0) {
|
|
|
|
|
spa_list_remove(&handle->link);
|
|
|
|
|
spa_handle_clear(handle->handle);
|
|
|
|
|
free(handle->handle);
|
|
|
|
|
unref_plugin(handle->plugin);
|
|
|
|
|
free(handle);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct interface *
|
|
|
|
|
load_interface(struct plugin *plugin,
|
|
|
|
|
const char *factory_name,
|
2018-08-23 17:47:57 +02:00
|
|
|
uint32_t type_id,
|
2018-04-26 09:48:19 +02:00
|
|
|
const struct spa_dict *info,
|
2018-04-20 16:27:19 +02:00
|
|
|
uint32_t n_support,
|
|
|
|
|
struct spa_support support[n_support])
|
|
|
|
|
{
|
|
|
|
|
int res;
|
|
|
|
|
struct handle *handle;
|
|
|
|
|
void *ptr;
|
|
|
|
|
struct interface *iface;
|
|
|
|
|
|
2018-04-26 09:48:19 +02:00
|
|
|
handle = load_handle(plugin, factory_name, info, n_support, support);
|
2018-04-20 16:27:19 +02:00
|
|
|
if (handle == NULL)
|
|
|
|
|
goto not_found;
|
|
|
|
|
|
|
|
|
|
if ((res = spa_handle_get_interface(handle->handle, type_id, &ptr)) < 0) {
|
2018-08-23 17:47:57 +02:00
|
|
|
fprintf(stderr, "can't get %d interface %d\n", type_id, res);
|
2017-06-14 11:48:41 +02:00
|
|
|
goto interface_failed;
|
|
|
|
|
}
|
2018-04-20 16:27:19 +02:00
|
|
|
|
|
|
|
|
if ((iface = calloc(1, sizeof(struct interface))) == NULL)
|
|
|
|
|
goto alloc_failed;
|
|
|
|
|
|
|
|
|
|
iface->ref = 1;
|
|
|
|
|
iface->handle = handle;
|
2018-08-23 17:47:57 +02:00
|
|
|
iface->type = type_id;
|
2018-04-20 16:27:19 +02:00
|
|
|
iface->iface = ptr;
|
|
|
|
|
spa_list_append(&handle->interfaces, &iface->link);
|
|
|
|
|
|
2017-06-14 11:48:41 +02:00
|
|
|
return iface;
|
|
|
|
|
|
2018-04-20 16:27:19 +02:00
|
|
|
alloc_failed:
|
2017-06-14 11:48:41 +02:00
|
|
|
interface_failed:
|
2018-04-20 16:27:19 +02:00
|
|
|
unref_handle(handle);
|
2017-06-14 11:48:41 +02:00
|
|
|
free(handle);
|
2017-06-14 16:10:07 +02:00
|
|
|
not_found:
|
2017-06-14 11:48:41 +02:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-20 16:27:19 +02:00
|
|
|
static void
|
|
|
|
|
unref_interface(struct interface *iface)
|
|
|
|
|
{
|
|
|
|
|
if (--iface->ref == 0) {
|
|
|
|
|
spa_list_remove(&iface->link);
|
|
|
|
|
unref_handle(iface->handle);
|
|
|
|
|
free(iface);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void configure_debug(struct support *support, const char *str)
|
2017-05-29 10:28:19 +02:00
|
|
|
{
|
|
|
|
|
char **level;
|
|
|
|
|
int n_tokens;
|
|
|
|
|
|
|
|
|
|
level = pw_split_strv(str, ":", INT_MAX, &n_tokens);
|
|
|
|
|
if (n_tokens > 0)
|
|
|
|
|
pw_log_set_level(atoi(level[0]));
|
|
|
|
|
|
|
|
|
|
if (n_tokens > 1)
|
2018-04-20 16:27:19 +02:00
|
|
|
support->categories = pw_split_strv(level[1], ",", INT_MAX, &n_tokens);
|
2017-05-29 10:28:19 +02:00
|
|
|
}
|
|
|
|
|
|
2017-06-14 11:48:41 +02:00
|
|
|
/** Get a support interface
|
|
|
|
|
* \param type the interface type
|
|
|
|
|
* \return the interface or NULL when not configured
|
|
|
|
|
*/
|
2019-02-06 13:24:41 +01:00
|
|
|
SPA_EXPORT
|
2018-08-23 17:47:57 +02:00
|
|
|
void *pw_get_support_interface(uint32_t type)
|
2017-06-14 11:48:41 +02:00
|
|
|
{
|
2018-04-20 16:27:19 +02:00
|
|
|
return spa_support_find(global_support.support, global_support.n_support, type);
|
2017-06-14 11:48:41 +02:00
|
|
|
}
|
|
|
|
|
|
2019-02-06 13:24:41 +01:00
|
|
|
SPA_EXPORT
|
2017-06-14 16:10:07 +02:00
|
|
|
const struct spa_handle_factory *pw_get_support_factory(const char *factory_name)
|
|
|
|
|
{
|
2018-04-20 16:27:19 +02:00
|
|
|
struct plugin *plugin = global_support.support_plugin;
|
2019-01-09 10:48:18 +01:00
|
|
|
if (plugin == NULL)
|
|
|
|
|
return NULL;
|
2018-04-20 16:27:19 +02:00
|
|
|
return find_factory(plugin, factory_name);
|
2017-06-14 16:10:07 +02:00
|
|
|
}
|
|
|
|
|
|
2019-02-06 13:24:41 +01:00
|
|
|
SPA_EXPORT
|
2017-06-14 16:10:07 +02:00
|
|
|
const struct spa_support *pw_get_support(uint32_t *n_support)
|
|
|
|
|
{
|
2018-04-20 16:27:19 +02:00
|
|
|
*n_support = global_support.n_support;
|
|
|
|
|
return global_support.support;
|
2017-06-14 16:10:07 +02:00
|
|
|
}
|
2017-06-14 11:48:41 +02:00
|
|
|
|
2019-02-06 13:24:41 +01:00
|
|
|
SPA_EXPORT
|
2018-08-23 17:47:57 +02:00
|
|
|
void *pw_load_spa_interface(const char *lib, const char *factory_name, uint32_t type,
|
2018-04-26 09:48:19 +02:00
|
|
|
const struct spa_dict *info,
|
|
|
|
|
uint32_t n_support,
|
2018-11-23 12:43:47 +01:00
|
|
|
const struct spa_support support[])
|
2017-12-18 12:41:47 +01:00
|
|
|
{
|
2018-04-20 16:27:19 +02:00
|
|
|
struct support *sup = &global_support;
|
|
|
|
|
struct spa_support extra_support[MAX_SUPPORT];
|
|
|
|
|
uint32_t extra_n_support;
|
|
|
|
|
struct plugin *plugin;
|
|
|
|
|
struct interface *iface;
|
2019-01-07 15:52:42 +01:00
|
|
|
uint32_t i;
|
2017-12-18 12:41:47 +01:00
|
|
|
|
2018-04-20 16:27:19 +02:00
|
|
|
extra_n_support = sup->n_support;
|
|
|
|
|
memcpy(extra_support, sup->support,
|
|
|
|
|
sizeof(struct spa_support) * sup->n_support);
|
2017-12-18 12:41:47 +01:00
|
|
|
|
2018-04-05 15:34:33 +02:00
|
|
|
for (i = 0; i < n_support; i++) {
|
2018-04-20 16:27:19 +02:00
|
|
|
extra_support[extra_n_support++] =
|
2018-04-05 15:34:33 +02:00
|
|
|
SPA_SUPPORT_INIT(support[i].type, support[i].data);
|
|
|
|
|
}
|
|
|
|
|
pw_log_debug("load \"%s\", \"%s\"", lib, factory_name);
|
2018-04-26 09:48:19 +02:00
|
|
|
if ((plugin = open_plugin(sup->registry, sup->plugin_dir, lib)) == NULL) {
|
|
|
|
|
pw_log_warn("can't load '%s'", lib);
|
2018-04-20 16:27:19 +02:00
|
|
|
return NULL;
|
2018-04-26 09:48:19 +02:00
|
|
|
}
|
2018-04-05 15:34:33 +02:00
|
|
|
|
2018-04-26 09:48:19 +02:00
|
|
|
if ((iface = load_interface(plugin, factory_name, type, info,
|
|
|
|
|
extra_n_support, extra_support)) == NULL)
|
2018-04-20 16:27:19 +02:00
|
|
|
return NULL;
|
2017-12-18 12:41:47 +01:00
|
|
|
|
2018-04-20 16:27:19 +02:00
|
|
|
return iface->iface;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct interface *find_interface(void *iface)
|
|
|
|
|
{
|
|
|
|
|
struct registry *registry = global_support.registry;
|
|
|
|
|
struct plugin *p;
|
|
|
|
|
struct handle *h;
|
|
|
|
|
struct interface *i;
|
|
|
|
|
|
|
|
|
|
spa_list_for_each(p, ®istry->plugins, link) {
|
|
|
|
|
spa_list_for_each(h, &p->handles, link) {
|
|
|
|
|
spa_list_for_each(i, &h->interfaces, link) {
|
|
|
|
|
if (i->iface == iface)
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-12-18 12:41:47 +01:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-06 13:24:41 +01:00
|
|
|
SPA_EXPORT
|
2018-04-20 16:27:19 +02:00
|
|
|
int pw_unload_spa_interface(void *iface)
|
|
|
|
|
{
|
|
|
|
|
struct interface *i;
|
|
|
|
|
|
|
|
|
|
if ((i = find_interface(iface)) == NULL)
|
|
|
|
|
return -ENOENT;
|
|
|
|
|
|
|
|
|
|
unref_interface(i);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-06 13:24:41 +01:00
|
|
|
SPA_EXPORT
|
2018-09-19 13:38:39 +02:00
|
|
|
void *pw_load_spa_dbus_interface(struct pw_loop *loop)
|
2018-04-05 15:34:33 +02:00
|
|
|
{
|
2018-08-27 15:03:11 +02:00
|
|
|
struct spa_support support = SPA_SUPPORT_INIT(SPA_TYPE_INTERFACE_LoopUtils, loop->utils);
|
2018-04-05 15:34:33 +02:00
|
|
|
|
2018-08-27 15:03:11 +02:00
|
|
|
return pw_load_spa_interface("support/libspa-dbus", "dbus", SPA_TYPE_INTERFACE_DBus,
|
2018-04-26 09:48:19 +02:00
|
|
|
NULL, 1, &support);
|
2018-04-05 15:34:33 +02:00
|
|
|
}
|
|
|
|
|
|
2017-05-30 19:46:51 +02:00
|
|
|
/** Initialize PipeWire
|
2017-05-23 19:15:33 +02:00
|
|
|
*
|
2017-05-30 19:46:51 +02:00
|
|
|
* \param argc pointer to argc
|
|
|
|
|
* \param argv pointer to argv
|
|
|
|
|
*
|
|
|
|
|
* Initialize the PipeWire system, parse and modify any parameters given
|
|
|
|
|
* by \a argc and \a argv and set up debugging.
|
|
|
|
|
*
|
|
|
|
|
* The environment variable \a PIPEWIRE_DEBUG
|
|
|
|
|
*
|
|
|
|
|
* \memberof pw_pipewire
|
2017-05-23 19:15:33 +02:00
|
|
|
*/
|
2019-02-06 13:24:41 +01:00
|
|
|
SPA_EXPORT
|
2017-05-26 08:05:01 +02:00
|
|
|
void pw_init(int *argc, char **argv[])
|
2017-05-23 19:15:33 +02:00
|
|
|
{
|
2017-05-26 08:05:01 +02:00
|
|
|
const char *str;
|
2018-04-20 16:27:19 +02:00
|
|
|
struct interface *iface;
|
|
|
|
|
struct support *support = &global_support;
|
|
|
|
|
struct plugin *plugin;
|
2018-04-26 09:48:19 +02:00
|
|
|
struct spa_dict info;
|
|
|
|
|
struct spa_dict_item items[1];
|
2017-05-23 19:15:33 +02:00
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
if ((str = getenv("PIPEWIRE_DEBUG")))
|
2018-04-20 16:27:19 +02:00
|
|
|
configure_debug(support, str);
|
2017-06-14 11:48:41 +02:00
|
|
|
|
2017-06-19 12:19:22 +02:00
|
|
|
if ((str = getenv("SPA_PLUGIN_DIR")) == NULL)
|
|
|
|
|
str = PLUGINDIR;
|
|
|
|
|
|
2018-04-20 16:27:19 +02:00
|
|
|
support->plugin_dir = str;
|
|
|
|
|
spa_list_init(&global_registry.plugins);
|
|
|
|
|
support->registry = &global_registry;
|
|
|
|
|
|
|
|
|
|
if (support->n_support > 0)
|
2017-10-17 10:14:56 +02:00
|
|
|
return;
|
|
|
|
|
|
2018-04-20 16:27:19 +02:00
|
|
|
plugin = open_plugin(support->registry, support->plugin_dir, "support/libspa-support");
|
|
|
|
|
if (plugin == NULL) {
|
|
|
|
|
fprintf(stderr, "can't open support library");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-12-18 12:41:47 +01:00
|
|
|
|
2018-04-20 16:27:19 +02:00
|
|
|
support->support_plugin = plugin;
|
|
|
|
|
|
2018-04-26 09:48:19 +02:00
|
|
|
items[0] = SPA_DICT_ITEM_INIT("log.colors", "1");
|
|
|
|
|
info = SPA_DICT_INIT(items, 1);
|
|
|
|
|
|
2018-08-27 15:03:11 +02:00
|
|
|
iface = load_interface(plugin, "logger", SPA_TYPE_INTERFACE_Log, &info,
|
2018-04-20 16:27:19 +02:00
|
|
|
support->n_support, support->support);
|
|
|
|
|
if (iface != NULL) {
|
|
|
|
|
support->support[support->n_support++] =
|
2018-08-27 15:03:11 +02:00
|
|
|
SPA_SUPPORT_INIT(SPA_TYPE_INTERFACE_Log, iface->iface);
|
2018-04-20 16:27:19 +02:00
|
|
|
pw_log_set(iface->iface);
|
2017-12-18 12:41:47 +01:00
|
|
|
}
|
2018-12-17 13:26:04 +01:00
|
|
|
iface = load_interface(plugin, "cpu", SPA_TYPE_INTERFACE_CPU, &info,
|
|
|
|
|
support->n_support, support->support);
|
|
|
|
|
if (iface != NULL) {
|
2019-01-07 15:02:18 +01:00
|
|
|
struct spa_cpu *cpu = iface->iface;
|
|
|
|
|
if ((str = getenv("PIPEWIRE_CPU")))
|
|
|
|
|
spa_cpu_force_flags(cpu, strtoul(str, NULL, 0));
|
|
|
|
|
|
2018-12-17 13:26:04 +01:00
|
|
|
support->support[support->n_support++] =
|
|
|
|
|
SPA_SUPPORT_INIT(SPA_TYPE_INTERFACE_CPU, iface->iface);
|
|
|
|
|
}
|
2018-08-13 15:46:48 +02:00
|
|
|
pw_log_info("version %s", pw_get_library_version());
|
2017-05-29 10:28:19 +02:00
|
|
|
}
|
|
|
|
|
|
2017-05-30 19:46:51 +02:00
|
|
|
/** Check if a debug category is enabled
|
|
|
|
|
*
|
|
|
|
|
* \param name the name of the category to check
|
|
|
|
|
* \return true if enabled
|
|
|
|
|
*
|
|
|
|
|
* Debugging categories can be enabled by using the PIPEWIRE_DEBUG
|
|
|
|
|
* environment variable
|
|
|
|
|
*
|
|
|
|
|
* \memberof pw_pipewire
|
|
|
|
|
*/
|
2019-02-06 13:24:41 +01:00
|
|
|
SPA_EXPORT
|
2017-05-29 10:28:19 +02:00
|
|
|
bool pw_debug_is_category_enabled(const char *name)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
2018-04-20 16:27:19 +02:00
|
|
|
if (global_support.categories == NULL)
|
2017-05-29 10:28:19 +02:00
|
|
|
return false;
|
|
|
|
|
|
2018-04-20 16:27:19 +02:00
|
|
|
for (i = 0; global_support.categories[i]; i++) {
|
|
|
|
|
if (strcmp(global_support.categories[i], name) == 0)
|
2017-05-29 10:28:19 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
2017-05-23 19:15:33 +02:00
|
|
|
}
|
|
|
|
|
|
2017-05-30 19:46:51 +02:00
|
|
|
/** Get the application name \memberof pw_pipewire */
|
2019-02-06 13:24:41 +01:00
|
|
|
SPA_EXPORT
|
2017-05-26 08:05:01 +02:00
|
|
|
const char *pw_get_application_name(void)
|
2017-05-23 19:15:33 +02:00
|
|
|
{
|
2017-05-26 08:05:01 +02:00
|
|
|
return NULL;
|
2017-05-23 19:15:33 +02:00
|
|
|
}
|
|
|
|
|
|
2017-05-30 19:46:51 +02:00
|
|
|
/** Get the program name \memberof pw_pipewire */
|
2019-02-06 13:24:41 +01:00
|
|
|
SPA_EXPORT
|
2017-05-26 08:05:01 +02:00
|
|
|
const char *pw_get_prgname(void)
|
2017-05-23 19:15:33 +02:00
|
|
|
{
|
2017-05-26 08:05:01 +02:00
|
|
|
static char tcomm[16 + 1];
|
|
|
|
|
spa_zero(tcomm);
|
2017-05-23 19:15:33 +02:00
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
if (prctl(PR_GET_NAME, (unsigned long) tcomm, 0, 0, 0) == 0)
|
|
|
|
|
return tcomm;
|
2017-05-23 19:15:33 +02:00
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
return NULL;
|
2017-05-23 19:15:33 +02:00
|
|
|
}
|
|
|
|
|
|
2017-05-30 19:46:51 +02:00
|
|
|
/** Get the user name \memberof pw_pipewire */
|
2019-02-06 13:24:41 +01:00
|
|
|
SPA_EXPORT
|
2017-05-26 08:05:01 +02:00
|
|
|
const char *pw_get_user_name(void)
|
2017-05-23 19:15:33 +02:00
|
|
|
{
|
2017-05-26 08:05:01 +02:00
|
|
|
struct passwd *pw;
|
2017-05-23 19:15:33 +02:00
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
if ((pw = getpwuid(getuid())))
|
|
|
|
|
return pw->pw_name;
|
2017-05-23 19:15:33 +02:00
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
return NULL;
|
2017-05-23 19:15:33 +02:00
|
|
|
}
|
|
|
|
|
|
2017-05-30 19:46:51 +02:00
|
|
|
/** Get the host name \memberof pw_pipewire */
|
2019-02-06 13:24:41 +01:00
|
|
|
SPA_EXPORT
|
2017-05-26 08:05:01 +02:00
|
|
|
const char *pw_get_host_name(void)
|
2017-05-23 19:15:33 +02:00
|
|
|
{
|
2017-05-26 08:05:01 +02:00
|
|
|
static char hname[256];
|
2017-05-23 19:15:33 +02:00
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
if (gethostname(hname, 256) < 0)
|
|
|
|
|
return NULL;
|
2017-05-23 19:15:33 +02:00
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
hname[255] = 0;
|
|
|
|
|
return hname;
|
2017-05-23 19:15:33 +02:00
|
|
|
}
|
|
|
|
|
|
2017-05-30 19:46:51 +02:00
|
|
|
/** Get the client name
|
2017-05-23 19:15:33 +02:00
|
|
|
*
|
2017-07-11 15:57:20 +02:00
|
|
|
* Make a new PipeWire client name that can be used to construct a remote.
|
2017-05-30 19:46:51 +02:00
|
|
|
*
|
|
|
|
|
* \memberof pw_pipewire
|
2017-05-23 19:15:33 +02:00
|
|
|
*/
|
2019-02-06 13:24:41 +01:00
|
|
|
SPA_EXPORT
|
2018-09-19 13:38:39 +02:00
|
|
|
const char *pw_get_client_name(void)
|
2017-05-23 19:15:33 +02:00
|
|
|
{
|
2017-05-26 08:05:01 +02:00
|
|
|
const char *cc;
|
2018-09-19 13:38:39 +02:00
|
|
|
static char cname[256];
|
2017-05-26 08:05:01 +02:00
|
|
|
|
|
|
|
|
if ((cc = pw_get_application_name()))
|
2018-09-19 13:38:39 +02:00
|
|
|
return cc;
|
2017-05-26 08:05:01 +02:00
|
|
|
else if ((cc = pw_get_prgname()))
|
2018-09-19 13:38:39 +02:00
|
|
|
return cc;
|
2017-05-26 08:05:01 +02:00
|
|
|
else {
|
2018-09-19 13:38:39 +02:00
|
|
|
if (snprintf(cname, sizeof(cname), "pipewire-pid-%zd", (size_t) getpid()) < 0)
|
2017-07-04 12:21:01 +02:00
|
|
|
return NULL;
|
2018-09-19 13:38:39 +02:00
|
|
|
cname[255] = 0;
|
|
|
|
|
return cname;
|
2017-05-26 08:05:01 +02:00
|
|
|
}
|
2017-05-23 19:15:33 +02:00
|
|
|
}
|
|
|
|
|
|
2017-07-11 15:57:20 +02:00
|
|
|
/** Fill remote properties
|
2017-05-30 19:46:51 +02:00
|
|
|
* \param properties a \ref pw_properties
|
2017-05-23 19:15:33 +02:00
|
|
|
*
|
2017-07-11 15:57:20 +02:00
|
|
|
* Fill \a properties with a set of default remote properties.
|
2017-05-30 19:46:51 +02:00
|
|
|
*
|
|
|
|
|
* \memberof pw_pipewire
|
2017-05-23 19:15:33 +02:00
|
|
|
*/
|
2019-02-06 13:24:41 +01:00
|
|
|
SPA_EXPORT
|
2017-07-11 20:38:48 +02:00
|
|
|
void pw_fill_remote_properties(struct pw_core *core, struct pw_properties *properties)
|
2017-05-23 19:15:33 +02:00
|
|
|
{
|
2017-07-11 20:38:48 +02:00
|
|
|
const char *val;
|
|
|
|
|
|
2017-05-26 08:05:01 +02:00
|
|
|
if (!pw_properties_get(properties, "application.name"))
|
2018-06-01 11:19:54 +02:00
|
|
|
pw_properties_set(properties, "application.name", pw_get_client_name());
|
2017-05-26 08:05:01 +02:00
|
|
|
|
|
|
|
|
if (!pw_properties_get(properties, "application.prgname"))
|
|
|
|
|
pw_properties_set(properties, "application.prgname", pw_get_prgname());
|
|
|
|
|
|
|
|
|
|
if (!pw_properties_get(properties, "application.language")) {
|
|
|
|
|
pw_properties_set(properties, "application.language", getenv("LANG"));
|
|
|
|
|
}
|
|
|
|
|
if (!pw_properties_get(properties, "application.process.id")) {
|
|
|
|
|
pw_properties_setf(properties, "application.process.id", "%zd", (size_t) getpid());
|
|
|
|
|
}
|
|
|
|
|
if (!pw_properties_get(properties, "application.process.user"))
|
|
|
|
|
pw_properties_set(properties, "application.process.user", pw_get_user_name());
|
|
|
|
|
|
|
|
|
|
if (!pw_properties_get(properties, "application.process.host"))
|
|
|
|
|
pw_properties_set(properties, "application.process.host", pw_get_host_name());
|
|
|
|
|
|
|
|
|
|
if (!pw_properties_get(properties, "application.process.session_id")) {
|
|
|
|
|
pw_properties_set(properties, "application.process.session_id",
|
|
|
|
|
getenv("XDG_SESSION_ID"));
|
|
|
|
|
}
|
2018-12-04 11:33:43 +01:00
|
|
|
if (!pw_properties_get(properties, "window.x11.display")) {
|
|
|
|
|
pw_properties_set(properties, "window.x11.display",
|
|
|
|
|
getenv("DISPLAY"));
|
|
|
|
|
}
|
2017-09-18 20:37:00 +02:00
|
|
|
pw_properties_set(properties, PW_CORE_PROP_VERSION, core->info.version);
|
|
|
|
|
pw_properties_set(properties, PW_CORE_PROP_NAME, core->info.name);
|
2017-07-11 20:38:48 +02:00
|
|
|
|
2017-09-18 20:37:00 +02:00
|
|
|
if ((val = pw_properties_get(core->properties, PW_CORE_PROP_DAEMON)))
|
|
|
|
|
pw_properties_set(properties, PW_CORE_PROP_DAEMON, val);
|
2017-05-23 19:15:33 +02:00
|
|
|
}
|
|
|
|
|
|
2017-05-30 19:46:51 +02:00
|
|
|
/** Fill stream properties
|
|
|
|
|
* \param properties a \ref pw_properties
|
|
|
|
|
*
|
|
|
|
|
* Fill \a properties with a set of default stream properties.
|
2017-05-23 19:15:33 +02:00
|
|
|
*
|
2017-05-30 19:46:51 +02:00
|
|
|
* \memberof pw_pipewire
|
2017-05-23 19:15:33 +02:00
|
|
|
*/
|
2019-02-06 13:24:41 +01:00
|
|
|
SPA_EXPORT
|
2017-07-11 20:38:48 +02:00
|
|
|
void pw_fill_stream_properties(struct pw_core *core, struct pw_properties *properties)
|
2017-05-23 19:15:33 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-30 19:46:51 +02:00
|
|
|
/** Reverse the direction \memberof pw_pipewire */
|
2019-02-06 13:24:41 +01:00
|
|
|
SPA_EXPORT
|
2017-05-26 08:05:01 +02:00
|
|
|
enum pw_direction pw_direction_reverse(enum pw_direction direction)
|
2017-05-23 19:15:33 +02:00
|
|
|
{
|
2017-05-26 08:05:01 +02:00
|
|
|
if (direction == PW_DIRECTION_INPUT)
|
|
|
|
|
return PW_DIRECTION_OUTPUT;
|
|
|
|
|
else if (direction == PW_DIRECTION_OUTPUT)
|
|
|
|
|
return PW_DIRECTION_INPUT;
|
|
|
|
|
return direction;
|
2017-05-23 19:15:33 +02:00
|
|
|
}
|
2018-07-17 10:31:17 +02:00
|
|
|
|
|
|
|
|
/** Get the currently running version */
|
2019-02-06 13:24:41 +01:00
|
|
|
SPA_EXPORT
|
2018-07-17 10:31:17 +02:00
|
|
|
const char* pw_get_library_version(void)
|
|
|
|
|
{
|
|
|
|
|
return pw_get_headers_version();
|
|
|
|
|
}
|
2018-10-31 16:05:58 +00:00
|
|
|
|
|
|
|
|
static const struct spa_type_info type_info[] = {
|
2019-01-14 12:58:23 +01:00
|
|
|
{ PW_TYPE_INTERFACE_Core, PW_TYPE_INFO_INTERFACE_BASE "Core", SPA_TYPE_Pointer, NULL },
|
|
|
|
|
{ PW_TYPE_INTERFACE_Registry, PW_TYPE_INFO_INTERFACE_BASE "Registry", SPA_TYPE_Pointer, NULL },
|
|
|
|
|
{ PW_TYPE_INTERFACE_Node, PW_TYPE_INFO_INTERFACE_BASE "Node", SPA_TYPE_Pointer, NULL },
|
|
|
|
|
{ PW_TYPE_INTERFACE_Port, PW_TYPE_INFO_INTERFACE_BASE "Port", SPA_TYPE_Pointer, NULL },
|
|
|
|
|
{ PW_TYPE_INTERFACE_Factory, PW_TYPE_INFO_INTERFACE_BASE "Factory", SPA_TYPE_Pointer, NULL },
|
|
|
|
|
{ PW_TYPE_INTERFACE_Link, PW_TYPE_INFO_INTERFACE_BASE "Link", SPA_TYPE_Pointer, NULL },
|
|
|
|
|
{ PW_TYPE_INTERFACE_Client, PW_TYPE_INFO_INTERFACE_BASE "Client", SPA_TYPE_Pointer, NULL },
|
|
|
|
|
{ PW_TYPE_INTERFACE_Module, PW_TYPE_INFO_INTERFACE_BASE "Module", SPA_TYPE_Pointer, NULL },
|
|
|
|
|
{ PW_TYPE_INTERFACE_ClientNode, PW_TYPE_INFO_INTERFACE_BASE "ClientNode", SPA_TYPE_Pointer, NULL },
|
|
|
|
|
{ PW_TYPE_INTERFACE_Device, PW_TYPE_INFO_INTERFACE_BASE "Device", SPA_TYPE_Pointer, NULL },
|
2018-10-31 16:05:58 +00:00
|
|
|
{ SPA_ID_INVALID, "spa_types", SPA_ID_INVALID, spa_types },
|
2019-01-07 13:56:08 +01:00
|
|
|
{ 0, NULL, 0, NULL },
|
2018-10-31 16:05:58 +00:00
|
|
|
};
|
|
|
|
|
|
2019-02-06 13:24:41 +01:00
|
|
|
SPA_EXPORT
|
2018-10-31 16:05:58 +00:00
|
|
|
const struct spa_type_info * pw_type_info(void)
|
|
|
|
|
{
|
|
|
|
|
return type_info;
|
|
|
|
|
}
|