diff --git a/spa/plugins/alsa/alsa-sink.c b/spa/plugins/alsa/alsa-sink.c index 596592468..747b1fe6b 100644 --- a/spa/plugins/alsa/alsa-sink.c +++ b/spa/plugins/alsa/alsa-sink.c @@ -33,7 +33,7 @@ #define CHECK_PORT(this,d,p) ((d) == SPA_DIRECTION_INPUT && (p) == 0) static const char default_device[] = "hw:0"; -static const uint32_t default_min_latency = 64; +static const uint32_t default_min_latency = 16; static const uint32_t default_max_latency = 1024; static void reset_props(struct props *props) diff --git a/spa/plugins/v4l2/v4l2-utils.c b/spa/plugins/v4l2/v4l2-utils.c index 5cdad71f6..b8dcaa644 100644 --- a/spa/plugins/v4l2/v4l2-utils.c +++ b/spa/plugins/v4l2/v4l2-utils.c @@ -87,6 +87,8 @@ static int spa_v4l2_open(struct impl *this) ((port->cap.capabilities & V4L2_CAP_DEVICE_CAPS) && (port->cap.device_caps & V4L2_CAP_VIDEO_CAPTURE) == 0)) { spa_log_error(port->log, "v4l2: %s is no video capture device", props->device); + close(port->fd); + port->fd = -1; return -ENODEV; } diff --git a/src/daemon/pipewire.conf.in b/src/daemon/pipewire.conf.in index 869409872..f02ecc8db 100644 --- a/src/daemon/pipewire.conf.in +++ b/src/daemon/pipewire.conf.in @@ -10,5 +10,5 @@ load-module libpipewire-module-spa-monitor v4l2/libspa-v4l2 v4l2-monitor v4l2 #load-module libpipewire-module-mixer load-module libpipewire-module-client-node load-module libpipewire-module-flatpak -load-module libpipewire-module-audio-session +load-module libpipewire-module-media-session load-module libpipewire-module-link-factory diff --git a/src/examples/export-source.c b/src/examples/export-source.c index 9fdcf6005..88e473ed5 100644 --- a/src/examples/export-source.c +++ b/src/examples/export-source.c @@ -206,7 +206,7 @@ static int port_enum_formats(struct spa_node *node, ":", d->type.format_audio.format, "Ieu", d->type.audio_format.S16, SPA_POD_PROP_ENUM(2, d->type.audio_format.S16, d->type.audio_format.F32), - ":", d->type.format_audio.layout, "i", SPA_AUDIO_LAYOUT_NON_INTERLEAVED, + ":", d->type.format_audio.layout, "i", SPA_AUDIO_LAYOUT_INTERLEAVED, ":", d->type.format_audio.channels, "iru", 2, SPA_POD_PROP_MIN_MAX(1, INT32_MAX), ":", d->type.format_audio.rate, "iru", 44100, @@ -538,7 +538,9 @@ static void make_node(struct data *data) { struct pw_properties *props; - props = pw_properties_new(PW_NODE_PROP_AUTOCONNECT, "1", NULL); + props = pw_properties_new(PW_NODE_PROP_AUTOCONNECT, "1", + PW_NODE_PROP_EXCLUSIVE, "1", + NULL); if (data->path) pw_properties_set(props, PW_NODE_PROP_TARGET_NODE, data->path); diff --git a/src/examples/video-play.c b/src/examples/video-play.c index 958ab5b8a..2b4e85552 100644 --- a/src/examples/video-play.c +++ b/src/examples/video-play.c @@ -375,6 +375,7 @@ int main(int argc, char *argv[]) data.path, PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_INACTIVE | + PW_STREAM_FLAG_EXCLUSIVE | PW_STREAM_FLAG_MAP_BUFFERS, params, 1); diff --git a/src/modules/meson.build b/src/modules/meson.build index 0f8b8d59e..cc36aa460 100644 --- a/src/modules/meson.build +++ b/src/modules/meson.build @@ -91,9 +91,9 @@ pipewire_module_protocol_native = shared_library('pipewire-module-protocol-nativ dependencies : [mathlib, dl_lib, pipewire_dep], ) -pipewire_module_audio_session = shared_library('pipewire-module-audio-session', - [ 'module-audio-session.c', - 'module-audio-session/audio-dsp.c', +pipewire_module_audio_session = shared_library('pipewire-module-media-session', + [ 'module-media-session.c', + 'module-media-session/audio-dsp.c', 'spa/spa-node.c' ], c_args : pipewire_module_c_args, include_directories : [configinc, spa_inc], diff --git a/src/modules/module-audio-session.c b/src/modules/module-media-session.c similarity index 89% rename from src/modules/module-audio-session.c rename to src/modules/module-media-session.c index 1d92cbb76..ea10e5599 100644 --- a/src/modules/module-audio-session.c +++ b/src/modules/module-media-session.c @@ -40,7 +40,7 @@ #include "pipewire/type.h" #include "pipewire/private.h" -#include "module-audio-session/audio-dsp.h" +#include "module-media-session/audio-dsp.h" #define DEFAULT_CHANNELS 2 #define DEFAULT_SAMPLE_RATE 44100 @@ -96,6 +96,7 @@ struct session { struct pw_link *link; + bool exclusive; int sample_rate; int buffer_size; @@ -152,7 +153,9 @@ static void session_destroy(struct session *sess) spa_hook_remove(&sess->node_listener); spa_list_for_each_safe(ni, t, &sess->node_list, l) node_info_free(ni); - pw_node_destroy(sess->dsp); + if (sess->dsp) + pw_node_destroy(sess->dsp); + free(sess); } static void @@ -296,6 +299,8 @@ static void reconfigure_session(struct session *sess) if (ni->buffer_size > 0) buffer_size = SPA_MIN(buffer_size, ni->buffer_size); } + if (spa_list_is_empty(&sess->node_list)) + sess->exclusive = false; sess->buffer_size = buffer_size; @@ -387,6 +392,11 @@ static int find_session(void *data, struct session *sess) if ((str = pw_properties_get(props, "node.plugged")) != NULL) plugged = pw_properties_parse_uint64(str); + + if (sess->exclusive) { + pw_log_debug("module %p: session in use", impl); + return 0; + } } pw_log_debug("module %p: found session '%d' %" PRIu64, impl, @@ -416,8 +426,6 @@ static void handle_autoconnect(struct impl *impl, struct pw_node *node, if ((media = pw_properties_get(props, PW_NODE_PROP_MEDIA)) == NULL) media = "Audio"; - if (strcmp(media, "Audio")) - return; if ((category = pw_properties_get(props, PW_NODE_PROP_CATEGORY)) == NULL) category = "Playback"; @@ -439,10 +447,20 @@ static void handle_autoconnect(struct impl *impl, struct pw_node *node, media, category, role, exclusive, sample_rate, buffer_size); - if (strcmp(category, "Playback") == 0) - find.media_class = "Audio/Sink"; - else if (strcmp(category, "Capture") == 0) - find.media_class = "Audio/Source"; + if (strcmp(media, "Audio") == 0) { + if (strcmp(category, "Playback") == 0) + find.media_class = "Audio/Sink"; + else if (strcmp(category, "Capture") == 0) + find.media_class = "Audio/Source"; + else + return; + } + else if (strcmp(media, "Video") == 0) { + if (strcmp(category, "Capture") == 0) + find.media_class = "Video/Source"; + else + return; + } else return; @@ -470,8 +488,8 @@ static void handle_autoconnect(struct impl *impl, struct pw_node *node, else return; - if (exclusive) { - if (!spa_list_is_empty(&session->node_list)) { + if (exclusive || session->dsp == NULL) { + if (exclusive && !spa_list_is_empty(&session->node_list)) { pw_log_warn("session busy, can't get exclusive access"); return; } @@ -480,6 +498,7 @@ static void handle_autoconnect(struct impl *impl, struct pw_node *node, return; } peer = session->node; + session->exclusive = exclusive; } else { if (session->link == NULL) { @@ -555,7 +574,8 @@ struct channel_data { uint32_t rate; }; -static int collect_channel(void *data, uint32_t id, uint32_t index, uint32_t next, struct spa_pod *param) +static int collect_audio_format(void *data, uint32_t id, + uint32_t index, uint32_t next, struct spa_pod *param) { struct channel_data *d = data; struct impl *impl = d->impl; @@ -584,7 +604,7 @@ static int collect_channel(void *data, uint32_t id, uint32_t index, uint32_t nex } -static int find_port_channels(struct impl *impl, struct pw_port *port, +static int find_port_format(struct impl *impl, struct pw_port *port, uint32_t *channels, uint32_t *rate) { struct pw_type *t = impl->t; @@ -593,9 +613,10 @@ static int find_port_channels(struct impl *impl, struct pw_port *port, pw_port_for_each_param(port, t->param.idEnumFormat, 0, 0, NULL, - collect_channel, &data); + collect_audio_format, &data); + + pw_log_debug("port channels %d rate %d", data.channels, data.rate); - pw_log_debug("port channels %d", data.channels); *channels = data.channels; *rate = data.rate; @@ -612,6 +633,7 @@ static int on_global(void *data, struct pw_global *global) enum pw_direction direction; struct pw_port *node_port, *dsp_port; uint32_t id, channels, rate; + bool need_dsp; if (pw_global_get_type(global) != impl->t->node) return 0; @@ -619,6 +641,8 @@ static int on_global(void *data, struct pw_global *global) node = pw_global_get_object(global); id = pw_global_get_id(global); + pw_log_debug("global added %d", id); + properties = pw_node_get_properties(node); str = pw_properties_get(properties, PW_NODE_PROP_AUTOCONNECT); @@ -629,11 +653,20 @@ static int on_global(void *data, struct pw_global *global) else if ((str = pw_properties_get(properties, "media.class")) == NULL) return 0; - pw_log_debug("global added %s (%d)", str, id); + if (strstr(str, "Audio/") == str) { + need_dsp = true; + str += strlen("Audio/"); + } + else if (strstr(str, "Video/") == str) { + need_dsp = false; + str += strlen("Video/"); + } + else + return 0; - if (strcmp(str, "Audio/Sink") == 0) + if (strcmp(str, "Sink") == 0) direction = PW_DIRECTION_OUTPUT; - else if (strcmp(str, "Audio/Source") == 0) + else if (strcmp(str, "Source") == 0) direction = PW_DIRECTION_INPUT; else return 0; @@ -641,41 +674,45 @@ static int on_global(void *data, struct pw_global *global) if ((node_port = pw_node_get_free_port(node, pw_direction_reverse(direction))) == NULL) return 0; - if (find_port_channels(impl, node_port, &channels, &rate) < 0) - return 0; - - dsp = pw_audio_dsp_new(impl->core, - properties, - direction, - channels, - rate, - MAX_BUFFER_SIZE, - sizeof(struct session)); - if (dsp == NULL) - return 0; - - if ((dsp_port = pw_node_get_free_port(dsp, direction)) == NULL) - return 0; - - sess = pw_audio_dsp_get_user_data(dsp); + sess = calloc(1, sizeof(struct session)); sess->impl = impl; sess->direction = direction; sess->id = id; sess->node = node; sess->node_port = node_port; - sess->dsp = dsp; - sess->dsp_port = dsp_port; - sess->sample_rate = rate; - sess->buffer_size = MAX_BUFFER_SIZE; spa_list_init(&sess->node_list); - spa_list_append(&impl->session_list, &sess->l); - pw_node_add_listener(dsp, &sess->dsp_listener, &dsp_events, sess); pw_node_add_listener(node, &sess->node_listener, &node_events, sess); - pw_node_register(dsp, NULL, pw_module_get_global(impl->module), NULL); - pw_node_set_active(dsp, true); + if (need_dsp) { + if (find_port_format(impl, node_port, &channels, &rate) < 0) + return 0; + + dsp = pw_audio_dsp_new(impl->core, + properties, + direction, + channels, + rate, + MAX_BUFFER_SIZE, + 0); + if (dsp == NULL) + return 0; + + if ((dsp_port = pw_node_get_free_port(dsp, direction)) == NULL) + return 0; + + pw_node_add_listener(dsp, &sess->dsp_listener, &dsp_events, sess); + + sess->dsp = dsp; + sess->dsp_port = dsp_port; + sess->sample_rate = rate; + sess->buffer_size = MAX_BUFFER_SIZE; + + pw_node_register(dsp, NULL, pw_module_get_global(impl->module), NULL); + pw_node_set_active(dsp, true); + + } return 0; } diff --git a/src/modules/module-audio-session/audio-dsp.c b/src/modules/module-media-session/audio-dsp.c similarity index 100% rename from src/modules/module-audio-session/audio-dsp.c rename to src/modules/module-media-session/audio-dsp.c diff --git a/src/modules/module-audio-session/audio-dsp.h b/src/modules/module-media-session/audio-dsp.h similarity index 100% rename from src/modules/module-audio-session/audio-dsp.h rename to src/modules/module-media-session/audio-dsp.h