Projects
Essentials
pipewire-aptx
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 57
View file
pipewire-aptx.changes
Changed
@@ -1,4 +1,9 @@ ------------------------------------------------------------------- +Thu Aug 7 08:53:42 UTC 2025 - Bjørn Lie <zaitor@opensuse.org> + +- Update to version 1.4.7 + +------------------------------------------------------------------- Tue Jul 1 16:46:10 UTC 2025 - Bjørn Lie <zaitor@opensuse.org> - Update to version 1.4.6
View file
pipewire-aptx.spec
Changed
@@ -8,7 +8,7 @@ %define minimum_version 1.4.0 Name: pipewire-aptx -Version: 1.4.6 +Version: 1.4.7 Release: 0 Summary: PipeWire Bluetooth aptX codec plugin License: MIT
View file
_service
Changed
@@ -2,6 +2,6 @@ <service name="download_url"> <param name="host">gitlab.freedesktop.org</param> <param name="protocol">https</param> - <param name="path">/pipewire/pipewire/-/archive/1.4.6/pipewire-1.4.6.tar.bz2</param> + <param name="path">/pipewire/pipewire/-/archive/1.4.7/pipewire-1.4.7.tar.bz2</param> </service> </services> \ No newline at end of file
View file
_service:download_url:pipewire-1.4.6.tar.bz2/NEWS -> _service:download_url:pipewire-1.4.7.tar.bz2/NEWS
Changed
@@ -1,3 +1,35 @@ +# PipeWire 1.4.7 (2025-07-23) + +This is a bugfix release that is API and ABI compatible with +previous 1.x releases. + +## Highlights + - Improve latency handling in echo-cancel. + - Don't leak SyncObj fds in client-node. + - Improve the adaptive resampler performance. + - Some more fixes and improvements. + + +## modules + - Set module-echo-cancel latency correctly. + - Avoid extra latency in echo-cancel by dropping samples when + one end is paused. + - Don't leak SyncObj fds in client-node. (#4807) + +## SPA + - Actually enable echo cancellation when using webrtc 2.0 + - Improve ALSA driver resampling setup and follower adaptive + resampling. + - Fix an off-by-one in the delay filter. + - Improve the adaptive resampler performance. + +## bluetooth + - Improve compatibility with some JBL flip and change models. + +## GStreamer + - Add some format validations. + + # PipeWire 1.4.6 (2025-06-27) This is a bugfix release that is API and ABI compatible with
View file
_service:download_url:pipewire-1.4.6.tar.bz2/meson.build -> _service:download_url:pipewire-1.4.7.tar.bz2/meson.build
Changed
@@ -1,5 +1,5 @@ project('pipewire', 'c' , - version : '1.4.6', + version : '1.4.7', license : 'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' , meson_version : '>= 0.61.1', default_options : 'warning_level=3',
View file
_service:download_url:pipewire-1.4.6.tar.bz2/spa/plugins/aec/aec-webrtc.cpp -> _service:download_url:pipewire-1.4.7.tar.bz2/spa/plugins/aec/aec-webrtc.cpp
Changed
@@ -119,15 +119,14 @@ #elif defined(HAVE_WEBRTC1) bool voice_detection = webrtc_get_spa_bool(args, "webrtc.voice_detection", true); bool transient_suppression = webrtc_get_spa_bool(args, "webrtc.transient_suppression", true); + bool mobile_mode = webrtc_get_spa_bool(args, "webrtc.mobile_mode", false); +#elif defined(HAVE_WEBRTC2) + bool mobile_mode = webrtc_get_spa_bool(args, "webrtc.mobile_mode", false); #endif // Note: AGC seems to mess up with Agnostic Delay Detection, especially with speech, // result in very poor performance, disable by default bool gain_control = webrtc_get_spa_bool(args, "webrtc.gain_control", false); - // FIXME: Intelligibility enhancer is not currently supported - // This filter will modify playback buffer (when calling ProcessReverseStream), but now - // playback buffer modifications are discarded. - #if defined(HAVE_WEBRTC) webrtc::Config config; config.Set<webrtc::ExtendedFilter>(new webrtc::ExtendedFilter(extended_filter)); @@ -175,6 +174,7 @@ #elif defined(HAVE_WEBRTC1) webrtc::AudioProcessing::Config config; config.echo_canceller.enabled = true; + config.echo_canceller.mobile_mode = mobile_mode; config.pipeline.multi_channel_capture = rec_info->channels > 1; config.pipeline.multi_channel_render = play_info->channels > 1; // FIXME: Example code enables both gain controllers, but that seems sus @@ -191,6 +191,8 @@ config.voice_detection.enabled = voice_detection; #elif defined(HAVE_WEBRTC2) webrtc::AudioProcessing::Config config; + config.echo_canceller.enabled = true; + config.echo_canceller.mobile_mode = mobile_mode; config.pipeline.multi_channel_capture = rec_info->channels > 1; config.pipeline.multi_channel_render = play_info->channels > 1; // FIXME: Example code enables both gain controllers, but that seems sus @@ -308,9 +310,6 @@ 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 ((res = impl->apm->ProcessReverseStream(impl->play_buffer.get(), play_config, play_config, impl->play_buffer.get())) != webrtc::AudioProcessing::kNoError) {
View file
_service:download_url:pipewire-1.4.6.tar.bz2/spa/plugins/alsa/alsa-pcm.c -> _service:download_url:pipewire-1.4.7.tar.bz2/spa/plugins/alsa/alsa-pcm.c
Changed
@@ -2368,13 +2368,13 @@ spa_log_info(state->log, "%s: format:%s access:%s-%s rate:%d channels:%d " "buffer frames %lu, period frames %lu, periods %u, frame_size %zd " - "headroom %u start-delay:%u batch:%u tsched:%u", + "headroom %u start-delay:%u batch:%u tsched:%u resample:%u", state->name, snd_pcm_format_name(state->format), state->use_mmap ? "mmap" : "rw", planar ? "planar" : "interleaved", state->rate, state->channels, state->buffer_frames, state->period_frames, periods, state->frame_size, state->headroom, state->start_delay, - state->is_batch, !state->disable_tsched); + state->is_batch, !state->disable_tsched, state->resample); /* write the parameters to device */ CHECK(snd_pcm_hw_params(hndl, params), "set_hw_params"); @@ -2900,6 +2900,13 @@ return 0; } +static bool need_resample(struct state *state) +{ + return !state->pitch_elem && + ((state->rate != 0 && state->driver_rate.denom != 0 && + (uint32_t)state->rate != state->driver_rate.denom) || state->matching); +} + static int setup_matching(struct state *state) { state->matching = state->following; @@ -2913,8 +2920,10 @@ if (spa_streq(state->position->clock.name, state->clock_name)) state->matching = false; - state->resample = !state->pitch_elem && - (((uint32_t)state->rate != state->driver_rate.denom) || state->matching); + state->resample = need_resample(state); + + check_position_config(state, false); + recalc_headroom(state); spa_log_info(state->log, "driver clock:'%s'@%d our clock:'%s'@%d matching:%d resample:%d", @@ -2972,8 +2981,7 @@ state->max_error = SPA_MAX(256.0f, (state->threshold + state->headroom) / 2.0f); state->max_resync = SPA_MIN(state->threshold + state->headroom, state->max_error); state->err_wdw = (double)state->driver_rate.denom/state->driver_duration; - state->resample = !state->pitch_elem && - (((uint32_t)state->rate != state->driver_rate.denom) || state->matching); + state->resample = need_resample(state); state->alsa_sync = true; } return 0; @@ -3376,6 +3384,10 @@ uint64_t current_time = state->position->clock.nsec; alsa_read_sync(state, current_time); } + else if (state->resample && state->rate_match) { + state->read_size = state->rate_match->size; + state->max_read = SPA_MIN(state->buffer_frames, state->read_size); + } return alsa_read_frames(state); }
View file
_service:download_url:pipewire-1.4.6.tar.bz2/spa/plugins/audioconvert/audioconvert.c -> _service:download_url:pipewire-1.4.7.tar.bz2/spa/plugins/audioconvert/audioconvert.c
Changed
@@ -1188,8 +1188,8 @@ } else if (spa_streq(k, "channelmix.lock-volumes")) this->props.lock_volumes = spa_atob(s); - else if (spa_strstartswith(k, "audioconvert.filter-graph")) { - int order = atoi(k+ strlen("audioconvert.filter-graph.")); + else if (spa_strstartswith(k, "audioconvert.filter-graph.")) { + int order = atoi(k + strlen("audioconvert.filter-graph.")); if ((res = load_filter_graph(this, s, order)) < 0) { spa_log_warn(this->log, "Can't load filter-graph %d: %s", order, spa_strerror(res));
View file
_service:download_url:pipewire-1.4.6.tar.bz2/spa/plugins/audioconvert/resample-native-impl.h -> _service:download_url:pipewire-1.4.7.tar.bz2/spa/plugins/audioconvert/resample-native-impl.h
Changed
@@ -30,10 +30,12 @@ uint32_t in_rate; uint32_t out_rate; float phase; + float pm; uint32_t inc; uint32_t frac; uint32_t filter_stride; uint32_t filter_stride_os; + uint32_t gcd; uint32_t hist; float **history; resample_func_t func; @@ -84,7 +86,7 @@ { \ struct native_data *data = r->data; \ uint32_t n_taps = data->n_taps, stride = data->filter_stride_os; \ - uint32_t index, phase, n_phases = data->out_rate; \ + uint32_t index, phase, out_rate = data->out_rate; \ uint32_t c, o, olen = *out_len, ilen = *in_len; \ uint32_t inc = data->inc, frac = data->frac, ch = r->channels; \ \ @@ -98,7 +100,7 @@ inner_product_##arch(&do, &sindex, \ filter, n_taps); \ } \ - INC(index, phase, n_phases); \ + INC(index, phase, out_rate); \ } \ *in_len = index; \ *out_len = o; \ @@ -110,16 +112,15 @@ { \ struct native_data *data = r->data; \ uint32_t index, stride = data->filter_stride; \ - uint32_t n_phases = data->n_phases, out_rate = data->out_rate; \ - uint32_t n_taps = data->n_taps; \ + uint32_t n_taps = data->n_taps, out_rate = data->out_rate; \ uint32_t c, o, olen = *out_len, ilen = *in_len; \ uint32_t inc = data->inc, frac = data->frac, ch = r->channels; \ - float phase; \ + float phase, pm = data->pm; \ \ index = ioffs; \ phase = data->phase; \ for (o = ooffs; o < olen && index + n_taps <= ilen; o++) { \ - float ph = phase * n_phases / out_rate; \ + float ph = phase * pm; \ uint32_t offset = (uint32_t)floorf(ph); \ float *filter0 = &data->filter(offset+0) * stride; \ float *filter1 = &data->filter(offset+1) * stride; \
View file
_service:download_url:pipewire-1.4.6.tar.bz2/spa/plugins/audioconvert/resample-native.c -> _service:download_url:pipewire-1.4.7.tar.bz2/spa/plugins/audioconvert/resample-native.c
Changed
@@ -137,44 +137,38 @@ static void impl_native_update_rate(struct resample *r, double rate) { struct native_data *data = r->data; - uint32_t in_rate, out_rate, gcd, old_out_rate; - float phase; + uint32_t in_rate, out_rate; if (SPA_LIKELY(data->rate == rate)) return; - old_out_rate = data->out_rate; - in_rate = (uint32_t)(r->i_rate / rate); - out_rate = r->o_rate; - phase = data->phase; - - gcd = calc_gcd(in_rate, out_rate); - in_rate /= gcd; - out_rate /= gcd; - data->rate = rate; - data->phase = phase * out_rate / (float)old_out_rate; - data->in_rate = in_rate; - data->out_rate = out_rate; - - data->inc = data->in_rate / data->out_rate; - data->frac = data->in_rate % data->out_rate; + in_rate = r->i_rate; + out_rate = r->o_rate; - if (data->in_rate == data->out_rate && rate == 1.0) { + if (rate != 1.0) { + in_rate = (uint32_t)(in_rate / rate); + data->func = data->info->process_inter; + } + else if (in_rate == out_rate) { data->func = data->info->process_copy; - r->func_name = data->info->copy_name; } - else if (rate == 1.0) { + else { + in_rate /= data->gcd; + out_rate /= data->gcd; data->func = data->info->process_full; - r->func_name = data->info->full_name; } - else { - data->func = data->info->process_inter; - r->func_name = data->info->inter_name; + + data->in_rate = in_rate; + if (data->out_rate != out_rate) { + data->phase = data->phase * out_rate / (float)data->out_rate; + data->out_rate = out_rate; } + data->inc = data->in_rate / data->out_rate; + data->frac = data->in_rate % data->out_rate; - spa_log_trace_fp(r->log, "native %p: rate:%f in:%d out:%d gcd:%d phase:%f inc:%d frac:%d", r, - rate, r->i_rate, r->o_rate, gcd, data->phase, data->inc, data->frac); + spa_log_trace_fp(r->log, "native %p: rate:%f in:%d out:%d phase:%f inc:%d frac:%d", r, + rate, r->i_rate, r->o_rate, data->phase, data->inc, data->frac); } @@ -393,6 +387,8 @@ d->n_phases = n_phases; d->in_rate = in_rate; d->out_rate = out_rate; + d->gcd = gcd; + d->pm = (float)n_phases / r->o_rate; d->filter = SPA_PTROFF_ALIGN(d, sizeof(struct native_data), 64, float); d->hist_mem = SPA_PTROFF_ALIGN(d->filter, filter_size, 64, float); d->history = SPA_PTROFF(d->hist_mem, history_size, float*); @@ -436,5 +432,12 @@ impl_native_reset(r); impl_native_update_rate(r, 1.0); + if (d->func == d->info->process_copy) + r->func_name = d->info->copy_name; + else if (d->func == d->info->process_full) + r->func_name = d->info->full_name; + else + r->func_name = d->info->inter_name; + return 0; }
View file
_service:download_url:pipewire-1.4.6.tar.bz2/spa/plugins/bluez5/a2dp-codec-caps.h -> _service:download_url:pipewire-1.4.7.tar.bz2/spa/plugins/bluez5/a2dp-codec-caps.h
Changed
@@ -116,8 +116,10 @@ #define AAC_SAMPLING_FREQ_88200 0x0002 #define AAC_SAMPLING_FREQ_96000 0x0001 -#define AAC_CHANNELS_1 0x02 -#define AAC_CHANNELS_2 0x01 +#define AAC_CHANNELS_1 0x08 +#define AAC_CHANNELS_2 0x04 +#define AAC_CHANNELS_5_1 0x02 +#define AAC_CHANNELS_7_1 0x01 #define AAC_GET_BITRATE(a) ((a).bitrate1 << 16 | \ (a).bitrate2 << 8 | (a).bitrate3) @@ -341,8 +343,7 @@ typedef struct { uint8_t object_type; uint8_t frequency1; - uint8_t rfa:2; - uint8_t channels:2; + uint8_t channels:4; uint8_t frequency2:4; uint8_t bitrate1:7; uint8_t vbr:1; @@ -403,8 +404,7 @@ uint8_t object_type; uint8_t frequency1; uint8_t frequency2:4; - uint8_t channels:2; - uint8_t rfa:2; + uint8_t channels:4; uint8_t vbr:1; uint8_t bitrate1:7; uint8_t bitrate2;
View file
_service:download_url:pipewire-1.4.6.tar.bz2/spa/plugins/filter-graph/audio-dsp-c.c -> _service:download_url:pipewire-1.4.7.tar.bz2/spa/plugins/filter-graph/audio-dsp-c.c
Changed
@@ -217,7 +217,7 @@ for (i = 0; i < n_samples; i++) { bufferw = bufferw + n_buffer = srci; dsti = bufferw + o; - w = w + 1 > n_buffer ? 0 : w + 1; + w = w + 1 >= n_buffer ? 0 : w + 1; } *pos = w; }
View file
_service:download_url:pipewire-1.4.6.tar.bz2/src/gst/gstpipewireformat.c -> _service:download_url:pipewire-1.4.7.tar.bz2/src/gst/gstpipewireformat.c
Changed
@@ -828,6 +828,8 @@ if ((idx = find_index(video_format_map, SPA_N_ELEMENTS(video_format_map), id)) == -1) return NULL; fourcc = gst_video_dma_drm_fourcc_from_format(idx); + if (fourcc == DRM_FORMAT_INVALID) + return NULL; return gst_video_dma_drm_fourcc_to_string(fourcc, mod); } #endif
View file
_service:download_url:pipewire-1.4.6.tar.bz2/src/modules/module-client-node/client-node.c -> _service:download_url:pipewire-1.4.7.tar.bz2/src/modules/module-client-node/client-node.c
Changed
@@ -242,7 +242,11 @@ static void clear_data(struct impl *impl, struct spa_data *d) { - switch (d->type) { + switch ((enum spa_data_type)d->type) { + case SPA_DATA_Invalid: + case SPA_DATA_MemPtr: + case _SPA_DATA_LAST: + break; case SPA_DATA_MemId: { uint32_t id; @@ -258,11 +262,10 @@ } case SPA_DATA_MemFd: case SPA_DATA_DmaBuf: + case SPA_DATA_SyncObj: pw_log_debug("%p: close fd:%d", impl, (int)d->fd); close(d->fd); break; - default: - break; } }
View file
_service:download_url:pipewire-1.4.6.tar.bz2/src/modules/module-echo-cancel.c -> _service:download_url:pipewire-1.4.7.tar.bz2/src/modules/module-echo-cancel.c
Changed
@@ -309,11 +309,6 @@ uint32_t i, size; uint32_t rindex, pindex, oindex, pdindex, avail; - if (impl->playback != NULL && (pout = pw_stream_dequeue_buffer(impl->playback)) == NULL) { - pw_log_debug("out of playback buffers: %m"); - goto done; - } - size = impl->aec_blocksize; /* First read a block from the playback and capture ring buffers */ @@ -338,6 +333,16 @@ spa_ringbuffer_get_read_index(&impl->play_ring, &pindex); spa_ringbuffer_get_read_index(&impl->play_delayed_ring, &pdindex); + if (impl->playback != NULL && (pout = pw_stream_dequeue_buffer(impl->playback)) == NULL) { + pw_log_debug("out of playback buffers: %m"); + + /* playback stream may not yet be in streaming state, drop play + * data to avoid introducing additional playback latency */ + spa_ringbuffer_read_update(&impl->play_ring, pindex + size); + spa_ringbuffer_read_update(&impl->play_delayed_ring, pdindex + size); + goto done; + } + for (i = 0; i < impl->play_info.channels; i++) { /* echo from sink */ playi = &play_bufi0; @@ -453,6 +458,31 @@ impl->capture_ready = false; } +static void reset_buffers(struct impl *impl) +{ + uint32_t index, i; + + spa_ringbuffer_init(&impl->rec_ring); + spa_ringbuffer_init(&impl->play_ring); + spa_ringbuffer_init(&impl->play_delayed_ring); + spa_ringbuffer_init(&impl->out_ring); + + for (i = 0; i < impl->rec_info.channels; i++) + memset(impl->rec_bufferi, 0, impl->rec_ringsize); + for (i = 0; i < impl->play_info.channels; i++) + memset(impl->play_bufferi, 0, impl->play_ringsize); + for (i = 0; i < impl->out_info.channels; i++) + memset(impl->out_bufferi, 0, impl->out_ringsize); + + spa_ringbuffer_get_write_index(&impl->play_ring, &index); + spa_ringbuffer_write_update(&impl->play_ring, index + (sizeof(float) * (impl->buffer_delay))); + spa_ringbuffer_get_read_index(&impl->play_ring, &index); + spa_ringbuffer_read_update(&impl->play_ring, index + (sizeof(float) * (impl->buffer_delay))); + + impl->sink_ready = false; + impl->capture_ready = false; +} + static void capture_destroy(void *d) { struct impl *impl = d; @@ -537,6 +567,8 @@ if (old == PW_STREAM_STATE_STREAMING) { if (pw_stream_get_state(impl->sink, NULL) != PW_STREAM_STATE_STREAMING) { + reset_buffers(impl); + pw_log_debug("%p: deactivate %s", impl, impl->aec->name); res = spa_audio_aec_deactivate(impl->aec); if (res < 0 && res != -EOPNOTSUPP) { @@ -588,28 +620,6 @@ } } -static void reset_buffers(struct impl *impl) -{ - uint32_t index, i; - - spa_ringbuffer_init(&impl->rec_ring); - spa_ringbuffer_init(&impl->play_ring); - spa_ringbuffer_init(&impl->play_delayed_ring); - spa_ringbuffer_init(&impl->out_ring); - - for (i = 0; i < impl->rec_info.channels; i++) - memset(impl->rec_bufferi, 0, impl->rec_ringsize); - for (i = 0; i < impl->play_info.channels; i++) - memset(impl->play_bufferi, 0, impl->play_ringsize); - for (i = 0; i < impl->out_info.channels; i++) - memset(impl->out_bufferi, 0, impl->out_ringsize); - - spa_ringbuffer_get_write_index(&impl->play_ring, &index); - spa_ringbuffer_write_update(&impl->play_ring, index + (sizeof(float) * (impl->buffer_delay))); - spa_ringbuffer_get_read_index(&impl->play_ring, &index); - spa_ringbuffer_read_update(&impl->play_ring, index + (sizeof(float) * (impl->buffer_delay))); -} - static void input_param_latency_changed(struct impl *impl, const struct spa_pod *param) { struct spa_latency_info latency; @@ -624,9 +634,9 @@ params0 = spa_latency_build(&b, SPA_PARAM_Latency, &latency); if (latency.direction == SPA_DIRECTION_INPUT) - pw_stream_update_params(impl->source, params, 1); - else pw_stream_update_params(impl->capture, params, 1); + else + pw_stream_update_params(impl->source, params, 1); } static struct spa_pod* get_props_param(struct impl* impl, struct spa_pod_builder* b) @@ -792,6 +802,8 @@ impl->current_delay = 0; if (pw_stream_get_state(impl->capture, NULL) != PW_STREAM_STATE_STREAMING) { + reset_buffers(impl); + pw_log_debug("%p: deactivate %s", impl, impl->aec->name); res = spa_audio_aec_deactivate(impl->aec); if (res < 0 && res != -EOPNOTSUPP) {
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
.