Projects
Essentials
pipewire-aptx
Sign Up
Log In
Username
Password
We truncated the diff of some files because they were too big. If you want to see the full diff for every file,
click here
.
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 26
View file
pipewire-aptx.changes
Changed
@@ -1,4 +1,9 @@ ------------------------------------------------------------------- +Fri Apr 14 13:35:34 UTC 2023 - Bjørn Lie <zaitor@opensuse.org> + +- Update to version 0.3.69 + +------------------------------------------------------------------- Sat Apr 8 17:49:24 UTC 2023 - Bjørn Lie <zaitor@opensuse.org> - Update to version 0.3.68
View file
pipewire-aptx.spec
Changed
@@ -7,7 +7,7 @@ %define soversion 0_2 Name: pipewire-aptx -Version: 0.3.68 +Version: 0.3.69 Release: 0 Summary: PipeWire Bluetooth aptX codec plugin License: MIT @@ -16,7 +16,7 @@ BuildRequires: c++_compiler BuildRequires: c_compiler -BuildRequires: meson >= 0.59.0 +BuildRequires: meson >= 0.61.1 BuildRequires: pkgconfig BuildRequires: pkgconfig(bluez) BuildRequires: pkgconfig(dbus-1)
View file
pipewire-0.3.68.tar.gz/NEWS -> pipewire-0.3.69.tar.gz/NEWS
Changed
@@ -1,3 +1,59 @@ +# PipeWire 0.3.69 (2023-04-13) + +This is a quick bugfix release that is API and ABI compatible with previous +0.3.x releases. + +## Highlights + - Reverted the UCM changes, they seem to cause regressions causing audio + to be muted in some cases. + - Fix a regression in the scheduler where a driver node might not be marked + runnable in some cases, like when echo-cancel is used. (#3145) + - Handle links from the driver to itself. This makes the midi bridge work + again. (#3153) + - ALSA rate matching for sources was fixed. It would previously wait too + long for rate matching and then cause drift. This should reduce + crackling and stuttering whan capturing in low latency. + - Fix the GStreamer clock to make cheese video recording work again. (#3149) + - More fixes and improvements. + +## PipeWire + - Fix a regression in the scheduler where a driver node might not be marked + runnable in some cases, like when echo-cancel is used. (#3145) + - Handle links from the driver to itself. This makes the midi bridge work + again. (#3153) + - Some man pages were improved. + - Fix a potential crash when thread-loop is destroyed before the loop. + (#3150) + +## Modules + - A new raw biquad filter was added to filter-chain. You can manually set the + 6 parameters and you can use this to create custom filters per sample rate. + (#3139) + - The echo-canceler now supports different channels for the capture and playback + streams. + +## SPA + - A SB Audigy specific profile set was added to make better use of the + controls. (#2934) + - More ALSA IRQ based scheduling improvements. + - ALSA rate matching for sources was fixed. It would previously wait too + long for rate matching and then cause drift. This should reduce + crackling and stuttering whan capturing in low latency. + - The echo-cancel plugin API has a new method to make it possible to have + different channels for capture, source and playback. + - Reverted the UCM changes, they seem to cause regressions causing audio + to be muted in some cases. + +## Bluetooth + - Many more BAP fixes and improvements. Devices are now created as a set + and can be combined into one device by the session manager. + +## GStreamer + - Fix the GStreamer clock to make cheese video recording work again. (#3149) + + +Older versions: + # PipeWire 0.3.68 (2023-04-06) This is a bugfix release that is API and ABI compatible with previous @@ -135,9 +191,6 @@ ## GStreamer - Sort the device by priority in deviceprovider. (#3072) - -Older versions: - # PipeWire 0.3.67 (2023-03-09) This is a bugfix release that is API and ABI compatible with previous
View file
pipewire-0.3.68.tar.gz/man/pipewire.conf.5.rst.in -> pipewire-0.3.69.tar.gz/man/pipewire.conf.5.rst.in
Changed
@@ -69,8 +69,7 @@ of use, a relaxed format may be used where: * ``:`` to delimit keys and values can be substuted by ``=`` or a space. - * ``"`` around keys and string can be omited as long as no special characters - are used in the strings. + * ``"`` around keys and string can be omited as long as no special characters are used in the strings. * ``,`` to separate objects can be replaced with a whitespace character. * ``#`` can be used to start a comment until the line end
View file
pipewire-0.3.68.tar.gz/man/pw-cli.1.rst.in -> pipewire-0.3.69.tar.gz/man/pw-cli.1.rst.in
Changed
@@ -174,10 +174,6 @@ send-command *object-id* Send a command to an object. - -EXAMPLES -======== - AUTHORS =======
View file
pipewire-0.3.68.tar.gz/man/pw-metadata.1.rst.in -> pipewire-0.3.69.tar.gz/man/pw-metadata.1.rst.in
Changed
@@ -48,11 +48,23 @@ Keeps running and log the changes to the metadata. -d | --delete + Delete all metadata for *id* or for the specified *key* of object *id*. + Without any option, all metadata is removed. - Delete all metadata for *id* or for the - specified *key* of object *id* +-n | --name + Metadata name (Default: "default"). - Without any option, all metadata is removed +EXAMPLES +======== + +**pw-metadata** + Show metadata in default name. + +**pw-metadata** -n settings 0 + Display settings. + +**pw-metadata** -n settings 0 clock.quantum 1024 + Change clock.quantum to 1024. AUTHORS =======
View file
pipewire-0.3.68.tar.gz/meson.build -> pipewire-0.3.69.tar.gz/meson.build
Changed
@@ -1,5 +1,5 @@ project('pipewire', 'c' , - version : '0.3.68', + version : '0.3.69', license : 'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' , meson_version : '>= 0.61.1', default_options : 'warning_level=3',
View file
pipewire-0.3.68.tar.gz/pipewire-jack/src/pipewire-jack.c -> pipewire-0.3.69.tar.gz/pipewire-jack/src/pipewire-jack.c
Changed
@@ -1361,10 +1361,16 @@ return c->sample_rate == sample_rate; } +static inline uint64_t get_time_ns(void) +{ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return SPA_TIMESPEC_TO_NSEC(&ts); +} + static inline uint32_t cycle_run(struct client *c) { uint64_t cmd; - struct timespec ts; int fd = c->socket_source->fd; struct spa_io_position *pos = c->rt.position; struct pw_node_activation *activation = c->activation; @@ -1383,9 +1389,8 @@ if (SPA_UNLIKELY(cmd > 1)) pw_log_info("%p: missed %"PRIu64" wakeups", c, cmd - 1); - clock_gettime(CLOCK_MONOTONIC, &ts); activation->status = PW_NODE_ACTIVATION_AWAKE; - activation->awake_time = SPA_TIMESPEC_TO_NSEC(&ts); + activation->awake_time = get_time_ns(); if (SPA_UNLIKELY(c->first)) { if (c->thread_init_callback) @@ -1442,15 +1447,13 @@ static inline void signal_sync(struct client *c) { - struct timespec ts; uint64_t cmd, nsec; struct link *l; struct pw_node_activation *activation = c->activation; complete_process(c, c->buffer_frames); - clock_gettime(CLOCK_MONOTONIC, &ts); - nsec = SPA_TIMESPEC_TO_NSEC(&ts); + nsec = get_time_ns(); activation->status = PW_NODE_ACTIVATION_FINISHED; activation->finish_time = nsec; @@ -5700,7 +5703,6 @@ { struct client *c = (struct client *) client; struct spa_io_position *pos; - struct timespec ts; uint64_t diff; spa_return_val_if_fail(c != NULL, 0); @@ -5708,17 +5710,14 @@ if (SPA_UNLIKELY((pos = c->rt.position) == NULL)) return 0; - clock_gettime(CLOCK_MONOTONIC, &ts); - diff = SPA_TIMESPEC_TO_NSEC(&ts) - pos->clock.nsec; + diff = get_time_ns() - pos->clock.nsec; return (jack_nframes_t) floor(((double)c->sample_rate * diff) / SPA_NSEC_PER_SEC); } SPA_EXPORT jack_nframes_t jack_frame_time (const jack_client_t *client) { - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return jack_time_to_frames(client, SPA_TIMESPEC_TO_USEC(&ts)); + return jack_time_to_frames(client, jack_get_time()); } SPA_EXPORT @@ -5801,9 +5800,7 @@ SPA_EXPORT jack_time_t jack_get_time(void) { - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return SPA_TIMESPEC_TO_USEC(&ts); + return get_time_ns()/SPA_NSEC_PER_USEC; } SPA_EXPORT @@ -6000,9 +5997,7 @@ running = pos->clock.position - pos->offset; if (pos->state == SPA_IO_POSITION_STATE_RUNNING) { - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - uint64_t nsecs = SPA_TIMESPEC_TO_NSEC(&ts) - pos->clock.nsec; + uint64_t nsecs = get_time_ns() - pos->clock.nsec; running += (uint64_t)floor((((double) c->sample_rate) / SPA_NSEC_PER_SEC) * nsecs); } seg = &pos->segments0;
View file
pipewire-0.3.68.tar.gz/spa/include/spa/interfaces/audio/aec.h -> pipewire-0.3.69.tar.gz/spa/include/spa/interfaces/audio/aec.h
Changed
@@ -40,7 +40,7 @@ }; struct spa_audio_aec_methods { -#define SPA_VERSION_AUDIO_AEC_METHODS 2 +#define SPA_VERSION_AUDIO_AEC_METHODS 3 uint32_t version; int (*add_listener) (void *object, @@ -60,6 +60,12 @@ int (*enum_props) (void* object, int index, struct spa_pod_builder* builder); int (*get_params) (void* object, struct spa_pod_builder* builder); int (*set_params) (void *object, const struct spa_pod *args); + + /* version 1:3 */ + int (*init2) (void *object, const struct spa_dict *args, + struct spa_audio_info_raw *play_info, + struct spa_audio_info_raw *rec_info, + struct spa_audio_info_raw *out_info); }; #define spa_audio_aec_method(o,method,version,...) \ @@ -81,6 +87,7 @@ #define spa_audio_aec_enum_props(o,...) spa_audio_aec_method(o, enum_props, 2, __VA_ARGS__) #define spa_audio_aec_get_params(o,...) spa_audio_aec_method(o, get_params, 2, __VA_ARGS__) #define spa_audio_aec_set_params(o,...) spa_audio_aec_method(o, set_params, 2, __VA_ARGS__) +#define spa_audio_aec_init2(o,...) spa_audio_aec_method(o, init2, 3, __VA_ARGS__) #ifdef __cplusplus } /* extern "C" */
View file
pipewire-0.3.68.tar.gz/spa/plugins/aec/aec-webrtc.cpp -> pipewire-0.3.69.tar.gz/spa/plugins/aec/aec-webrtc.cpp
Changed
@@ -22,7 +22,9 @@ struct spa_log *log; std::unique_ptr<webrtc::AudioProcessing> apm; - spa_audio_info_raw info; + spa_audio_info_raw rec_info; + spa_audio_info_raw out_info; + spa_audio_info_raw play_info; std::unique_ptr<float *> play_buffer, rec_buffer, out_buffer; }; @@ -38,9 +40,12 @@ return default_value; } -static int webrtc_init(void *object, const struct spa_dict *args, const struct spa_audio_info_raw *info) +static int webrtc_init2(void *object, const struct spa_dict *args, + struct spa_audio_info_raw *rec_info, struct spa_audio_info_raw *out_info, + struct spa_audio_info_raw *play_info) { auto impl = static_cast<struct impl_data*>(object); + int res; bool extended_filter = webrtc_get_spa_bool(args, "webrtc.extended_filter", true); bool delay_agnostic = webrtc_get_spa_bool(args, "webrtc.delay_agnostic", true); @@ -67,16 +72,16 @@ config.Set<webrtc::ExperimentalNs>(new webrtc::ExperimentalNs(experimental_ns)); webrtc::ProcessingConfig pconfig = {{ - webrtc::StreamConfig(info->rate, info->channels, false), /* input stream */ - webrtc::StreamConfig(info->rate, info->channels, false), /* output stream */ - webrtc::StreamConfig(info->rate, info->channels, false), /* reverse input stream */ - webrtc::StreamConfig(info->rate, info->channels, false), /* reverse output stream */ + webrtc::StreamConfig(rec_info->rate, rec_info->channels, false), /* input stream */ + webrtc::StreamConfig(out_info->rate, out_info->channels, false), /* output stream */ + webrtc::StreamConfig(play_info->rate, play_info->channels, false), /* reverse input stream */ + webrtc::StreamConfig(play_info->rate, play_info->channels, false), /* reverse output stream */ }}; auto apm = std::unique_ptr<webrtc::AudioProcessing>(webrtc::AudioProcessing::Create(config)); - if (apm->Initialize(pconfig) != webrtc::AudioProcessing::kNoError) { - spa_log_error(impl->log, "Error initialising webrtc audio processing module"); - return -1; + if ((res = apm->Initialize(pconfig)) != webrtc::AudioProcessing::kNoError) { + spa_log_error(impl->log, "Error initialising webrtc audio processing module: %d", res); + return -EINVAL; } apm->high_pass_filter()->Enable(high_pass_filter); @@ -94,48 +99,72 @@ apm->gain_control()->set_mode(webrtc::GainControl::kAdaptiveDigital); apm->gain_control()->Enable(gain_control); impl->apm = std::move(apm); - impl->info = *info; - impl->play_buffer = std::make_unique<float *>(info->channels); - impl->rec_buffer = std::make_unique<float *>(info->channels); - impl->out_buffer = std::make_unique<float *>(info->channels); + impl->rec_info = *rec_info; + impl->out_info = *out_info; + impl->play_info = *play_info; + impl->play_buffer = std::make_unique<float *>(play_info->channels); + impl->rec_buffer = std::make_unique<float *>(rec_info->channels); + impl->out_buffer = std::make_unique<float *>(out_info->channels); return 0; } +static int webrtc_init(void *object, const struct spa_dict *args, + const struct spa_audio_info_raw *info) +{ + int res; + struct spa_audio_info_raw rec_info = *info; + struct spa_audio_info_raw out_info = *info; + struct spa_audio_info_raw play_info = *info; + res = webrtc_init2(object, args, &rec_info, &out_info, &play_info); + if (rec_info.channels != out_info.channels) + res = -EINVAL; + return res; +} + static int webrtc_run(void *object, const float *rec, const float *play, float *out, uint32_t n_samples) { auto impl = static_cast<struct impl_data*>(object); - webrtc::StreamConfig config = - webrtc::StreamConfig(impl->info.rate, impl->info.channels, false); - unsigned int num_blocks = n_samples * 1000 / impl->info.rate / 10; + int res; + + webrtc::StreamConfig play_config = + webrtc::StreamConfig(impl->play_info.rate, impl->play_info.channels, false); + webrtc::StreamConfig rec_config = + webrtc::StreamConfig(impl->rec_info.rate, impl->rec_info.channels, false); + webrtc::StreamConfig out_config = + webrtc::StreamConfig(impl->out_info.rate, impl->out_info.channels, false); + unsigned int num_blocks = n_samples * 1000 / impl->play_info.rate / 10; - if (n_samples * 1000 / impl->info.rate % 10 != 0) { + if (n_samples * 1000 / impl->play_info.rate % 10 != 0) { spa_log_error(impl->log, "Buffers must be multiples of 10ms in length (currently %u samples)", n_samples); - return -1; + return -EINVAL; } for (size_t i = 0; i < num_blocks; i ++) { - for (size_t j = 0; j < impl->info.channels; j++) { - impl->play_bufferj = const_cast<float *>(playj) + config.num_frames() * i; - impl->rec_bufferj = const_cast<float *>(recj) + config.num_frames() * i; - impl->out_bufferj = outj + config.num_frames() * i; - } + for (size_t j = 0; j < impl->play_info.channels; j++) + impl->play_bufferj = const_cast<float *>(playj) + play_config.num_frames() * i; + for (size_t j = 0; j < impl->rec_info.channels; j++) + impl->rec_bufferj = const_cast<float *>(recj) + rec_config.num_frames() * i; + for (size_t j = 0; j < impl->out_info.channels; j++) + impl->out_bufferj = outj + out_config.num_frames() * i; + /* FIXME: ProcessReverseStream may change the playback buffer, in which * case we should use that, if we ever expose the intelligibility * enhancer */ - if (impl->apm->ProcessReverseStream(impl->play_buffer.get(), config, config, impl->play_buffer.get()) != + if ((res = impl->apm->ProcessReverseStream(impl->play_buffer.get(), + play_config, play_config, impl->play_buffer.get())) != webrtc::AudioProcessing::kNoError) { - spa_log_error(impl->log, "Processing reverse stream failed"); + spa_log_error(impl->log, "Processing reverse stream failed: %d", res); } // Extra delay introduced by multiple frames impl->apm->set_stream_delay_ms((num_blocks - 1) * 10); - if (impl->apm->ProcessStream(impl->rec_buffer.get(), config, config, impl->out_buffer.get()) != + if ((res = impl->apm->ProcessStream(impl->rec_buffer.get(), + rec_config, out_config, impl->out_buffer.get())) != webrtc::AudioProcessing::kNoError) { - spa_log_error(impl->log, "Processing stream failed"); + spa_log_error(impl->log, "Processing stream failed: %d", res); } } - return 0; } @@ -144,6 +173,7 @@ .add_listener = NULL, .init = webrtc_init, .run = webrtc_run, + .init2 = webrtc_init2, }; static int impl_get_interface(struct spa_handle *handle, const char *type, void **interface)
View file
pipewire-0.3.68.tar.gz/spa/plugins/alsa/acp/acp.c -> pipewire-0.3.69.tar.gz/spa/plugins/alsa/acp/acp.c
Changed
@@ -362,7 +362,7 @@ devstr, NULL, &m->sample_spec, &m->channel_map, SND_PCM_STREAM_PLAYBACK, &try_period_size, &try_buffer_size, - 0, NULL, NULL, NULL, NULL, false))) { + 0, NULL, NULL, false))) { pa_alsa_init_proplist_pcm(NULL, m->output_proplist, m->output_pcm); pa_proplist_setf(m->output_proplist, "clock.name", "api.alsa.%u", index); pa_alsa_close(&m->output_pcm); @@ -392,7 +392,7 @@ devstr, NULL, &m->sample_spec, &m->channel_map, SND_PCM_STREAM_CAPTURE, &try_period_size, &try_buffer_size, - 0, NULL, NULL, NULL, NULL, false))) { + 0, NULL, NULL, false))) { pa_alsa_init_proplist_pcm(NULL, m->input_proplist, m->input_pcm); pa_proplist_setf(m->input_proplist, "clock.name", "api.alsa.%u", index); pa_alsa_close(&m->input_pcm); @@ -449,8 +449,8 @@ pa_dynarray_append(&impl->out.devices, dev); } if (impl->use_ucm) { - if (m->ucm_context.ucm_device) { - pa_alsa_ucm_add_port(NULL, &m->ucm_context, + if (m->ucm_context.ucm_devices) { + pa_alsa_ucm_add_ports_combination(NULL, &m->ucm_context, true, impl->ports, ap, NULL); pa_alsa_ucm_add_ports(&dev->ports, m->proplist, &m->ucm_context, true, impl, dev->pcm_handle, impl->profile_set->ignore_dB); @@ -473,8 +473,8 @@ } if (impl->use_ucm) { - if (m->ucm_context.ucm_device) { - pa_alsa_ucm_add_port(NULL, &m->ucm_context, + if (m->ucm_context.ucm_devices) { + pa_alsa_ucm_add_ports_combination(NULL, &m->ucm_context, false, impl->ports, ap, NULL); pa_alsa_ucm_add_ports(&dev->ports, m->proplist, &m->ucm_context, false, impl, dev->pcm_handle, impl->profile_set->ignore_dB); @@ -608,7 +608,7 @@ static int report_jack_state(snd_mixer_elem_t *melem, unsigned int mask) { pa_card *impl = snd_mixer_elem_get_callback_private(melem); - snd_hctl_elem_t **_elem = snd_mixer_elem_get_private(melem), *elem; + snd_hctl_elem_t *elem = snd_mixer_elem_get_private(melem); snd_ctl_elem_value_t *elem_value; bool plugged_in, any_input_port_available; void *state; @@ -618,8 +618,6 @@ enum acp_available active_available = ACP_AVAILABLE_UNKNOWN; size_t size; - pa_assert(_elem); - elem = *_elem; #if 0 /* Changing the jack state may cause a port change, and a port change will * make the sink or source change the mixer settings. If there are multiple @@ -888,17 +886,13 @@ static int hdmi_eld_changed(snd_mixer_elem_t *melem, unsigned int mask) { pa_card *impl = snd_mixer_elem_get_callback_private(melem); - snd_hctl_elem_t **_elem = snd_mixer_elem_get_private(melem), *elem; - int device; + snd_hctl_elem_t *elem = snd_mixer_elem_get_private(melem); + int device = snd_hctl_elem_get_device(elem); const char *old_monitor_name; pa_device_port *p; pa_hdmi_eld eld; bool changed = false; - pa_assert(_elem); - elem = *_elem; - device = snd_hctl_elem_get_device(elem); - if (mask == SND_CTL_EVENT_MASK_REMOVE) return 0; @@ -1259,7 +1253,8 @@ * will be NULL, but the UCM device enable sequence will still need to be * executed. */ if (dev->active_port && dev->ucm_context) { - if ((res = pa_alsa_ucm_set_port(dev->ucm_context, dev->active_port)) < 0) + if ((res = pa_alsa_ucm_set_port(dev->ucm_context, dev->active_port, + dev->direction == PA_ALSA_DIRECTION_OUTPUT)) < 0) return res; } @@ -1434,7 +1429,8 @@ /* if UCM is available for this card then update the verb */ if (impl->use_ucm && !(np->profile.flags & ACP_PROFILE_PRO)) { if ((res = pa_alsa_ucm_set_profile(&impl->ucm, impl, - np->profile.flags & ACP_PROFILE_OFF ? NULL : np, op)) < 0) { + np->profile.flags & ACP_PROFILE_OFF ? NULL : np->profile.name, + op ? op->profile.name : NULL)) < 0) { return res; } } @@ -1443,8 +1439,8 @@ PA_IDXSET_FOREACH(am, np->output_mappings, idx) { if (impl->use_ucm) { /* Update ports priorities */ - if (am->ucm_context.ucm_device) { - pa_alsa_ucm_add_port(am->output.ports, &am->ucm_context, + if (am->ucm_context.ucm_devices) { + pa_alsa_ucm_add_ports_combination(am->output.ports, &am->ucm_context, true, impl->ports, np, NULL); } } @@ -1456,8 +1452,8 @@ PA_IDXSET_FOREACH(am, np->input_mappings, idx) { if (impl->use_ucm) { /* Update ports priorities */ - if (am->ucm_context.ucm_device) { - pa_alsa_ucm_add_port(am->input.ports, &am->ucm_context, + if (am->ucm_context.ucm_devices) { + pa_alsa_ucm_add_ports_combination(am->input.ports, &am->ucm_context, false, impl->ports, np, NULL); } } @@ -1848,7 +1844,8 @@ mixer_volume_init(impl, d); sync_mixer(d, p); - res = pa_alsa_ucm_set_port(d->ucm_context, p); + res = pa_alsa_ucm_set_port(d->ucm_context, p, + dev->direction == ACP_DIRECTION_PLAYBACK); } else { pa_alsa_port_data *data;
View file
pipewire-0.3.68.tar.gz/spa/plugins/alsa/acp/alsa-mixer.c -> pipewire-0.3.69.tar.gz/spa/plugins/alsa/acp/alsa-mixer.c
Changed
@@ -5000,7 +5000,7 @@ handle = pa_alsa_open_by_template( m->device_strings, dev_id, NULL, &try_ss, &try_map, mode, &try_period_size, - &try_buffer_size, 0, NULL, NULL, NULL, NULL, exact_channels); + &try_buffer_size, 0, NULL, NULL, exact_channels); if (handle && !exact_channels && m->channel_map.channels != try_map.channels) { char bufPA_CHANNEL_MAP_SNPRINT_MAX; pa_log_debug("Channel map for mapping '%s' permanently changed to '%s'", m->name,
View file
pipewire-0.3.68.tar.gz/spa/plugins/alsa/acp/alsa-mixer.h -> pipewire-0.3.69.tar.gz/spa/plugins/alsa/acp/alsa-mixer.h
Changed
@@ -354,7 +354,7 @@ pa_alsa_device output; pa_alsa_device input; - /* ucm device context */ + /* ucm device context*/ pa_alsa_ucm_mapping_context ucm_context; }; @@ -381,9 +381,6 @@ pa_idxset *input_mappings; pa_idxset *output_mappings; - /* ucm device context */ - pa_alsa_ucm_profile_context ucm_context; - struct { pa_dynarray devices; } out;
View file
pipewire-0.3.68.tar.gz/spa/plugins/alsa/acp/alsa-ucm.c -> pipewire-0.3.69.tar.gz/spa/plugins/alsa/acp/alsa-ucm.c
Changed
@@ -72,8 +72,9 @@ static void ucm_port_data_init(pa_alsa_ucm_port_data *port, pa_alsa_ucm_config *ucm, pa_device_port *core_port, - pa_alsa_ucm_device *device); + pa_alsa_ucm_device **devices, unsigned n_devices); static void ucm_port_data_free(pa_device_port *port); +static void ucm_port_update_available(pa_alsa_ucm_port_data *port); static struct ucm_type types = { {"None", PA_DEVICE_PORT_TYPE_UNKNOWN}, @@ -169,6 +170,17 @@ return (char *)value; } +static int ucm_device_exists(pa_idxset *idxset, pa_alsa_ucm_device *dev) { + pa_alsa_ucm_device *d; + uint32_t idx; + + PA_IDXSET_FOREACH(d, idxset, idx) + if (d == dev) + return 1; + + return 0; +} + static void ucm_add_devices_to_idxset( pa_idxset *idxset, pa_alsa_ucm_device *me, @@ -494,10 +506,10 @@ n_confdev = snd_use_case_get_list(uc_mgr, id, &devices); pa_xfree(id); - device->conflicting_devices = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); if (n_confdev <= 0) pa_log_debug("No %s for device %s", "_conflictingdevs", device_name); else { + device->conflicting_devices = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); ucm_add_devices_to_idxset(device->conflicting_devices, device, verb->devices, devices, n_confdev); snd_use_case_free_list(devices, n_confdev); } @@ -506,10 +518,10 @@ n_suppdev = snd_use_case_get_list(uc_mgr, id, &devices); pa_xfree(id); - device->supported_devices = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); if (n_suppdev <= 0) pa_log_debug("No %s for device %s", "_supporteddevs", device_name); else { + device->supported_devices = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); ucm_add_devices_to_idxset(device->supported_devices, device, verb->devices, devices, n_suppdev); snd_use_case_free_list(devices, n_suppdev); } @@ -518,16 +530,10 @@ }; /* Create a property list for this ucm modifier */ -static int ucm_get_modifier_property( - pa_alsa_ucm_modifier *modifier, - snd_use_case_mgr_t *uc_mgr, - pa_alsa_ucm_verb *verb, - const char *modifier_name) { +static int ucm_get_modifier_property(pa_alsa_ucm_modifier *modifier, snd_use_case_mgr_t *uc_mgr, const char *modifier_name) { const char *value; char *id; int i; - const char **devices; - int n_confdev, n_suppdev; for (i = 0; itemi.id; i++) { int err; @@ -544,28 +550,16 @@ } id = pa_sprintf_malloc("%s/%s", "_conflictingdevs", modifier_name); - n_confdev = snd_use_case_get_list(uc_mgr, id, &devices); + modifier->n_confdev = snd_use_case_get_list(uc_mgr, id, &modifier->conflicting_devices); pa_xfree(id); - - modifier->conflicting_devices = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); - if (n_confdev <= 0) + if (modifier->n_confdev < 0) pa_log_debug("No %s for modifier %s", "_conflictingdevs", modifier_name); - else { - ucm_add_devices_to_idxset(modifier->conflicting_devices, NULL, verb->devices, devices, n_confdev); - snd_use_case_free_list(devices, n_confdev); - } id = pa_sprintf_malloc("%s/%s", "_supporteddevs", modifier_name); - n_suppdev = snd_use_case_get_list(uc_mgr, id, &devices); + modifier->n_suppdev = snd_use_case_get_list(uc_mgr, id, &modifier->supported_devices); pa_xfree(id); - - modifier->supported_devices = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); - if (n_suppdev <= 0) + if (modifier->n_suppdev < 0) pa_log_debug("No %s for modifier %s", "_supporteddevs", modifier_name); - else { - ucm_add_devices_to_idxset(modifier->supported_devices, NULL, verb->devices, devices, n_suppdev); - snd_use_case_free_list(devices, n_suppdev); - } return 0; }; @@ -602,59 +596,6 @@ return 0; }; -static long ucm_device_status(pa_alsa_ucm_config *ucm, pa_alsa_ucm_device *dev) { - const char *dev_name = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME); - char *devstatus; - long status = 0; - - devstatus = pa_sprintf_malloc("_devstatus/%s", dev_name); - if (snd_use_case_geti(ucm->ucm_mgr, devstatus, &status) < 0) { - pa_log_debug("Failed to get status for UCM device %s", dev_name); - status = -1; - } - pa_xfree(devstatus); - - return status; -} - -static int ucm_device_disable(pa_alsa_ucm_config *ucm, pa_alsa_ucm_device *dev) { - const char *dev_name = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME); - - /* If any of dev's conflicting devices is enabled, trying to disable - * dev gives an error despite the fact that it's already disabled. - * Check that dev is enabled to avoid this error. */ - if (ucm_device_status(ucm, dev) == 0) { - pa_log_debug("UCM device %s is already disabled", dev_name); - return 0; - } - - pa_log_debug("Disabling UCM device %s", dev_name); - if (snd_use_case_set(ucm->ucm_mgr, "_disdev", dev_name) < 0) { - pa_log("Failed to disable UCM device %s", dev_name); - return -1; - } - - return 0; -} - -static int ucm_device_enable(pa_alsa_ucm_config *ucm, pa_alsa_ucm_device *dev) { - const char *dev_name = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME); - - /* We don't need to enable devices that are already enabled */ - if (ucm_device_status(ucm, dev) > 0) { - pa_log_debug("UCM device %s is already enabled", dev_name); - return 0; - } - - pa_log_debug("Enabling UCM device %s", dev_name); - if (snd_use_case_set(ucm->ucm_mgr, "_enadev", dev_name) < 0) { - pa_log("Failed to enable UCM device %s", dev_name); - return -1; - } - - return 0; -} - static int ucm_get_modifiers(pa_alsa_ucm_verb *verb, snd_use_case_mgr_t *uc_mgr) { const char **mod_list; int num_mod, i; @@ -685,57 +626,6 @@ return 0; }; -static long ucm_modifier_status(pa_alsa_ucm_config *ucm, pa_alsa_ucm_modifier *mod) { - const char *mod_name = pa_proplist_gets(mod->proplist, PA_ALSA_PROP_UCM_NAME); - char *modstatus; - long status = 0; - - modstatus = pa_sprintf_malloc("_modstatus/%s", mod_name); - if (snd_use_case_geti(ucm->ucm_mgr, modstatus, &status) < 0) { - pa_log_debug("Failed to get status for UCM modifier %s", mod_name); - status = -1; - } - pa_xfree(modstatus); - - return status; -} - -static int ucm_modifier_disable(pa_alsa_ucm_config *ucm, pa_alsa_ucm_modifier *mod) { - const char *mod_name = pa_proplist_gets(mod->proplist, PA_ALSA_PROP_UCM_NAME); - - /* We don't need to disable modifiers that are already disabled */ - if (ucm_modifier_status(ucm, mod) == 0) { - pa_log_debug("UCM modifier %s is already disabled", mod_name); - return 0; - } - - pa_log_debug("Disabling UCM modifier %s", mod_name); - if (snd_use_case_set(ucm->ucm_mgr, "_dismod", mod_name) < 0) { - pa_log("Failed to disable UCM modifier %s", mod_name); - return -1; - } - - return 0; -}
View file
pipewire-0.3.68.tar.gz/spa/plugins/alsa/acp/alsa-ucm.h -> pipewire-0.3.69.tar.gz/spa/plugins/alsa/acp/alsa-ucm.h
Changed
@@ -142,13 +142,12 @@ typedef struct pa_alsa_ucm_device pa_alsa_ucm_device; typedef struct pa_alsa_ucm_config pa_alsa_ucm_config; typedef struct pa_alsa_ucm_mapping_context pa_alsa_ucm_mapping_context; -typedef struct pa_alsa_ucm_profile_context pa_alsa_ucm_profile_context; typedef struct pa_alsa_ucm_port_data pa_alsa_ucm_port_data; typedef struct pa_alsa_ucm_volume pa_alsa_ucm_volume; int pa_alsa_ucm_query_profiles(pa_alsa_ucm_config *ucm, int card_index); pa_alsa_profile_set* pa_alsa_ucm_add_profile_set(pa_alsa_ucm_config *ucm, pa_channel_map *default_channel_map); -int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, pa_card *card, pa_alsa_profile *new_profile, pa_alsa_profile *old_profile); +int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, pa_card *card, const char *new_profile, const char *old_profile); int pa_alsa_ucm_get_verb(snd_use_case_mgr_t *uc_mgr, const char *verb_name, const char *verb_desc, pa_alsa_ucm_verb **p_verb); @@ -160,14 +159,14 @@ pa_card *card, snd_pcm_t *pcm_handle, bool ignore_dB); -void pa_alsa_ucm_add_port( +void pa_alsa_ucm_add_ports_combination( pa_hashmap *hash, pa_alsa_ucm_mapping_context *context, bool is_sink, pa_hashmap *ports, pa_card_profile *cp, pa_core *core); -int pa_alsa_ucm_set_port(pa_alsa_ucm_mapping_context *context, pa_device_port *port); +int pa_alsa_ucm_set_port(pa_alsa_ucm_mapping_context *context, pa_device_port *port, bool is_sink); void pa_alsa_ucm_free(pa_alsa_ucm_config *ucm); void pa_alsa_ucm_mapping_context_free(pa_alsa_ucm_mapping_context *context); @@ -224,8 +223,11 @@ pa_proplist *proplist; - pa_idxset *conflicting_devices; - pa_idxset *supported_devices; + int n_confdev; + int n_suppdev; + + const char **conflicting_devices; + const char **supported_devices; pa_direction_t action_direction; @@ -268,23 +270,21 @@ pa_alsa_ucm_config *ucm; pa_direction_t direction; - pa_alsa_ucm_device *ucm_device; - pa_alsa_ucm_modifier *ucm_modifier; -}; - -struct pa_alsa_ucm_profile_context { - pa_alsa_ucm_verb *verb; + pa_idxset *ucm_devices; + pa_idxset *ucm_modifiers; }; struct pa_alsa_ucm_port_data { pa_alsa_ucm_config *ucm; pa_device_port *core_port; - pa_alsa_ucm_device *device; + /* A single port will be associated with multiple devices if it represents + * a combination of devices. */ + pa_dynarray *devices; /* pa_alsa_ucm_device */ - /* verb name -> pa_alsa_path for volume control */ + /* profile name -> pa_alsa_path for volume control */ pa_hashmap *paths; - /* Current path, set when activating verb */ + /* Current path, set when activating profile */ pa_alsa_path *path; /* ELD info */
View file
pipewire-0.3.68.tar.gz/spa/plugins/alsa/acp/alsa-util.c -> pipewire-0.3.69.tar.gz/spa/plugins/alsa/acp/alsa-util.c
Changed
@@ -505,8 +505,6 @@ snd_pcm_uframes_t tsched_size, bool *use_mmap, bool *use_tsched, - pa_sample_format_t **query_supported_formats, - unsigned int **query_supported_rates, pa_alsa_profile_set *ps, pa_alsa_mapping **mapping) { @@ -545,8 +543,6 @@ tsched_size, use_mmap, use_tsched, - query_supported_formats, - query_supported_rates, m); if (pcm_handle) { @@ -574,8 +570,6 @@ tsched_size, use_mmap, use_tsched, - query_supported_formats, - query_supported_rates, m); if (pcm_handle) { @@ -600,8 +594,6 @@ tsched_size, use_mmap, use_tsched, - query_supported_formats, - query_supported_rates, false); pa_xfree(d); @@ -623,8 +615,6 @@ snd_pcm_uframes_t tsched_size, bool *use_mmap, bool *use_tsched, - pa_sample_format_t **query_supported_formats, - unsigned int **query_supported_rates, pa_alsa_mapping *m) { snd_pcm_t *pcm_handle; @@ -654,8 +644,6 @@ tsched_size, use_mmap, use_tsched, - query_supported_formats, - query_supported_rates, pa_channel_map_valid(&m->channel_map) /* Query the channel count if we don't know what we want */); if (!pcm_handle) @@ -693,8 +681,6 @@ snd_pcm_uframes_t tsched_size, bool *use_mmap, bool *use_tsched, - pa_sample_format_t **query_supported_formats, - unsigned int **query_supported_rates, bool require_exact_channel_number) { int err; @@ -722,12 +708,6 @@ pa_log_info("ALSA device open '%s' %s: %p", d, mode == SND_PCM_STREAM_CAPTURE ? "capture" : "playback", pcm_handle); - if (query_supported_formats) - *query_supported_formats = pa_alsa_get_supported_formats(pcm_handle, ss->format); - - if (query_supported_rates) - *query_supported_rates = pa_alsa_get_supported_rates(pcm_handle, ss->rate); - if ((err = pa_alsa_set_hw_params( pcm_handle, ss, @@ -801,8 +781,6 @@ snd_pcm_uframes_t tsched_size, bool *use_mmap, bool *use_tsched, - pa_sample_format_t **query_supported_formats, - unsigned int **query_supported_rates, bool require_exact_channel_number) { snd_pcm_t *pcm_handle; @@ -824,8 +802,6 @@ tsched_size, use_mmap, use_tsched, - query_supported_formats, - query_supported_rates, require_exact_channel_number); pa_xfree(d); @@ -1435,24 +1411,6 @@ return pa_sprintf_malloc("Audio%i", i); } -#endif - -static void dump_supported_rates(unsigned int* values) -{ - pa_strbuf *buf; - char *str; - int i; - - buf = pa_strbuf_new(); - - for (i = 0; valuesi; i++) { - pa_strbuf_printf(buf, " %u", valuesi); - } - - str = pa_strbuf_to_string_free(buf); - pa_log_debug("Supported rates:%s", str); - pa_xfree(str); -} unsigned int *pa_alsa_get_supported_rates(snd_pcm_t *pcm, unsigned int fallback_rate) { static unsigned int all_rates = { 8000, 11025, 12000, @@ -1460,8 +1418,7 @@ 32000, 44100, 48000, 64000, 88200, 96000, 128000, 176400, 192000, - 352800, 384000, - 705600, 768000 }; + 384000 }; bool supportedPA_ELEMENTSOF(all_rates) = { false, }; snd_pcm_hw_params_t *hwparams; unsigned int i, j, n, *rates = NULL; @@ -1503,40 +1460,39 @@ rates1 = 0; } - dump_supported_rates(rates); return rates; } pa_sample_format_t *pa_alsa_get_supported_formats(snd_pcm_t *pcm, pa_sample_format_t fallback_format) { - static const snd_pcm_format_t format_trans_to_pcm = { - PA_SAMPLE_U8 = SND_PCM_FORMAT_U8, - PA_SAMPLE_ALAW = SND_PCM_FORMAT_A_LAW, - PA_SAMPLE_ULAW = SND_PCM_FORMAT_MU_LAW, - PA_SAMPLE_S16LE = SND_PCM_FORMAT_S16_LE, - PA_SAMPLE_S16BE = SND_PCM_FORMAT_S16_BE, - PA_SAMPLE_FLOAT32LE = SND_PCM_FORMAT_FLOAT_LE, - PA_SAMPLE_FLOAT32BE = SND_PCM_FORMAT_FLOAT_BE, - PA_SAMPLE_S32LE = SND_PCM_FORMAT_S32_LE, - PA_SAMPLE_S32BE = SND_PCM_FORMAT_S32_BE, - PA_SAMPLE_S24LE = SND_PCM_FORMAT_S24_3LE, - PA_SAMPLE_S24BE = SND_PCM_FORMAT_S24_3BE, - PA_SAMPLE_S24_32LE = SND_PCM_FORMAT_S24_LE, - PA_SAMPLE_S24_32BE = SND_PCM_FORMAT_S24_BE, + static const snd_pcm_format_t format_trans_to_pa = { + SND_PCM_FORMAT_U8 = PA_SAMPLE_U8, + SND_PCM_FORMAT_A_LAW = PA_SAMPLE_ALAW, + SND_PCM_FORMAT_MU_LAW = PA_SAMPLE_ULAW, + SND_PCM_FORMAT_S16_LE = PA_SAMPLE_S16LE, + SND_PCM_FORMAT_S16_BE = PA_SAMPLE_S16BE, + SND_PCM_FORMAT_FLOAT_LE = PA_SAMPLE_FLOAT32LE, + SND_PCM_FORMAT_FLOAT_BE = PA_SAMPLE_FLOAT32BE, + SND_PCM_FORMAT_S32_LE = PA_SAMPLE_S32LE, + SND_PCM_FORMAT_S32_BE = PA_SAMPLE_S32BE, + SND_PCM_FORMAT_S24_3LE = PA_SAMPLE_S24LE, + SND_PCM_FORMAT_S24_3BE = PA_SAMPLE_S24BE, + SND_PCM_FORMAT_S24_LE = PA_SAMPLE_S24_32LE, + SND_PCM_FORMAT_S24_BE = PA_SAMPLE_S24_32BE, }; - static const pa_sample_format_t all_formats = { - PA_SAMPLE_U8, - PA_SAMPLE_ALAW, - PA_SAMPLE_ULAW, - PA_SAMPLE_S16LE, - PA_SAMPLE_S16BE, - PA_SAMPLE_FLOAT32LE, - PA_SAMPLE_FLOAT32BE, - PA_SAMPLE_S32LE, - PA_SAMPLE_S32BE, - PA_SAMPLE_S24LE, - PA_SAMPLE_S24BE, - PA_SAMPLE_S24_32LE, - PA_SAMPLE_S24_32BE, + static const snd_pcm_format_t all_formats = { + SND_PCM_FORMAT_U8, + SND_PCM_FORMAT_A_LAW, + SND_PCM_FORMAT_MU_LAW, + SND_PCM_FORMAT_S16_LE, + SND_PCM_FORMAT_S16_BE, + SND_PCM_FORMAT_FLOAT_LE, + SND_PCM_FORMAT_FLOAT_BE, + SND_PCM_FORMAT_S32_LE, + SND_PCM_FORMAT_S32_BE, + SND_PCM_FORMAT_S24_3LE, + SND_PCM_FORMAT_S24_3BE, + SND_PCM_FORMAT_S24_LE, + SND_PCM_FORMAT_S24_BE, }; bool supportedPA_ELEMENTSOF(all_formats) = { false, @@ -1554,7 +1510,7 @@ }
View file
pipewire-0.3.68.tar.gz/spa/plugins/alsa/acp/alsa-util.h -> pipewire-0.3.69.tar.gz/spa/plugins/alsa/acp/alsa-util.h
Changed
@@ -64,8 +64,6 @@ snd_pcm_uframes_t tsched_size, bool *use_mmap, /* modified at return */ bool *use_tsched, /* modified at return */ - pa_sample_format_t **query_supported_formats, /* modified at return */ - unsigned int **query_supported_rates, /* modified at return */ pa_alsa_profile_set *ps, pa_alsa_mapping **mapping); /* modified at return */ #endif @@ -82,8 +80,6 @@ snd_pcm_uframes_t tsched_size, bool *use_mmap, /* modified at return */ bool *use_tsched, /* modified at return */ - pa_sample_format_t **query_supported_formats, /* modified at return */ - unsigned int **query_supported_rates, /* modified at return */ pa_alsa_mapping *mapping); /* Opens the explicit ALSA device */ @@ -98,8 +94,6 @@ snd_pcm_uframes_t tsched_size, bool *use_mmap, /* modified at return */ bool *use_tsched, /* modified at return */ - pa_sample_format_t **query_supported_formats, /* modified at return */ - unsigned int **query_supported_rates, /* modified at return */ bool require_exact_channel_number); /* Opens the explicit ALSA device with a fallback list */ @@ -115,8 +109,6 @@ snd_pcm_uframes_t tsched_size, bool *use_mmap, /* modified at return */ bool *use_tsched, /* modified at return */ - pa_sample_format_t **query_supported_formats, /* modified at return */ - unsigned int **query_supported_rates, /* modified at return */ bool require_exact_channel_number); #if 0
View file
pipewire-0.3.68.tar.gz/spa/plugins/alsa/acp/compat.h -> pipewire-0.3.69.tar.gz/spa/plugins/alsa/acp/compat.h
Changed
@@ -47,12 +47,10 @@ #define PA_LIKELY(x) (__builtin_expect(!!(x),1)) #define PA_UNLIKELY(x) (__builtin_expect(!!(x),0)) #define PA_PRINTF_FUNC(fmt, arg1) __attribute__((format(printf, fmt, arg1))) -#define PA_UNUSED __attribute__ ((unused)) #else #define PA_LIKELY(x) (x) #define PA_UNLIKELY(x) (x) #define PA_PRINTF_FUNC(fmt, arg1) -#define PA_UNUSED #endif #define PA_MIN(a,b) \ @@ -98,7 +96,7 @@ PA_AVAILABLE_YES = 2, } pa_available_t; -#define PA_RATE_MAX (48000U*16U) +#define PA_RATE_MAX (48000U*8U) typedef enum pa_sample_format { PA_SAMPLE_U8, /**< Unsigned 8 Bit PCM */
View file
pipewire-0.3.68.tar.gz/spa/plugins/alsa/acp/idxset.h -> pipewire-0.3.69.tar.gz/spa/plugins/alsa/acp/idxset.h
Changed
@@ -130,25 +130,13 @@ return count; } -static inline pa_idxset_item *pa_idxset_search(pa_idxset *s, uint32_t *idx) +static inline void *pa_idxset_search(pa_idxset *s, uint32_t *idx) { pa_idxset_item *item; for (item = pa_array_get_unchecked(&s->array, *idx, pa_idxset_item); pa_array_check(&s->array, item); item++, (*idx)++) { if (item->ptr != NULL) - return item; - } - *idx = PA_IDXSET_INVALID; - return NULL; -} - -static inline pa_idxset_item *pa_idxset_reverse_search(pa_idxset *s, uint32_t *idx) -{ - pa_idxset_item *item; - for (item = pa_array_get_unchecked(&s->array, *idx, pa_idxset_item); - pa_array_check(&s->array, item); item--, (*idx)--) { - if (item->ptr != NULL) - return item; + return item->ptr; } *idx = PA_IDXSET_INVALID; return NULL; @@ -156,93 +144,29 @@ static inline void *pa_idxset_next(pa_idxset *s, uint32_t *idx) { - pa_idxset_item *item; (*idx)++;; - item = pa_idxset_search(s, idx); - return item ? item->ptr : NULL; + return pa_idxset_search(s, idx); } static inline void* pa_idxset_first(pa_idxset *s, uint32_t *idx) { uint32_t i = 0; - pa_idxset_item *item = pa_idxset_search(s, &i); + void *ptr = pa_idxset_search(s, &i); if (idx) *idx = i; - return item ? item->ptr : NULL; -} - -static inline void* pa_idxset_last(pa_idxset *s, uint32_t *idx) -{ - uint32_t i = pa_array_get_len(&s->array, pa_idxset_item) - 1; - pa_idxset_item *item = pa_idxset_reverse_search(s, &i); - if (idx) - *idx = i; - return item ? item->ptr : NULL; -} - -static inline void* pa_idxset_steal_last(pa_idxset *s, uint32_t *idx) -{ - uint32_t i = pa_array_get_len(&s->array, pa_idxset_item) - 1; - void *ptr = NULL; - pa_idxset_item *item = pa_idxset_reverse_search(s, &i); - if (idx) - *idx = i; - if (item) { - ptr = item->ptr; - item->ptr = NULL; - pa_array_remove(&s->array, item); - } return ptr; } static inline void* pa_idxset_get_by_data(pa_idxset*s, const void *p, uint32_t *idx) { pa_idxset_item *item = pa_idxset_find(s, p); - if (item == NULL) { - if (idx) - *idx = PA_IDXSET_INVALID; + if (item == NULL) return NULL; - } if (idx) *idx = item - (pa_idxset_item*)s->array.data; return item->ptr; } -static inline bool pa_idxset_contains(pa_idxset *s, const void *p) -{ - return pa_idxset_get_by_data(s, p, NULL) == p; -} - -static inline bool pa_idxset_isdisjoint(pa_idxset *s, pa_idxset *t) -{ - pa_idxset_item *item; - pa_array_for_each(item, &s->array) { - if (item->ptr && pa_idxset_contains(t, item->ptr)) - return false; - } - return true; -} - -static inline bool pa_idxset_issubset(pa_idxset *s, pa_idxset *t) -{ - pa_idxset_item *item; - pa_array_for_each(item, &s->array) { - if (item->ptr && !pa_idxset_contains(t, item->ptr)) - return false; - } - return true; -} - -static inline bool pa_idxset_issuperset(pa_idxset *s, pa_idxset *t) -{ - return pa_idxset_issubset(t, s); -} - -static inline bool pa_idxset_equals(pa_idxset *s, pa_idxset *t) -{ - return pa_idxset_issubset(s, t) && pa_idxset_issuperset(s, t); -} - static inline void* pa_idxset_get_by_index(pa_idxset*s, uint32_t idx) { pa_idxset_item *item;
View file
pipewire-0.3.68.tar.gz/spa/plugins/alsa/alsa-pcm.c -> pipewire-0.3.69.tar.gz/spa/plugins/alsa/alsa-pcm.c
Changed
@@ -1567,10 +1567,13 @@ is_batch = snd_pcm_hw_params_is_batch(params) && !state->disable_batch; + /* no period size specified. If we are batch or not using timers, + * use the graph duration as the period */ + if (period_size == 0 && (is_batch || state->disable_tsched)) + period_size = state->position ? state->position->clock.duration : DEFAULT_PERIOD; + if (is_batch) { if (period_size == 0) - period_size = state->position ? state->position->clock.duration : DEFAULT_PERIOD; - if (period_size == 0) period_size = DEFAULT_PERIOD; /* batch devices get their hw pointers updated every period. Make * the period smaller and add one period of headroom. Limit the @@ -1616,10 +1619,18 @@ } state->headroom = state->default_headroom; - /* If tsched is disabled, we know the pointers are updated when we wake - * up, so we don't need the additional headroom */ - if (is_batch && !state->disable_tsched) - state->headroom += period_size; + if (!state->disable_tsched) { + /* When using timers, we might miss the pointer update for batch + * devices so add some extra headroom. With IRQ, we know the pointers + * are updated when we wake up and we don't need the headroom. */ + if (is_batch) + state->headroom += period_size; + /* Add 32 extra samples of headroom to handle jitter in capture. + * For IRQ, we don't need this because when we wake up, we have + * exactly enough samples to read or write. */ + if (state->stream == SND_PCM_STREAM_CAPTURE) + state->headroom = SPA_MAX(state->headroom, 32u); + } state->max_delay = state->buffer_frames / 2; if (spa_strstartswith(state->props.device, "a52") || @@ -1921,9 +1932,7 @@ *delay = state->buffer_frames - avail; } else { *delay = avail; - *target = SPA_MAX(*target, state->read_size); - if (state->matching) - *target += 32; + *target = SPA_MAX(*target, state->read_size + state->headroom); } *target = SPA_CLAMP(*target, state->min_delay, state->max_delay); return 0; @@ -1935,10 +1944,15 @@ double err, corr; int32_t diff; - if (state->stream == SND_PCM_STREAM_PLAYBACK) - err = delay - target; - else - err = target - delay; + if (state->disable_tsched && !follower) { + err = (int64_t)(current_time - state->next_time); + err = err / 1e9 * state->rate; + } else { + if (state->stream == SND_PCM_STREAM_PLAYBACK) + err = delay - target; + else + err = target - delay; + } if (SPA_UNLIKELY(state->dll.bw == 0.0)) { spa_dll_set_bw(&state->dll, SPA_DLL_BW_MAX, state->threshold, state->rate); @@ -1955,12 +1969,14 @@ state->alsa_sync = true; state->alsa_sync_warning = false; } - if (err > state->max_error) { - err = state->max_error; + if (err > state->max_resync) { state->alsa_sync = true; - } else if (err < -state->max_error) { - err = -state->max_error; + if (err > state->max_error) + err = state->max_error; + } else if (err < -state->max_resync) { state->alsa_sync = true; + if (err < -state->max_error) + err = -state->max_error; } if (!follower || state->matching) @@ -2002,8 +2018,8 @@ state->clock->next_nsec = state->next_time; } - spa_log_trace_fp(state->log, "%p: follower:%d %"PRIu64" %f %ld %f %f %u", - state, follower, current_time, corr, delay, err, state->threshold * corr, + spa_log_trace_fp(state->log, "%p: follower:%d %"PRIu64" %f %ld %ld %f %f %u", + state, follower, current_time, corr, delay, target, err, state->threshold * corr, state->threshold); return 0; @@ -2065,6 +2081,7 @@ return -EIO; state->threshold = SPA_SCALE32_UP(state->duration, state->rate, state->rate_denom); state->max_error = SPA_MAX(256.0f, state->threshold / 2.0f); + state->max_resync = SPA_MIN(state->threshold, state->max_error); state->resample = ((uint32_t)state->rate != state->rate_denom) || state->matching; state->alsa_sync = true; } @@ -2478,14 +2495,15 @@ int res; struct spa_io_buffers *io; - if (SPA_UNLIKELY(delay < target)) { - spa_log_trace(state->log, "%p: early wakeup %ld %ld", state, delay, target); + if (SPA_UNLIKELY(delay < state->read_size)) { + spa_log_trace(state->log, "%p: early wakeup %ld %ld %d", state, delay, target, + state->read_size); state->next_time = current_time + (target - delay) * SPA_NSEC_PER_SEC / state->rate; return -EAGAIN; } - if (SPA_UNLIKELY(res = update_time(state, current_time, delay, target, false)) < 0) + if (SPA_UNLIKELY((res = update_time(state, current_time, delay, target, false)) < 0)) return res; if ((res = spa_alsa_read(state)) < 0) @@ -2514,6 +2532,14 @@ return 0; } +static uint64_t get_time_ns(struct state *state) +{ + struct timespec now; + if (spa_system_clock_gettime(state->data_system, CLOCK_MONOTONIC, &now) < 0) + return 0; + return SPA_TIMESPEC_TO_NSEC(&now); +} + static void alsa_wakeup_event(struct spa_source *source) { struct state *state = source->data; @@ -2526,6 +2552,8 @@ int err; unsigned short revents; + current_time = get_time_ns(state); + for (int i = 0; i < state->n_fds; i++) { state->pfdsi.revents = state->sourcei.rmask; /* Reset so that we only handle all our sources' events once */ @@ -2543,17 +2571,20 @@ spa_log_trace_fp(state->log, "Woken up with no work to do"); return; } - } else if (SPA_LIKELY(state->started)) { - if (SPA_UNLIKELY((res = spa_system_timerfd_read(state->data_system, + } else { + if (SPA_LIKELY(state->started)) { + if (SPA_UNLIKELY((res = spa_system_timerfd_read(state->data_system, state->timerfd, &expire)) < 0)) { /* we can get here when the timer is changed since the last - * timerfd wakeup, for example by do_reassign_follower() executed - * in the same epoll wakeup cycle */ - if (res != -EAGAIN) - spa_log_warn(state->log, "%p: error reading timerfd: %s", - state, spa_strerror(res)); - return; + * timerfd wakeup, for example by do_reassign_follower() executed + * in the same epoll wakeup cycle */ + if (res != -EAGAIN) + spa_log_warn(state->log, "%p: error reading timerfd: %s", + state, spa_strerror(res)); + return; + } } + current_time = state->next_time; } if (SPA_UNLIKELY((res = check_position_config(state)) < 0)) { @@ -2562,8 +2593,6 @@ return; } - current_time = state->next_time; - if (SPA_UNLIKELY(get_status(state, current_time, &delay, &target) < 0)) { spa_log_error(state->log, "get_status error"); state->next_time += state->threshold * 1e9 / state->rate; @@ -2572,11 +2601,7 @@ #ifndef FASTPATH if (SPA_UNLIKELY(spa_log_level_topic_enabled(state->log, SPA_LOG_TOPIC_DEFAULT, SPA_LOG_LEVEL_TRACE))) { - struct timespec now; - uint64_t nsec; - if (spa_system_clock_gettime(state->data_system, CLOCK_MONOTONIC, &now) < 0) - return; - nsec = SPA_TIMESPEC_TO_NSEC(&now); + uint64_t nsec = get_time_ns(state); spa_log_trace_fp(state->log, "%p: wakeup %lu %lu %"PRIu64" %"PRIu64" %"PRIi64
View file
pipewire-0.3.68.tar.gz/spa/plugins/alsa/alsa-pcm.h -> pipewire-0.3.69.tar.gz/spa/plugins/alsa/alsa-pcm.h
Changed
@@ -213,6 +213,7 @@ struct spa_dll dll; double max_error; + double max_resync; struct spa_latency_info latency2; struct spa_process_latency_info process_latency;
View file
pipewire-0.3.69.tar.gz/spa/plugins/alsa/mixer/paths/audigy-analog-output-mirror.conf
Added
@@ -0,0 +1,56 @@ +; Mixer path for the Sound Blaster Audigy series, which uses the EMU10K2 DSP. +; We target 'Wave' and other non-'PCM' controls as a special case for when +; the device's stereo-to-all-speakers mirroring mode is in use. (For example, +; the Analog Stereo Output profile.) +; https://docs.kernel.org/sound/cards/audigy-mixer.html +; +; See analog-output.conf.common for an explanation on the directives + +General +priority = 99 +description-key = analog-output + +Element Master +switch = mute +volume = merge +override-map.1 = all +override-map.2 = all-left,all-right + +Element Wave +volume = merge +override-map.1 = all +override-map.2 = all-left,all-right + +# The following elements also exist in analog-output.conf. We list them here +# instead of including that file, for ideal positioning of the Wave element: +# Placing Wave below the Master element prevents Master from reaching its +# loudest until the user raises the unified volume control to maximum. +# (This should reduce the chance of a surprise speaker blow-out.) +# Placing Wave above the per-channel elements yields even steps at low volume. + +Element Front +volume = merge +override-map.1 = all-front +override-map.2 = front-left,front-right + +Element Surround +volume = merge +override-map.1 = all-rear +override-map.2 = rear-left,rear-right + +Element Side +volume = merge +override-map.1 = all-side +override-map.2 = side-left,side-right + +Element Center +volume = merge +override-map.1 = all-center +override-map.2 = all-center,all-center + +Element LFE +volume = merge +override-map.1 = lfe +override-map.2 = lfe,lfe + +.include analog-output.conf.common
View file
pipewire-0.3.69.tar.gz/spa/plugins/alsa/mixer/paths/audigy-analog-output.conf
Added
@@ -0,0 +1,44 @@ +; Mixer path for the Sound Blaster Audigy series, which uses the EMU10K2 DSP. +; We target 'PCM Front' and similarly named controls instead of 'Front' et al. +; because the latter affect volume only in the device's stereo-to-all-speakers +; mirroring mode, which is not used by most profiles. +; https://docs.kernel.org/sound/cards/audigy-mixer.html +; +; See analog-output.conf.common for an explanation on the directives + +General +priority = 99 +description-key = analog-output + +Element Master +switch = mute +volume = merge +override-map.1 = all +override-map.2 = all-left,all-right + +Element PCM Front +volume = merge +override-map.1 = all-front +override-map.2 = front-left,front-right + +Element PCM Surround +volume = merge +override-map.1 = all-rear +override-map.2 = rear-left,rear-right + +Element PCM Side +volume = merge +override-map.1 = all-side +override-map.2 = side-left,side-right + +Element PCM Center +volume = merge +override-map.1 = all-center +override-map.2 = all-center,all-center + +Element PCM LFE +volume = merge +override-map.1 = lfe +override-map.2 = lfe,lfe + +.include analog-output.conf.common
View file
pipewire-0.3.68.tar.gz/spa/plugins/alsa/mixer/profile-sets/audigy.conf -> pipewire-0.3.69.tar.gz/spa/plugins/alsa/mixer/profile-sets/audigy.conf
Changed
@@ -15,10 +15,11 @@ ; Creative Sound Blaster Audigy product line ; -; These are just copies of the mappings we find in default.conf, with the -; small change of making analog-stereo and analog-mono non-fallback mappings. -; This is needed because these cards only support duplex profiles with mono -; inputs, and in the default configuration, with stereo being a fallback +; These are copies of the mappings we find in default.conf, but with analog +; mixer paths targeting appropriate Audigy driver controls, and the small +; change of making analog-stereo and analog-mono non-fallback mappings. +; The latter is needed because these cards only support duplex profiles with +; mono inputs, and in the default configuration, with stereo being a fallback ; mapping, the mono mapping is never tried. ; ; See default.conf for an explanation on the directives used here. @@ -30,7 +31,7 @@ Mapping analog-stereo device-strings = hw:%f channel-map = front-left,front-right -paths-output = analog-output analog-output-lineout analog-output-speaker analog-output-headphones analog-output-headphones-2 +paths-output = audigy-analog-output-mirror analog-output-lineout analog-output-speaker analog-output-headphones analog-output-headphones-2 paths-input = analog-input-front-mic analog-input-rear-mic analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line analog-input-headphone-mic analog-input-headset-mic priority = 1 @@ -38,43 +39,42 @@ Mapping analog-mono device-strings = hw:%f channel-map = mono -paths-output = analog-output analog-output-lineout analog-output-speaker analog-output-headphones analog-output-headphones-2 analog-output-mono +paths-output = audigy-analog-output-mirror analog-output-lineout analog-output-speaker analog-output-headphones analog-output-headphones-2 analog-output-mono paths-input = analog-input-front-mic analog-input-rear-mic analog-input-internal-mic analog-input-dock-mic analog-input analog-input-mic analog-input-linein analog-input-aux analog-input-video analog-input-tvtuner analog-input-fm analog-input-mic-line analog-input-headset-mic priority = 1 -# The rest of these are identical to what's in default.conf Mapping analog-surround-21 device-strings = surround21:%f channel-map = front-left,front-right,lfe -paths-output = analog-output analog-output-lineout analog-output-speaker +paths-output = audigy-analog-output analog-output-lineout analog-output-speaker priority = 13 direction = output Mapping analog-surround-40 device-strings = surround40:%f channel-map = front-left,front-right,rear-left,rear-right -paths-output = analog-output analog-output-lineout analog-output-speaker +paths-output = audigy-analog-output analog-output-lineout analog-output-speaker priority = 12 direction = output Mapping analog-surround-41 device-strings = surround41:%f channel-map = front-left,front-right,rear-left,rear-right,lfe -paths-output = analog-output analog-output-lineout analog-output-speaker +paths-output = audigy-analog-output analog-output-lineout analog-output-speaker priority = 13 direction = output Mapping analog-surround-50 device-strings = surround50:%f channel-map = front-left,front-right,rear-left,rear-right,front-center -paths-output = analog-output analog-output-lineout analog-output-speaker +paths-output = audigy-analog-output analog-output-lineout analog-output-speaker priority = 12 direction = output Mapping analog-surround-51 device-strings = surround51:%f channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe -paths-output = analog-output analog-output-lineout analog-output-speaker +paths-output = audigy-analog-output analog-output-lineout analog-output-speaker priority = 13 direction = output @@ -82,7 +82,7 @@ device-strings = surround71:%f channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe,side-left,side-right description = Analog Surround 7.1 -paths-output = analog-output analog-output-lineout analog-output-speaker +paths-output = audigy-analog-output analog-output-lineout analog-output-speaker priority = 12 direction = output
View file
pipewire-0.3.68.tar.gz/spa/plugins/bluez5/backend-native.c -> pipewire-0.3.69.tar.gz/spa/plugins/bluez5/backend-native.c
Changed
@@ -1062,6 +1062,7 @@ rfcomm_send_reply(rfcomm, "OK"); } else if (sscanf(buf, "AT+BIEV=%u,%u", &indicator, &indicator_value) == 2) { process_hfp_hf_indicator(rfcomm, indicator, indicator_value); + rfcomm_send_reply(rfcomm, "OK"); } else if (sscanf(buf, "AT+XAPL=%04x-%04x-%*^,,%u", &xapl_vendor, &xapl_product, &xapl_features) == 3) { if (xapl_features & SPA_BT_HFP_HF_XAPL_FEATURE_BATTERY_REPORTING) { /* claim, that we support battery status reports */ @@ -1083,6 +1084,7 @@ process_iphoneaccev_indicator(rfcomm, key, value); buf += r; } + rfcomm_send_reply(rfcomm, "OK"); } else if (spa_strstartswith(buf, "AT+APLSIRI?")) { // This command is sent when we activate Apple extensions rfcomm_send_reply(rfcomm, "OK");
View file
pipewire-0.3.68.tar.gz/spa/plugins/bluez5/bap-codec-caps.h -> pipewire-0.3.69.tar.gz/spa/plugins/bluez5/bap-codec-caps.h
Changed
@@ -83,14 +83,6 @@ #define LC3_MAX_CHANNELS 28 -typedef struct { - uint8_t rate; - uint8_t frame_duration; - uint32_t channels; - uint16_t framelen; - uint8_t n_blks; -} __attribute__ ((packed)) bap_lc3_t; - #define BT_ISO_QOS_CIG_UNSET 0xff #define BT_ISO_QOS_CIS_UNSET 0xff @@ -98,6 +90,12 @@ #define BT_ISO_QOS_TARGET_LATENCY_BALANCED 0x02 #define BT_ISO_QOS_TARGET_LATENCY_RELIABILITY 0x03 +struct __attribute__((packed)) ltv { + uint8_t len; + uint8_t type; + uint8_t value; +}; + struct bap_endpoint_qos { uint8_t framing; uint8_t phy;
View file
pipewire-0.3.68.tar.gz/spa/plugins/bluez5/bap-codec-lc3.c -> pipewire-0.3.69.tar.gz/spa/plugins/bluez5/bap-codec-lc3.c
Changed
@@ -34,17 +34,19 @@ unsigned int codesize; }; -struct __attribute__((packed)) ltv { - uint8_t len; - uint8_t type; - uint8_t value; -}; - struct pac_data { const uint8_t *data; size_t size; }; +typedef struct { + uint8_t rate; + uint8_t frame_duration; + uint32_t channels; + uint16_t framelen; + uint8_t n_blks; +} bap_lc3_t; + static int write_ltv(uint8_t *dest, uint8_t type, void* value, size_t len) { struct ltv *ltv = (struct ltv *)dest; @@ -82,6 +84,7 @@ data += write_ltv_uint8(data, LC3_TYPE_DUR, LC3_DUR_ANY); data += write_ltv_uint8(data, LC3_TYPE_CHAN, LC3_CHAN_1 | LC3_CHAN_2); data += write_ltv(data, LC3_TYPE_FRAMELEN, framelen, sizeof(framelen)); + /* XXX: we support only one frame block -> max 2 frames per SDU */ data += write_ltv_uint8(data, LC3_TYPE_BLKS, 2); return data - caps; @@ -119,9 +122,26 @@ return pac + 1; } -static bool parse_capabilities(bap_lc3_t *conf, const uint8_t *data, size_t data_size) +static uint8_t get_num_channels(uint32_t channels) +{ + uint8_t num; + + if (channels == 0) + return 1; /* MONO */ + + for (num = 0; channels; channels >>= 1) + if (channels & 0x1) + ++num; + + return num; +} + +static bool select_config(bap_lc3_t *conf, const struct pac_data *pac) { + const uint8_t *data = pac->data; + size_t data_size = pac->size; uint16_t framelen_min = 0, framelen_max = 0; + int max_frames = -1; if (!data_size) return false; @@ -129,6 +149,9 @@ conf->frame_duration = 0xFF; + /* XXX: we always use one frame block */ + conf->n_blks = 1; + while (data_size > 0) { struct ltv *ltv = (struct ltv *)data; @@ -168,12 +191,11 @@ spa_return_val_if_fail(ltv->len == 2, false); { uint8_t channels = ltv->value0; - /* Only mono or stereo streams are currently supported, - * in both case Audio location is defined as both Front Left - * and Front Right, difference is done by the n_blks parameter. - */ - if ((channels & LC3_CHAN_2) || (channels & LC3_CHAN_1)) + /* XXX: we hardcode mono or stereo stream */ + if (channels & LC3_CHAN_2) conf->channels = LC3_CONFIG_CHNL_FR | LC3_CONFIG_CHNL_FL; + else if (channels & LC3_CHAN_1) + conf->channels = 0; /* mono (omit Audio_Channel_Allocation) */ else return false; } @@ -185,9 +207,7 @@ break; case LC3_TYPE_BLKS: spa_return_val_if_fail(ltv->len == 2, false); - conf->n_blks = ltv->value0; - if (!conf->n_blks) - return false; + max_frames = ltv->value0; break; default: return false; @@ -196,37 +216,42 @@ data += ltv->len + 1; } + /* Default: 1 per channel (BAP v1.0.1 Sec 4.3.1) */ + if (max_frames < 0) + max_frames = get_num_channels(conf->channels); + if (max_frames < get_num_channels(conf->channels)) + return false; + if (framelen_min < LC3_MIN_FRAME_BYTES || framelen_max > LC3_MAX_FRAME_BYTES) return false; if (conf->frame_duration == 0xFF || !conf->rate) return false; - if (!conf->channels) - conf->channels = LC3_CONFIG_CHNL_FL; + /* BAP v1.0.1 Table 5.2; high-reliability */ switch (conf->rate) { case LC3_CONFIG_FREQ_48KHZ: if (conf->frame_duration == LC3_CONFIG_DURATION_7_5) - conf->framelen = 117; + conf->framelen = 117; /* 48_5_2 */ else - conf->framelen = 120; + conf->framelen = 120; /* 48_4_2 */ break; case LC3_CONFIG_FREQ_24KHZ: if (conf->frame_duration == LC3_CONFIG_DURATION_7_5) - conf->framelen = 45; + conf->framelen = 45; /* 24_1_2 */ else - conf->framelen = 60; + conf->framelen = 60; /* 24_2_2 */ break; case LC3_CONFIG_FREQ_16KHZ: if (conf->frame_duration == LC3_CONFIG_DURATION_7_5) - conf->framelen = 30; + conf->framelen = 30; /* 16_1_2 */ else - conf->framelen = 40; + conf->framelen = 40; /* 16_2_2 */ break; case LC3_CONFIG_FREQ_8KHZ: if (conf->frame_duration == LC3_CONFIG_DURATION_7_5) - conf->framelen = 26; + conf->framelen = 26; /* 8_1_2 */ else - conf->framelen = 30; + conf->framelen = 30; /* 8_2_2 */ break; default: return false; @@ -243,6 +268,9 @@ conf->frame_duration = 0xFF; + /* Absent Codec_Frame_Blocks_Per_SDU means 0x1 (BAP v1.0.1 Sec 4.3.2) */ + conf->n_blks = 1; + while (data_size > 0) { struct ltv *ltv = (struct ltv *)data; @@ -269,7 +297,8 @@ case LC3_TYPE_BLKS: spa_return_val_if_fail(ltv->len == 2, false); conf->n_blks = ltv->value0; - if (!conf->n_blks) + /* XXX: we only support 1 frame block for now */ + if (conf->n_blks != 1) return false; break; default: @@ -325,8 +354,8 @@ bap_lc3_t conf1, conf2; int res1, res2; - res1 = parse_capabilities(&conf1, pac1->data, pac1->size) ? (int)sizeof(bap_lc3_t) : -EINVAL; - res2 = parse_capabilities(&conf2, pac2->data, pac2->size) ? (int)sizeof(bap_lc3_t) : -EINVAL; + res1 = select_config(&conf1, pac1) ? (int)sizeof(bap_lc3_t) : -EINVAL; + res2 = select_config(&conf2, pac2) ? (int)sizeof(bap_lc3_t) : -EINVAL; return conf_cmp(&conf1, res1, &conf2, res2); } @@ -353,12 +382,16 @@ qsort(pacs, npacs, sizeof(struct pac_data), pac_cmp); - if (!parse_capabilities(&conf, pacs0.data, pacs0.size)) + if (!select_config(&conf, &pacs0)) return -ENOTSUP; data += write_ltv_uint8(data, LC3_TYPE_FREQ, conf.rate); data += write_ltv_uint8(data, LC3_TYPE_DUR, conf.frame_duration); - data += write_ltv_uint32(data, LC3_TYPE_CHAN, htobl(conf.channels)); + + /* Indicate MONO with absent Audio_Channel_Allocation (BAP v1.0.1 Sec. 4.3.2) */ + if (conf.channels != 0) + data += write_ltv_uint32(data, LC3_TYPE_CHAN, htobl(conf.channels)); +
View file
pipewire-0.3.68.tar.gz/spa/plugins/bluez5/bluez5-dbus.c -> pipewire-0.3.69.tar.gz/spa/plugins/bluez5/bluez5-dbus.c
Changed
@@ -10,6 +10,7 @@ #include <sys/stat.h> #include <sys/socket.h> #include <fcntl.h> +#include <limits.h> #include <bluetooth/bluetooth.h> @@ -38,6 +39,8 @@ #include "iso-io.h" #include "defs.h" +#include "bap-codec-caps.h" + static struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.bluez5"); #undef SPA_LOG_TOPIC_DEFAULT #define SPA_LOG_TOPIC_DEFAULT &log_topic @@ -1266,6 +1269,7 @@ spa_list_init(&d->remote_endpoint_list); spa_list_init(&d->transport_list); spa_list_init(&d->codec_switch_list); + spa_list_init(&d->set_membership_list); spa_hook_list_init(&d->listener_list); @@ -1292,6 +1296,7 @@ struct spa_bt_media_codec_switch *sw; struct spa_bt_transport *t, *tt; struct spa_bt_monitor *monitor = device->monitor; + struct spa_bt_set_membership *s; spa_log_debug(monitor->log, "%p", device); @@ -1321,6 +1326,13 @@ spa_list_consume(sw, &device->codec_switch_list, device_link) media_codec_switch_free(sw); + spa_list_consume(s, &device->set_membership_list, link) { + spa_list_remove(&s->link); + spa_list_remove(&s->others); + free(s->path); + free(s); + } + spa_list_remove(&device->link); free(device->path); free(device->alias); @@ -1332,6 +1344,84 @@ free(device); } +static struct spa_bt_set_membership *device_set_find(struct spa_bt_monitor *monitor, const char *path) +{ + struct spa_bt_device *d; + + spa_list_for_each(d, &monitor->device_list, link) { + struct spa_bt_set_membership *s; + + spa_list_for_each(s, &d->set_membership_list, link) { + if (spa_streq(s->path, path)) + return s; + } + } + + return NULL; +} + +static int device_add_device_set(struct spa_bt_device *device, const char *path, uint8_t rank) +{ + struct spa_bt_monitor *monitor = device->monitor; + struct spa_bt_set_membership *s, *set; + + spa_list_for_each(s, &device->set_membership_list, link) { + if (spa_streq(s->path, path)) { + if (rank) + s->rank = rank; + return 0; + } + } + + s = calloc(1, sizeof(struct spa_bt_set_membership)); + if (s == NULL) + return -ENOMEM; + + s->path = strdup(path); + if (!s->path) { + free(s); + return -ENOMEM; + } + + s->device = device; + s->rank = rank; + + spa_list_init(&s->others); + + /* Join with other set members, if any */ + set = device_set_find(monitor, path); + if (set) + spa_list_append(&set->others, &s->others); + + spa_list_append(&device->set_membership_list, &s->link); + + spa_log_debug(monitor->log, "device %p: add %s to device set %s", device, + device->path, path); + + return 1; +} + +static bool device_remove_device_set(struct spa_bt_device *device, const char *path) +{ + struct spa_bt_monitor *monitor = device->monitor; + struct spa_bt_set_membership *s; + + spa_list_for_each(s, &device->set_membership_list, link) { + if (spa_streq(s->path, path)) { + spa_log_debug(monitor->log, + "device %p: remove %s from device set %s", device, + device->path, path); + spa_list_remove(&s->link); + spa_list_remove(&s->others); + free(s->path); + free(s); + return true; + } + } + + return false; +} + int spa_bt_format_vendor_product_id(uint16_t source_id, uint16_t vendor_id, uint16_t product_id, char *vendor_str, int vendor_str_size, char *product_str, int product_str_size) { @@ -1668,6 +1758,7 @@ int spa_bt_device_check_profiles(struct spa_bt_device *device, bool force) { struct spa_bt_monitor *monitor = device->monitor; + struct spa_bt_set_membership *s, *set; uint32_t connected_profiles = device->connected_profiles; uint32_t connectable_profiles = device->adapter ? adapter_connectable_profiles(device->adapter) : 0; @@ -1677,6 +1768,7 @@ SPA_BT_PROFILE_HEADSET_AUDIO_GATEWAY, }; bool direction_connected = false; + bool set_connected = true; bool all_connected; size_t i; @@ -1693,14 +1785,19 @@ all_connected = (device->profiles & connected_profiles) == device->profiles; - spa_log_debug(monitor->log, "device %p: profiles %08x %08x connectable:%08x added:%d all:%d dir:%d", + spa_list_for_each(set, &device->set_membership_list, link) + spa_bt_for_each_set_member(s, set) + if ((s->device->connected_profiles & s->device->profiles) != s->device->profiles) + set_connected = false; + + spa_log_debug(monitor->log, "device %p: profiles %08x %08x connectable:%08x added:%d all:%d dir:%d set:%d", device, device->profiles, connected_profiles, connectable_profiles, - device->added, all_connected, direction_connected); + device->added, all_connected, direction_connected, set_connected); if (connected_profiles == 0 && spa_list_is_empty(&device->codec_switch_list)) { device_stop_timer(device); device_connected(monitor, device, BT_DEVICE_DISCONNECTED); - } else if (force || direction_connected || all_connected) { + } else if (force || ((direction_connected || all_connected) && set_connected)) { device_stop_timer(device); device_connected(monitor, device, BT_DEVICE_CONNECTED); } else { @@ -1734,10 +1831,14 @@ } } +static void device_update_set_status(struct spa_bt_device *device, bool force, const char *path); + int spa_bt_device_connect_profile(struct spa_bt_device *device, enum spa_bt_profile profile) { uint32_t prev_connected = device->connected_profiles; device->connected_profiles |= profile; + if ((prev_connected ^ device->connected_profiles) & SPA_BT_PROFILE_BAP_DUPLEX) + device_update_set_status(device, true, NULL); spa_bt_device_check_profiles(device, false); if (device->connected_profiles != prev_connected) spa_bt_device_emit_profiles_changed(device, device->profiles, prev_connected); @@ -1761,6 +1862,214 @@ spa_log_debug(monitor->log, "hw-volume-profiles:%08x", (int)device->hw_volume_profiles); } +static bool device_set_update_leader(struct spa_bt_set_membership *set) +{ + struct spa_bt_set_membership *s, *leader; + int min_rank = INT_MAX; + int leader_rank = INT_MAX; + + leader = NULL; + + spa_bt_for_each_set_member(s, set) { + if (!(s->device->connected_profiles & SPA_BT_PROFILE_BAP_DUPLEX))
View file
pipewire-0.3.68.tar.gz/spa/plugins/bluez5/bluez5-device.c -> pipewire-0.3.69.tar.gz/spa/plugins/bluez5/bluez5-device.c
Changed
@@ -42,6 +42,8 @@ #define DEVICE_ID_SOURCE 0 #define DEVICE_ID_SINK 1 +#define DEVICE_ID_SOURCE_SET 2 +#define DEVICE_ID_SINK_SET 3 #define DYNAMIC_NODE_ID_FLAG 0x1000 static struct spa_i18n *_i18n; @@ -98,6 +100,22 @@ bool a2dp_duplex; }; +struct device_set_member { + struct impl *impl; + struct spa_bt_transport *transport; + struct spa_hook listener; +}; + +struct device_set { + struct impl *impl; + char *path; + bool leader; + uint32_t sinks; + uint32_t sources; + struct device_set_member sinkSPA_AUDIO_MAX_CHANNELS; + struct device_set_member sourceSPA_AUDIO_MAX_CHANNELS; +}; + struct impl { struct spa_handle handle; struct spa_device device; @@ -126,6 +144,8 @@ unsigned int save_profile:1; uint32_t prev_bt_connected_profiles; + struct device_set device_set; + const struct media_codec **supported_codecs; size_t supported_codec_count; @@ -138,7 +158,7 @@ struct spa_dict_item setting_itemsMAX_SETTINGS; struct spa_dict setting_dict; - struct node nodes2; + struct node nodes4; }; static void init_node(struct impl *this, struct node *node, uint32_t id) @@ -359,7 +379,7 @@ struct spa_bt_transport_volume *t_volume; float prev_hw_volume; - if (!node->transport || !spa_bt_transport_volume_enabled(node->transport)) + if (!node->active || !node->transport || !spa_bt_transport_volume_enabled(node->transport)) return false; /* PW is the controller for remote device. */ @@ -463,14 +483,146 @@ info.info.raw.channels * sizeof(uint32_t)); } +static const char *get_channel_name(uint32_t channel) +{ + int i; + for (i = 0; spa_type_audio_channeli.name; i++) { + if (spa_type_audio_channeli.type == channel) + return spa_debug_type_short_name(spa_type_audio_channeli.name); + } + return NULL; +} + +static int channel_position_cmp(const void *pa, const void *pb) +{ + uint32_t a = *(uint32_t *)pa, b = *(uint32_t *)pb; + return (int)a - (int)b; +} + +static void emit_device_set_node(struct impl *this, uint32_t id) +{ + struct spa_bt_device *device = this->bt_dev; + struct node *node = &this->nodesid; + struct spa_device_object_info info; + struct spa_dict_item items7; + char str_id32, members_json8192, channels_json512; + struct device_set_member *members; + uint32_t n_members; + uint32_t n_items = 0; + struct spa_strbuf json; + unsigned int i; + + itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_API_BLUEZ5_ADDRESS, device->address); + itemsn_items++ = SPA_DICT_ITEM_INIT("api.bluez5.set", this->device_set.path); + itemsn_items++ = SPA_DICT_ITEM_INIT("api.bluez5.set.leader", "true"); + snprintf(str_id, sizeof(str_id), "%d", id); + itemsn_items++ = SPA_DICT_ITEM_INIT("card.profile.device", str_id); + + if (id == DEVICE_ID_SOURCE_SET) { + itemsn_items++ = SPA_DICT_ITEM_INIT("media.class", "Audio/Source"); + members = this->device_set.source; + n_members = this->device_set.sources; + } else if (id == DEVICE_ID_SINK_SET) { + itemsn_items++ = SPA_DICT_ITEM_INIT("media.class", "Audio/Sink"); + members = this->device_set.sink; + n_members = this->device_set.sinks; + } else { + spa_assert_not_reached(); + } + + node->impl = this; + node->active = true; + node->transport = NULL; + node->a2dp_duplex = false; + node->offload_acquired = false; + node->mute = false; + node->save = false; + node->latency_offset = 0; + + /* Form channel map from members */ + node->n_channels = 0; + for (i = 0; i < n_members; ++i) { + struct spa_bt_transport *t = membersi.transport; + unsigned int j; + + for (j = 0; j < t->n_channels; ++j) { + unsigned int k; + + if (!get_channel_name(t->channelsj)) + continue; + + for (k = 0; k < node->n_channels; ++k) { + if (node->channelsk == t->channelsj) + break; + } + if (k == node->n_channels && node->n_channels < SPA_AUDIO_MAX_CHANNELS) + node->channelsnode->n_channels++ = t->channelsj; + } + } + + qsort(node->channels, node->n_channels, sizeof(uint32_t), channel_position_cmp); + + for (i = 0; i < node->n_channels; ++i) { + /* Session manager will override this, so put in some safe number */ + node->volumesi = node->soft_volumesi = 0.064; + } + + /* Produce member info json */ + spa_strbuf_init(&json, members_json, sizeof(members_json)); + spa_strbuf_append(&json, ""); + for (i = 0; i < n_members; ++i) { + struct spa_bt_transport *t = membersi.transport; + char object_path512; + unsigned int j; + int member_id = (id == DEVICE_ID_SINK_SET) ? DEVICE_ID_SINK : DEVICE_ID_SOURCE; + + if (i > 0) + spa_strbuf_append(&json, ","); + spa_scnprintf(object_path, sizeof(object_path), "%s/%s-%d", + this->device_set.path, t->device->address, member_id); + spa_strbuf_append(&json, "{\"object.path\":\"%s\",\"channels\":", object_path); + for (j = 0; j < t->n_channels; ++j) { + if (j > 0) + spa_strbuf_append(&json, ","); + spa_strbuf_append(&json, "\"%s\"", get_channel_name(t->channelsj)); + } + spa_strbuf_append(&json, "}"); + } + spa_strbuf_append(&json, ""); + json.bufferSPA_MIN(json.pos, json.maxsize-1) = 0; + itemsn_items++ = SPA_DICT_ITEM_INIT("api.bluez5.set.members", members_json); + + spa_strbuf_init(&json, channels_json, sizeof(channels_json)); + spa_strbuf_append(&json, ""); + for (i = 0; i < node->n_channels; ++i) { + if (i > 0) + spa_strbuf_append(&json, ","); + spa_strbuf_append(&json, "\"%s\"", get_channel_name(node->channelsi)); + } + spa_strbuf_append(&json, ""); + json.bufferSPA_MIN(json.pos, json.maxsize-1) = 0; + itemsn_items++ = SPA_DICT_ITEM_INIT("api.bluez5.set.channels", channels_json); + + /* Emit */ + info = SPA_DEVICE_OBJECT_INFO_INIT(); + info.type = SPA_TYPE_INTERFACE_Node; + info.factory_name = (id == DEVICE_ID_SOURCE_SET) ? "source" : "sink"; + info.change_mask = SPA_DEVICE_OBJECT_CHANGE_MASK_PROPS; + info.props = &SPA_DICT_INIT(items, n_items); + + spa_device_emit_object_info(&this->hooks, id, &info); + + emit_node_props(this, &this->nodesid, true); +} + static void emit_node(struct impl *this, struct spa_bt_transport *t, uint32_t id, const char *factory_name, bool a2dp_duplex) { struct spa_bt_device *device = this->bt_dev; struct spa_device_object_info info;
View file
pipewire-0.3.68.tar.gz/spa/plugins/bluez5/defs.h -> pipewire-0.3.69.tar.gz/spa/plugins/bluez5/defs.h
Changed
@@ -27,6 +27,7 @@ #define BLUEZ_PROFILE_INTERFACE BLUEZ_SERVICE ".Profile1" #define BLUEZ_ADAPTER_INTERFACE BLUEZ_SERVICE ".Adapter1" #define BLUEZ_DEVICE_INTERFACE BLUEZ_SERVICE ".Device1" +#define BLUEZ_DEVICE_SET_INTERFACE BLUEZ_SERVICE ".DeviceSet1" #define BLUEZ_MEDIA_INTERFACE BLUEZ_SERVICE ".Media1" #define BLUEZ_MEDIA_ENDPOINT_INTERFACE BLUEZ_SERVICE ".MediaEndpoint1" #define BLUEZ_MEDIA_TRANSPORT_INTERFACE BLUEZ_SERVICE ".MediaTransport1" @@ -440,12 +441,27 @@ /** Profile configuration changed */ void (*profiles_changed) (void *data, uint32_t prev_profiles, uint32_t prev_connected); + /** Device set configuration changed */ + void (*device_set_changed) (void *data); + /** Device freed */ void (*destroy) (void *data); }; struct media_codec; +struct spa_bt_set_membership { + struct spa_list link; + struct spa_list others; + struct spa_bt_device *device; + char *path; + uint8_t rank; + bool leader; +}; + +#define spa_bt_for_each_set_member(s, set) \ + for ((s) = (set); (s); (s) = spa_list_next((s), others), (s) = (s) != (set) ? (s) : NULL) + struct spa_bt_device { struct spa_list link; struct spa_bt_monitor *monitor; @@ -477,6 +493,7 @@ struct spa_list remote_endpoint_list; struct spa_list transport_list; struct spa_list codec_switch_list; + struct spa_list set_membership_list; uint8_t battery; int has_battery; @@ -518,6 +535,7 @@ #define spa_bt_device_emit_connected(d,...) spa_bt_device_emit(d, connected, 0, __VA_ARGS__) #define spa_bt_device_emit_codec_switched(d,...) spa_bt_device_emit(d, codec_switched, 0, __VA_ARGS__) #define spa_bt_device_emit_profiles_changed(d,...) spa_bt_device_emit(d, profiles_changed, 0, __VA_ARGS__) +#define spa_bt_device_emit_device_set_changed(d) spa_bt_device_emit(d, device_set_changed, 0) #define spa_bt_device_emit_destroy(d) spa_bt_device_emit(d, destroy, 0) #define spa_bt_device_add_listener(d,listener,events,data) \ spa_hook_list_append(&(d)->listener_list, listener, events, data) @@ -612,6 +630,8 @@ unsigned int latency_us; uint8_t bap_cig; uint8_t bap_cis; + uint32_t bap_location; + uint32_t bap_interval; struct spa_bt_iso_io *iso_io; struct spa_bt_sco_io *sco_io;
View file
pipewire-0.3.68.tar.gz/spa/plugins/bluez5/iso-io.c -> pipewire-0.3.69.tar.gz/spa/plugins/bluez5/iso-io.c
Changed
@@ -16,8 +16,6 @@ #include <spa/utils/result.h> #include <spa/node/io.h> -#include <bluetooth/bluetooth.h> - #include "config.h" #include "iso-io.h" @@ -25,7 +23,7 @@ #undef SPA_LOG_TOPIC_DEFAULT #define SPA_LOG_TOPIC_DEFAULT &log_topic -#define IDLE_TIME (100 * SPA_NSEC_PER_MSEC) +#define IDLE_TIME (200 * SPA_NSEC_PER_MSEC) struct group { struct spa_log *log; @@ -159,9 +157,8 @@ if (!stream->sink) continue; - if (stream->idle) - continue; - if (group->paused) { + if (stream->idle || group->paused) { + stream->this.resync = true; stream->this.size = 0; continue; } @@ -195,19 +192,12 @@ set_timeout(group, group->next); } -static struct group *group_create(int fd, struct spa_log *log, struct spa_loop *data_loop, - struct spa_system *data_system) +static struct group *group_create(uint8_t cig, uint32_t interval, + struct spa_log *log, struct spa_loop *data_loop, struct spa_system *data_system) { -#if defined(HAVE_BLUETOOTH_BAP) && defined(BT_ISO_QOS) struct group *group; - struct bt_iso_qos qos; - socklen_t len; - - len = sizeof(qos); - if (getsockopt(fd, SOL_BLUETOOTH, BT_ISO_QOS, &qos, &len) < 0) - return NULL; - if (qos.out.interval <= 5000) { + if (interval <= 5000) { errno = EINVAL; return NULL; } @@ -218,11 +208,11 @@ spa_log_topic_init(log, &log_topic); - group->cig = qos.cig; + group->cig = cig; group->log = log; group->data_loop = data_loop; group->data_system = data_system; - group->duration = qos.out.interval * SPA_NSEC_PER_USEC; + group->duration = interval * SPA_NSEC_PER_USEC; spa_list_init(&group->streams); @@ -243,10 +233,6 @@ spa_loop_add_source(group->data_loop, &group->source); return group; -#else - errno = EOPNOTSUPP; - return NULL; -#endif } static int do_remove_source(struct spa_loop *loop, bool async, uint32_t seq, @@ -286,6 +272,7 @@ stream->fd = fd; stream->sink = sink; stream->group = group; + stream->idle = true; stream->this.duration = group->duration; stream_link(group, stream); @@ -293,13 +280,13 @@ return stream; } -struct spa_bt_iso_io *spa_bt_iso_io_create(int fd, bool sink, struct spa_log *log, - struct spa_loop *data_loop, struct spa_system *data_system) +struct spa_bt_iso_io *spa_bt_iso_io_create(int fd, bool sink, uint8_t cig, uint32_t interval, + struct spa_log *log, struct spa_loop *data_loop, struct spa_system *data_system) { struct stream *stream; struct group *group; - group = group_create(fd, log, data_loop, data_system); + group = group_create(cig, interval, log, data_loop, data_system); if (group == NULL) return NULL; @@ -366,12 +353,11 @@ else if (enabled && !was_enabled) set_timers(stream->group); + stream->idle = true; + stream->this.resync = true; + if (pull == NULL) { stream->this.size = 0; return; } - - /* Pull data now for the next interval */ - stream->this.now = stream->group->next; - stream->pull(&stream->this); }
View file
pipewire-0.3.68.tar.gz/spa/plugins/bluez5/iso-io.h -> pipewire-0.3.69.tar.gz/spa/plugins/bluez5/iso-io.h
Changed
@@ -18,20 +18,22 @@ */ struct spa_bt_iso_io { - uint64_t now; - uint64_t duration; + uint64_t now; /**< Reference time position of next packet (read-only) */ + uint64_t duration; /**< ISO interval duration in ns (read-only) */ + bool resync; /**< Resync position for next packet; (pull callback sets to + * false when done) */ - uint32_t timestamp; - uint8_t buf4096; - size_t size; + uint32_t timestamp; /**< Packet timestamp (set by pull callback) */ + uint8_t buf4096; /**< Packet data (set by pull callback) */ + size_t size; /**< Packet size (set by pull callback) */ void *user_data; }; typedef void (*spa_bt_iso_io_pull_t)(struct spa_bt_iso_io *io); -struct spa_bt_iso_io *spa_bt_iso_io_create(int fd, bool sink, struct spa_log *log, - struct spa_loop *data_loop, struct spa_system *data_system); +struct spa_bt_iso_io *spa_bt_iso_io_create(int fd, bool sink, uint8_t cig, uint32_t interval, + struct spa_log *log, struct spa_loop *data_loop, struct spa_system *data_system); struct spa_bt_iso_io *spa_bt_iso_io_attach(struct spa_bt_iso_io *io, int fd, bool sink); void spa_bt_iso_io_destroy(struct spa_bt_iso_io *io); void spa_bt_iso_io_set_cb(struct spa_bt_iso_io *io, spa_bt_iso_io_pull_t pull, void *user_data);
View file
pipewire-0.3.68.tar.gz/spa/plugins/bluez5/media-sink.c -> pipewire-0.3.69.tar.gz/spa/plugins/bluez5/media-sink.c
Changed
@@ -58,6 +58,10 @@ #define BUFFER_SIZE (8192*8) #define RATE_CTL_DIFF_MAX 0.005 +/* Wait for two cycles before trying to sync ISO. On start/driver reassign, + * first cycle may have strange number of samples. */ +#define RESYNC_CYCLES 2 + struct buffer { uint32_t id; #define BUFFER_FLAG_OUT (1<<0) @@ -129,8 +133,10 @@ unsigned int following:1; unsigned int is_output:1; unsigned int flush_pending:1; + unsigned int iso_pending:1; unsigned int is_duplex:1; + unsigned int is_internal:1; struct spa_source source; int timerfd; @@ -159,8 +165,7 @@ int need_flush; bool fragment; - bool resync; - bool have_iso_packet; + uint32_t resync; uint32_t block_size; uint8_t bufferBUFFER_SIZE; uint32_t buffer_used; @@ -307,7 +312,7 @@ bool following; if (this->position != info->position || this->clock != info->clock) - this->resync = true; + this->resync = RESYNC_CYCLES; this->position = info->position; this->clock = info->clock; @@ -460,6 +465,7 @@ { struct port *port = &this->port; uint64_t t, duration_ns; + bool resampling; if (!this->process_rate || !this->process_duration) { if (this->position) { @@ -481,9 +487,12 @@ / port->current_format.info.raw.rate); /* Account for resampling delay */ - if (port->rate_match && this->clock && SPA_FLAG_IS_SET(port->rate_match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE)) + resampling = (port->current_format.info.raw.rate != this->process_rate) || this->following; + if (port->rate_match && this->clock && resampling) { t -= (uint64_t)port->rate_match->delay * SPA_NSEC_PER_SEC / this->clock->rate.denom; + t += SPA_NSEC_PER_SEC / port->current_format.info.raw.rate; + } return t; } @@ -715,6 +724,9 @@ if (!this->flush_timer_source.loop && !this->transport->iso_io) return -EIO; + if (this->transport->iso_io && !this->iso_pending) + return 0; + total_frames = 0; again: written = 0; @@ -787,7 +799,7 @@ if (this->transport->iso_io) { struct spa_bt_iso_io *iso_io = this->transport->iso_io; - if (this->need_flush && !this->have_iso_packet) { + if (this->need_flush) { size_t avail = SPA_MIN(this->buffer_used, sizeof(iso_io->buf)); spa_log_trace(this->log, "%p: ISO put fd:%d size:%u sn:%u ts:%u now:%"PRIu64, @@ -798,7 +810,7 @@ memcpy(iso_io->buf, this->buffer, avail); iso_io->size = avail; iso_io->timestamp = this->timestamp; - this->have_iso_packet = true; + this->iso_pending = false; reset_buffer(this); } @@ -953,9 +965,7 @@ struct port *port = &this->port; const double period = 0.1 * SPA_NSEC_PER_SEC; uint64_t duration_ns; - double value, target, err; - - this->have_iso_packet = false; + double value, target, err, max_err; if (this->resync || !this->position) { spa_bt_rate_control_init(&port->ratectl, 0); @@ -978,19 +988,28 @@ value = (int64_t)iso_io->now - (int64_t)get_reference_time(this, &duration_ns); target = iso_io->duration * 3/2; err = value - target; + max_err = iso_io->duration; - if (err > iso_io->duration) { - uint32_t req = err * port->current_format.info.raw.rate / SPA_NSEC_PER_SEC; - - spa_log_debug(this->log, "%p: ISO sync reset frames:%u", this, (unsigned int)req); - - spa_bt_rate_control_init(&port->ratectl, 0); - drop_frames(this, req); - } else if (-err > iso_io->duration) { - uint32_t req = -err * port->current_format.info.raw.rate / SPA_NSEC_PER_SEC; + if (err > max_err || (iso_io->resync && err > 0)) { + unsigned int req = err * port->current_format.info.raw.rate / SPA_NSEC_PER_SEC; - spa_log_debug(this->log, "%p: ISO sync skip flush frames:%u", this, (unsigned int)req); - return; + if (req > 0) { + spa_bt_rate_control_init(&port->ratectl, 0); + drop_frames(this, req); + spa_log_debug(this->log, "%p: ISO sync skip frames:%u resync:%d", + this, req, iso_io->resync); + } + } else if (-err > max_err || (iso_io->resync && -err > 0)) { + unsigned int req = -err * port->current_format.info.raw.rate / SPA_NSEC_PER_SEC; + static const uint8_t empty8192 = {0}; + + if (req > 0) { + spa_bt_rate_control_init(&port->ratectl, 0); + req = SPA_MIN(req, sizeof(empty) / port->frame_size); + add_data(this, empty, req * port->frame_size); + spa_log_debug(this->log, "%p: ISO sync pad frames:%u resync:%d", + this, req, iso_io->resync); + } } else { spa_bt_rate_control_update(&port->ratectl, err, 0, iso_io->duration, period, RATE_CTL_DIFF_MAX); @@ -1002,7 +1021,10 @@ port->ratectl.corr); } + iso_io->resync = false; + done: + this->iso_pending = true; flush_data(this, this->current_time); } @@ -1215,9 +1237,9 @@ this->flush_source.rmask = 0; spa_loop_add_source(this->data_loop, &this->flush_source); - this->resync = true; - + this->resync = RESYNC_CYCLES; this->flush_pending = false; + this->iso_pending = false; this->transport_started = true; @@ -1375,7 +1397,8 @@ { struct spa_dict_item node_info_items = { { SPA_KEY_DEVICE_API, "bluez5" }, - { SPA_KEY_MEDIA_CLASS, this->is_output ? "Audio/Sink" : "Stream/Input/Audio" }, + { SPA_KEY_MEDIA_CLASS, this->is_internal ? "Audio/Sink/Internal" : + this->is_output ? "Audio/Sink" : "Stream/Input/Audio" }, { "media.name", ((this->transport && this->transport->device->name) ? this->transport->device->name : this->codec->bap ? "BAP" : "A2DP" ) }, { SPA_KEY_NODE_DRIVER, this->is_output ? "true" : "false" }, @@ -1796,6 +1819,8 @@ if (io->status == SPA_STATUS_HAVE_DATA && io->buffer_id < port->n_buffers) { struct buffer *b = &port->buffersio->buffer_id; + struct spa_data *d = b->buf->datas; + unsigned int frames; if (!SPA_FLAG_IS_SET(b->flags, BUFFER_FLAG_OUT)) { spa_log_warn(this->log, "%p: buffer %u in use", this, io->buffer_id); @@ -1803,7 +1828,8 @@ return -EINVAL; } - spa_log_trace(this->log, "%p: queue buffer %u", this, io->buffer_id); + frames = d ? d0.chunk->size / port->frame_size : 0; + spa_log_trace(this->log, "%p: queue buffer %u frames:%u", this, io->buffer_id, frames); spa_list_append(&port->ready, &b->link); SPA_FLAG_CLEAR(b->flags, BUFFER_FLAG_OUT); @@ -1831,7 +1857,8 @@ } this->process_time = this->current_time; - this->resync = false; + if (this->resync)
View file
pipewire-0.3.68.tar.gz/spa/plugins/bluez5/media-source.c -> pipewire-0.3.69.tar.gz/spa/plugins/bluez5/media-source.c
Changed
@@ -122,6 +122,7 @@ unsigned int is_input:1; unsigned int is_duplex:1; + unsigned int is_internal:1; unsigned int use_duplex_source:1; unsigned int node_latency; @@ -901,7 +902,8 @@ struct spa_dict_item node_info_items = { { SPA_KEY_DEVICE_API, "bluez5" }, - { SPA_KEY_MEDIA_CLASS, this->is_input ? "Audio/Source" : "Stream/Output/Audio" }, + { SPA_KEY_MEDIA_CLASS, this->is_internal ? "Audio/Source/Internal" : + this->is_input ? "Audio/Source" : "Stream/Output/Audio" }, { SPA_KEY_NODE_LATENCY, this->is_input ? "" : latency }, { "media.name", ((this->transport && this->transport->device->name) ? this->transport->device->name : this->codec->bap ? "BAP" : "A2DP") }, @@ -1738,6 +1740,8 @@ this->is_input = spa_streq(str, "input"); if ((str = spa_dict_lookup(info, "api.bluez5.a2dp-duplex")) != NULL) this->is_duplex = spa_atob(str); + if ((str = spa_dict_lookup(info, "api.bluez5.internal")) != NULL) + this->is_internal = spa_atob(str); } if (this->transport == NULL) {
View file
pipewire-0.3.68.tar.gz/src/gst/gstpipewireclock.c -> pipewire-0.3.69.tar.gz/src/gst/gstpipewireclock.c
Changed
@@ -91,6 +91,7 @@ void gst_pipewire_clock_reset (GstPipeWireClock * clock, GstClockTime time) { +#if 0 GstClockTimeDiff time_offset; if (clock->last_time >= time) @@ -104,4 +105,5 @@ "reset clock to %" GST_TIME_FORMAT ", last %" GST_TIME_FORMAT ", offset %" GST_STIME_FORMAT, GST_TIME_ARGS (time), GST_TIME_ARGS (clock->last_time), GST_STIME_ARGS (time_offset)); +#endif }
View file
pipewire-0.3.68.tar.gz/src/modules/module-echo-cancel.c -> pipewire-0.3.69.tar.gz/src/modules/module-echo-cancel.c
Changed
@@ -183,7 +183,9 @@ struct spa_hook core_proxy_listener; struct spa_hook core_listener; - struct spa_audio_info_raw info; + struct spa_audio_info_raw rec_info; + struct spa_audio_info_raw out_info; + struct spa_audio_info_raw play_info; struct pw_properties *capture_props; struct pw_stream *capture; @@ -247,10 +249,13 @@ if (impl->wav_file == NULL) { struct wav_file_info info; - info.info.info.raw = impl->info; - info.info.info.raw.channels *= 3; + spa_zero(info); info.info.media_type = SPA_MEDIA_TYPE_audio; info.info.media_subtype = SPA_MEDIA_SUBTYPE_raw; + info.info.info.raw.format = SPA_AUDIO_FORMAT_F32P; + info.info.info.raw.rate = impl->rec_info.rate; + info.info.info.raw.channels = impl->play_info.channels + + impl->rec_info.channels + impl->out_info.channels; impl->wav_file = wav_file_open(impl->wav_path, "w", &info); @@ -259,14 +264,17 @@ impl->wav_path); } if (impl->wav_file) { - uint32_t i, c = impl->info.channels; - const float *datac * 3; + uint32_t i, n, c = impl->play_info.channels + + impl->rec_info.channels + impl->out_info.channels; + const float *datac; + + for (i = n = 0; i < impl->play_info.channels; i++) + datan++ = playi; + for (i = 0; i < impl->rec_info.channels; i++) + datan++ = reci; + for (i = 0; i < impl->out_info.channels; i++) + datan++ = outi; - for (i = 0; i < c; i++) { - datai = playi; - datai + c = reci; - datai + 2*c = outi; - } wav_file_write(impl->wav_file, (void*)data, n_samples); } else { spa_zero(impl->wav_path); @@ -281,18 +289,17 @@ { struct pw_buffer *cout; struct pw_buffer *pout = NULL; - float rec_bufimpl->info.channelsimpl->aec_blocksize / sizeof(float); - float play_bufimpl->info.channelsimpl->aec_blocksize / sizeof(float); - float play_delayed_bufimpl->info.channelsimpl->aec_blocksize / sizeof(float); - float out_bufimpl->info.channelsimpl->aec_blocksize / sizeof(float); - const float *recimpl->info.channels; - const float *playimpl->info.channels; - const float *play_delayedimpl->info.channels; - float *outimpl->info.channels; + float rec_bufimpl->rec_info.channelsimpl->aec_blocksize / sizeof(float); + float play_bufimpl->play_info.channelsimpl->aec_blocksize / sizeof(float); + float play_delayed_bufimpl->play_info.channelsimpl->aec_blocksize / sizeof(float); + float out_bufimpl->out_info.channelsimpl->aec_blocksize / sizeof(float); + const float *recimpl->rec_info.channels; + const float *playimpl->play_info.channels; + const float *play_delayedimpl->play_info.channels; + float *outimpl->out_info.channels; struct spa_data *dd; uint32_t i, size; uint32_t rindex, pindex, oindex, pdindex, avail; - int32_t stride = 0; if (impl->playback != NULL && (pout = pw_stream_dequeue_buffer(impl->playback)) == NULL) { pw_log_debug("out of playback buffers: %m"); @@ -302,32 +309,37 @@ size = impl->aec_blocksize; /* First read a block from the playback and capture ring buffers */ - spa_ringbuffer_get_read_index(&impl->rec_ring, &rindex); - spa_ringbuffer_get_read_index(&impl->play_ring, &pindex); - spa_ringbuffer_get_read_index(&impl->play_delayed_ring, &pdindex); - for (i = 0; i < impl->info.channels; i++) { + for (i = 0; i < impl->rec_info.channels; i++) { /* captured samples, with echo from sink */ reci = &rec_bufi0; - /* echo from sink */ - playi = &play_bufi0; - /* echo from sink delayed */ - play_delayedi = &play_delayed_bufi0; - /* filtered samples, without echo from sink */ - outi = &out_bufi0; - stride = 0; spa_ringbuffer_read_data(&impl->rec_ring, impl->rec_bufferi, impl->rec_ringsize, rindex % impl->rec_ringsize, (void*)reci, size); - stride = 0; + } + spa_ringbuffer_read_update(&impl->rec_ring, rindex + size); + + for (i = 0; i < impl->out_info.channels; i++) { + /* filtered samples, without echo from sink */ + outi = &out_bufi0; + } + + spa_ringbuffer_get_read_index(&impl->play_ring, &pindex); + spa_ringbuffer_get_read_index(&impl->play_delayed_ring, &pdindex); + + for (i = 0; i < impl->play_info.channels; i++) { + /* echo from sink */ + playi = &play_bufi0; + /* echo from sink delayed */ + play_delayedi = &play_delayed_bufi0; + spa_ringbuffer_read_data(&impl->play_ring, impl->play_bufferi, impl->play_ringsize, pindex % impl->play_ringsize, (void *)playi, size); - stride = 0; spa_ringbuffer_read_data(&impl->play_delayed_ring, impl->play_bufferi, impl->play_ringsize, pdindex % impl->play_ringsize, (void *)play_delayedi, size); @@ -339,11 +351,9 @@ dd->chunk->offset = 0; dd->chunk->size = size; - dd->chunk->stride = stride; + dd->chunk->stride = sizeof(float); } } - - spa_ringbuffer_read_update(&impl->rec_ring, rindex + size); spa_ringbuffer_read_update(&impl->play_ring, pindex + size); spa_ringbuffer_read_update(&impl->play_delayed_ring, pdindex + size); @@ -357,19 +367,20 @@ /* don't run the canceller until play_buffer has been filled, * copy silence to output in the meantime */ silence_size = SPA_MIN(size, delay_left * sizeof(float)); - for (i = 0; i < impl->info.channels; i++) + for (i = 0; i < impl->out_info.channels; i++) memset(outi, 0, silence_size); impl->current_delay += silence_size / sizeof(float); pw_log_debug("current_delay %d", impl->current_delay); if (silence_size != size) { - const float *pdimpl->info.channels; - float *oimpl->info.channels; + const float *pdimpl->play_info.channels; + float *oimpl->out_info.channels; - for (i = 0; i < impl->info.channels; i++) { + for (i = 0; i < impl->play_info.channels; i++) pdi = play_delayedi + delay_left; + for (i = 0; i < impl->out_info.channels; i++) oi = outi + delay_left; - } + aec_run(impl, rec, pd, o, size / sizeof(float) - delay_left); } } else { @@ -393,7 +404,7 @@ avail += drop; } - for (i = 0; i < impl->info.channels; i++) { + for (i = 0; i < impl->out_info.channels; i++) { /* captured samples, with echo from sink */ spa_ringbuffer_write_data(&impl->out_ring, impl->out_bufferi, impl->out_ringsize, oindex % impl->out_ringsize, @@ -412,14 +423,14 @@ break; } - for (i = 0; i < impl->info.channels; i++) { + for (i = 0; i < impl->out_info.channels; i++) { dd = &cout->buffer->datasi; spa_ringbuffer_read_data(&impl->out_ring, impl->out_bufferi, impl->out_ringsize, oindex % impl->out_ringsize, (void *)dd->data, size); dd->chunk->offset = 0; dd->chunk->size = size; - dd->chunk->stride = 0; + dd->chunk->stride = sizeof(float); } pw_stream_queue_buffer(impl->source, cout); @@ -482,7 +493,7 @@ pw_log_debug("Setting AEC block size to %u", impl->aec_blocksize); } - for (i = 0; i < impl->info.channels; i++) {
View file
pipewire-0.3.68.tar.gz/src/modules/module-filter-chain.c -> pipewire-0.3.69.tar.gz/src/modules/module-filter-chain.c
Changed
@@ -162,7 +162,11 @@ * * All biquad filters have an input port "In" and an output port "Out". They have * a "Freq", "Q" and "Gain" control. Their meaning depends on the particular biquad that - * is used. The following labels can be used: + * is used. The biquads also have "b0", "b1", "b2", "a0", "a1" and "a2" ports that + * are read-only except for the bq_raw biquad, which can configure default values + * depending on the graph rate and change those at runtime. + * + * The following labels can be used: * * - `bq_lowpass` a lowpass filter. * - `bq_highpass` a highpass filter. @@ -172,6 +176,30 @@ * - `bq_peaking` a peaking filter. * - `bq_notch` a notch filter. * - `bq_allpass` an allpass filter. + * - `bq_raw` a raw biquad filter. You need a config section to specify coefficients + * per sample rate. The coefficients of the sample rate closest to the + * graph rate are selected: + * + *\code{.unparsed} + * filter.graph = { + * nodes = + * { + * type = builtin + * name = ... + * label = bq_raw + * config = { + * coefficients = + * { rate = 44100, b0=.., b1=.., b2=.., a0=.., a1=.., a2=.. }, + * { rate = 48000, b0=.., b1=.., b2=.., a0=.., a1=.., a2=.. }, + * { rate = 192000, b0=.., b1=.., b2=.., a0=.., a1=.., a2=.. } + * + * } + * ... + * } + * } + * ... + * } + *\endcode * * ### Convolver * @@ -1006,6 +1034,20 @@ node->control_changed = false; } +static void update_props_param(struct impl *impl) +{ + struct graph *graph = &impl->graph; + uint8_t buffer1024; + struct spa_pod_dynamic_builder b; + const struct spa_pod *params1; + + spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096); + params0 = get_props_param(graph, &b.b); + + pw_stream_update_params(impl->capture, params, 1); + spa_pod_dynamic_builder_clean(&b); +} + static void param_props_changed(struct impl *impl, const struct spa_pod *param) { struct spa_pod_object *obj = (struct spa_pod_object *) param; @@ -1018,19 +1060,12 @@ changed += parse_params(graph, &prop->value); } if (changed > 0) { - uint8_t buffer1024; - struct spa_pod_dynamic_builder b; - const struct spa_pod *params1; struct node *node; spa_list_for_each(node, &graph->node_list, link) node_control_changed(node); - spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096); - params0 = get_props_param(graph, &b.b); - - pw_stream_update_params(impl->capture, params, 1); - spa_pod_dynamic_builder_clean(&b); + update_props_param(impl); } } @@ -1847,6 +1882,7 @@ d->control_changed(node->hndli); } } + update_props_param(impl); return 0; error: graph_cleanup(graph);
View file
pipewire-0.3.68.tar.gz/src/modules/module-filter-chain/builtin_plugin.c -> pipewire-0.3.69.tar.gz/src/modules/module-filter-chain/builtin_plugin.c
Changed
@@ -32,10 +32,13 @@ unsigned long rate; float *port64; + int type; struct biquad bq; float freq; float Q; float gain; + float b0, b1, b2; + float a0, a1, a2; }; static void *builtin_instantiate(const struct fc_descriptor * Descriptor, @@ -215,6 +218,159 @@ .cleanup = builtin_cleanup, }; +/** biquads */ +static int bq_type_from_name(const char *name) +{ + if (spa_streq(name, "bq_lowpass")) + return BQ_LOWPASS; + if (spa_streq(name, "bq_highpass")) + return BQ_HIGHPASS; + if (spa_streq(name, "bq_bandpass")) + return BQ_BANDPASS; + if (spa_streq(name, "bq_lowshelf")) + return BQ_LOWSHELF; + if (spa_streq(name, "bq_highshelf")) + return BQ_HIGHSHELF; + if (spa_streq(name, "bq_peaking")) + return BQ_PEAKING; + if (spa_streq(name, "bq_notch")) + return BQ_NOTCH; + if (spa_streq(name, "bq_allpass")) + return BQ_ALLPASS; + if (spa_streq(name, "bq_raw")) + return BQ_NONE; + return BQ_NONE; +} + +static void bq_raw_update(struct builtin *impl, float b0, float b1, float b2, + float a0, float a1, float a2) +{ + struct biquad *bq = &impl->bq; + impl->b0 = b0; + impl->b1 = b1; + impl->b2 = b2; + impl->a0 = a0; + impl->a1 = a1; + impl->a2 = a2; + if (a0 != 0.0f) + a0 = 1.0f / a0; + bq->b0 = impl->b0 * a0; + bq->b1 = impl->b1 * a0; + bq->b2 = impl->b2 * a0; + bq->a1 = impl->a1 * a0; + bq->a2 = impl->a2 * a0; + bq->x1 = bq->x2 = bq->y1 = bq->y2 = 0.0; +} + +/* + * config = { + * coefficients = + * { rate = 44100, b0=.., b1=.., b2=.., a0=.., a1=.., a2=.. }, + * { rate = 48000, b0=.., b1=.., b2=.., a0=.., a1=.., a2=.. }, + * { rate = 192000, b0=.., b1=.., b2=.., a0=.., a1=.., a2=.. } + * + * } + */ +static void *bq_instantiate(const struct fc_descriptor * Descriptor, + unsigned long SampleRate, int index, const char *config) +{ + struct builtin *impl; + struct spa_json it4; + const char *val; + char key256; + uint32_t best_rate = 0; + + impl = calloc(1, sizeof(*impl)); + if (impl == NULL) + return NULL; + + impl->rate = SampleRate; + impl->b0 = impl->a0 = 1.0f; + impl->type = bq_type_from_name(Descriptor->name); + + if (config == NULL) + goto error; + + spa_json_init(&it0, config, strlen(config)); + if (spa_json_enter_object(&it0, &it1) <= 0) + goto error; + + while (spa_json_get_string(&it1, key, sizeof(key)) > 0) { + if (spa_streq(key, "coefficients")) { + if (spa_json_enter_array(&it1, &it2) <= 0) { + pw_log_error("biquads:coefficients require an array"); + goto error; + } + while (spa_json_enter_object(&it2, &it3) > 0) { + int32_t rate = 0; + float b0 = 1.0f, b1 = 0.0f, b2 = 0.0f; + float a0 = 1.0f, a1 = 0.0f, a2 = 0.0f; + + while (spa_json_get_string(&it3, key, sizeof(key)) > 0) { + if (spa_streq(key, "rate")) { + if (spa_json_get_int(&it3, &rate) <= 0) { + pw_log_error("biquads:rate requires a number"); + goto error; + } + } + else if (spa_streq(key, "b0")) { + if (spa_json_get_float(&it3, &b0) <= 0) { + pw_log_error("biquads:b0 requires a float"); + goto error; + } + } + else if (spa_streq(key, "b1")) { + if (spa_json_get_float(&it3, &b1) <= 0) { + pw_log_error("biquads:b1 requires a float"); + goto error; + } + } + else if (spa_streq(key, "b2")) { + if (spa_json_get_float(&it3, &b2) <= 0) { + pw_log_error("biquads:b2 requires a float"); + goto error; + } + } + else if (spa_streq(key, "a0")) { + if (spa_json_get_float(&it3, &a0) <= 0) { + pw_log_error("biquads:a0 requires a float"); + goto error; + } + } + else if (spa_streq(key, "a1")) { + if (spa_json_get_float(&it3, &a1) <= 0) { + pw_log_error("biquads:a1 requires a float"); + goto error; + } + } + else if (spa_streq(key, "a2")) { + if (spa_json_get_float(&it3, &a2) <= 0) { + pw_log_error("biquads:a0 requires a float"); + goto error; + } + } + else if (spa_json_next(&it1, &val) < 0) + break; + } + if (labs((long)rate - (long)SampleRate) < + labs((long)best_rate - (long)SampleRate)) { + best_rate = rate; + bq_raw_update(impl, b0, b1, b2, a0, a1, a2); + } + } + } + else if (spa_json_next(&it1, &val) < 0) + break; + } + + return impl; +error: + free(impl); + errno = EINVAL; + return NULL; +} + +#define BQ_NUM_PORTS 11 static struct fc_port bq_ports = { { .index = 0, .name = "Out", @@ -240,176 +396,225 @@ .flags = FC_PORT_INPUT | FC_PORT_CONTROL, .def = 0.0f, .min = -120.0f, .max = 20.0f, }, + { .index = 5, + .name = "b0", + .flags = FC_PORT_INPUT | FC_PORT_CONTROL, + .def = 1.0f, .min = -10.0f, .max = 10.0f, + }, + { .index = 6, + .name = "b1", + .flags = FC_PORT_INPUT | FC_PORT_CONTROL, + .def = 0.0f, .min = -10.0f, .max = 10.0f, + }, + { .index = 7, + .name = "b2", + .flags = FC_PORT_INPUT | FC_PORT_CONTROL, + .def = 0.0f, .min = -10.0f, .max = 10.0f, + }, + { .index = 8, + .name = "a0", + .flags = FC_PORT_INPUT | FC_PORT_CONTROL, + .def = 1.0f, .min = -10.0f, .max = 10.0f, + }, + { .index = 9, + .name = "a1",
View file
pipewire-0.3.68.tar.gz/src/pipewire/context.c -> pipewire-0.3.69.tar.gz/src/pipewire/context.c
Changed
@@ -885,13 +885,16 @@ pw_impl_link_prepare(l); - if (!l->prepared || t->visited) + if (!l->prepared || (t != n && t->visited)) continue; if (!l->passive) t->runnable = true; - t->visited = true; - spa_list_append(&queue, &t->sort_link); + + if (!t->visited) { + t->visited = true; + spa_list_append(&queue, &t->sort_link); + } } } spa_list_for_each(p, &n->output_ports, link) { @@ -903,13 +906,16 @@ pw_impl_link_prepare(l); - if (!l->prepared || t->visited) + if (!l->prepared || (t != n && t->visited)) continue; if (!l->passive) t->runnable = true; - t->visited = true; - spa_list_append(&queue, &t->sort_link); + + if (!t->visited) { + t->visited = true; + spa_list_append(&queue, &t->sort_link); + } } } /* now go through all the nodes that have the same group and @@ -943,6 +949,8 @@ spa_list_consume(n, nodes, sort_link) { spa_list_remove(&n->sort_link); + driver->runnable |= n->runnable; + pw_log_debug(" follower: %p %s runnable:%u driver-runnable:%u", n, n->name, n->runnable, driver->runnable); pw_impl_node_set_driver(n, driver);
View file
pipewire-0.3.68.tar.gz/src/pipewire/thread-loop.c -> pipewire-0.3.69.tar.gz/src/pipewire/thread-loop.c
Changed
@@ -240,6 +240,7 @@ pw_thread_loop_stop(loop); + pw_loop_set_callbacks(loop->loop, NULL, NULL); spa_hook_remove(&loop->hook); spa_hook_list_clean(&loop->listener_list);
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.