Projects
Essentials
pipewire-aptx
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 50
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.0/pipewire-1.4.0.tar.bz2</param> + <param name="path">/pipewire/pipewire/-/archive/1.4.1/pipewire-1.4.1.tar.bz2</param> </service> </services> \ No newline at end of file
View file
_service:download_url:pipewire-1.4.0.tar.bz2/NEWS -> _service:download_url:pipewire-1.4.1.tar.bz2/NEWS
Changed
@@ -1,3 +1,43 @@ +# PipeWire 1.4.1 (2025-03-14) + +This is a quick bugfix release that is API and ABI compatible with +previous 1.x releases. + +## Highlights + - Handle SplitPCM wrong channels specifications. This fixes some + problems with disappearing devices. + - Add backwards compatibility support for when the kernel does not + support UMP. Also fix UMP output. This restores MIDI support for + older kernels/ALSA. + - Fix a crash in audioconvert because the resampler was not using the + right number of channels. + - Some compilation fixes and small improvements. + + +## PipeWire + - Don't emit events when disconnecting a stream. (#3314) + - Fix some compilation problems. (#4603) + +## Modules + - Bump the ROC requirement to version 0.4.0 + +## SPA + - Handle SplitPCM too few or too many channels. Add an error string + to the device names when the UCM config has an error. + - Add backwards compatibility support for when the kernel does not + support UMP. + - Configure the channels in the resampler correctly in all + cases. (#4595) + - Fix UMP output. + - Use the right samplerate of the filter-graph in audioconvert in + all cases. + +## Bluetooth + - Fix a crash with an incomming call. + + +Older versions: + # PipeWire 1.4.0 (2025-03-06) This is the 1.4 release that is API and ABI compatible with previous @@ -99,9 +139,6 @@ ## JACK - Add an option to disable the MIDI2 port flags. (#4584) - -Older versions: - # PipeWire 1.3.83 (2025-02-20) This is the third and hopefully last 1.4 release candidate that
View file
_service:download_url:pipewire-1.4.0.tar.bz2/meson.build -> _service:download_url:pipewire-1.4.1.tar.bz2/meson.build
Changed
@@ -1,5 +1,5 @@ project('pipewire', 'c' , - version : '1.4.0', + version : '1.4.1', license : 'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' , meson_version : '>= 0.61.1', default_options : 'warning_level=3', @@ -127,21 +127,30 @@ add_project_arguments(cxx.get_supported_arguments(cxx_flags), language: 'cpp') endif -sse_args = '-msse' -sse2_args = '-msse2' -ssse3_args = '-mssse3' -sse41_args = '-msse4.1' -fma_args = '-mfma' -avx_args = '-mavx' -avx2_args = '-mavx2' - -have_sse = cc.has_argument(sse_args) -have_sse2 = cc.has_argument(sse2_args) -have_ssse3 = cc.has_argument(ssse3_args) -have_sse41 = cc.has_argument(sse41_args) -have_fma = cc.has_argument(fma_args) -have_avx = cc.has_argument(avx_args) -have_avx2 = cc.has_argument(avx2_args) +have_sse = false +have_sse2 = false +have_ssse3 = false +have_sse41 = false +have_fma = false +have_avx = false +have_avx2 = false +if host_machine.cpu_family() in 'x86', 'x86_64' + sse_args = '-msse' + sse2_args = '-msse2' + ssse3_args = '-mssse3' + sse41_args = '-msse4.1' + fma_args = '-mfma' + avx_args = '-mavx' + avx2_args = '-mavx2' + + have_sse = cc.has_argument(sse_args) + have_sse2 = cc.has_argument(sse2_args) + have_ssse3 = cc.has_argument(ssse3_args) + have_sse41 = cc.has_argument(sse41_args) + have_fma = cc.has_argument(fma_args) + have_avx = cc.has_argument(avx_args) + have_avx2 = cc.has_argument(avx2_args) +endif have_neon = false if host_machine.cpu_family() == 'aarch64' @@ -481,7 +490,7 @@ summary({'intl support': libintl_dep.found()}, bool_yn: true) need_alsa = get_option('pipewire-alsa').enabled() or 'media-session' in get_option('session-managers') -alsa_dep = dependency('alsa', version : '>=1.2.10', required: need_alsa) +alsa_dep = dependency('alsa', version : '>=1.2.6', required: need_alsa) summary({'pipewire-alsa': alsa_dep.found()}, bool_yn: true) if host_machine.system() == 'freebsd' or host_machine.system() == 'midnightbsd'
View file
_service:download_url:pipewire-1.4.0.tar.bz2/spa/meson.build -> _service:download_url:pipewire-1.4.1.tar.bz2/spa/meson.build
Changed
@@ -43,9 +43,13 @@ endif # plugin-specific dependencies - alsa_dep = dependency('alsa', version : '>=1.2.10', required: get_option('alsa')) + alsa_dep = dependency('alsa', version : '>=1.2.6', required: get_option('alsa')) summary({'ALSA': alsa_dep.found()}, bool_yn: true, section: 'Backend') + if alsa_dep.version().version_compare('>=1.2.10') + cdata.set('HAVE_ALSA_UMP', true) + endif + bluez_dep = dependency('bluez', version : '>= 4.101', required: get_option('bluez5')) bluez_gio_dep = dependency('gio-2.0', required : get_option('bluez5')) bluez_gio_unix_dep = dependency('gio-unix-2.0', required : get_option('bluez5'))
View file
_service:download_url:pipewire-1.4.0.tar.bz2/spa/plugins/alsa/acp-tool.c -> _service:download_url:pipewire-1.4.1.tar.bz2/spa/plugins/alsa/acp-tool.c
Changed
@@ -132,6 +132,18 @@ int level, const char *file, int line, const char *func, const char *fmt, va_list arg) { + static const char * const levels = { "E", "W", "N", "I", "D", "T" }; + const char *level_str = levelsSPA_CLAMP(level, 0, (int)SPA_N_ELEMENTS(levels) - 1); + + if (file) { + const char *p = strrchr(file, '/'); + if (p) + file = p + 1; + } + + fprintf(stderr, "%s %16s:%-5d ", level_str, file ? file : "", line); + while (level-- > 1) + fprintf(stderr, " "); vfprintf(stderr, fmt, arg); fprintf(stderr, "\n"); }
View file
_service:download_url:pipewire-1.4.0.tar.bz2/spa/plugins/alsa/acp/acp.c -> _service:download_url:pipewire-1.4.1.tar.bz2/spa/plugins/alsa/acp/acp.c
Changed
@@ -498,6 +498,7 @@ int n_profiles, n_ports, n_devices; uint32_t idx; const char *arr; + bool broken_ucm = false; n_devices = 0; pa_dynarray_init(&impl->out.devices, device_free); @@ -541,6 +542,9 @@ dev->ports, NULL); pa_dynarray_append(&ap->out.devices, dev); + + if (m->split && m->split->broken) + broken_ucm = true; } } @@ -564,6 +568,9 @@ dev->ports, NULL); pa_dynarray_append(&ap->out.devices, dev); + + if (m->split && m->split->broken) + broken_ucm = true; } } cp->n_devices = pa_dynarray_size(&ap->out.devices); @@ -571,6 +578,22 @@ pa_hashmap_put(impl->profiles, ap->name, cp); } + + /* Add a conspicuous notice if there are errors in the UCM profile */ + if (broken_ucm) { + const char *desc; + char *new_desc = NULL; + + desc = pa_proplist_gets(impl->proplist, PA_PROP_DEVICE_DESCRIPTION); + if (!desc) + desc = ""; + new_desc = spa_aprintf(_("%s ALSA UCM error"), desc); + pa_log_notice("Errors in ALSA UCM profile for card %s", desc); + if (new_desc) + pa_proplist_sets(impl->proplist, PA_PROP_DEVICE_DESCRIPTION, new_desc); + free(new_desc); + } + pa_dynarray_init(&impl->out.ports, NULL); n_ports = 0; PA_HASHMAP_FOREACH(dp, impl->ports, state) {
View file
_service:download_url:pipewire-1.4.0.tar.bz2/spa/plugins/alsa/acp/alsa-ucm.c -> _service:download_url:pipewire-1.4.1.tar.bz2/spa/plugins/alsa/acp/alsa-ucm.c
Changed
@@ -353,6 +353,15 @@ const char *device_name; int i; uint32_t hw_channels; + const char *pcm_name; + const char *rule_name; + + if (spa_streq(prefix, "Playback")) + pcm_name = pa_proplist_gets(device->proplist, PA_ALSA_PROP_UCM_SINK); + else + pcm_name = pa_proplist_gets(device->proplist, PA_ALSA_PROP_UCM_SOURCE); + if (!pcm_name) + pcm_name = ""; device_name = pa_proplist_gets(device->proplist, PA_ALSA_PROP_UCM_NAME); if (!device_name) @@ -372,16 +381,23 @@ if (pa_atou(value, &idx) < 0) break; - if (idx >= hw_channels) - goto fail; + if (idx >= hw_channels) { + pa_log_notice("Error in ALSA UCM profile for %s (%s): %sChannel%d=%d >= %sChannels=%d", + pcm_name, device_name, prefix, i, idx, prefix, hw_channels); + split->broken = true; + } value = ucm_get_string(uc_mgr, "%sChannelPos%d/%s", prefix, i, device_name); - if (!value) + if (!value) { + rule_name = "ChannelPos"; goto fail; + } map = snd_pcm_chmap_parse_string(value); - if (!map) + if (!map) { + rule_name = "ChannelPos value"; goto fail; + } if (map->channels == 1) { pa_log_debug("Split %s channel %d -> device %s channel %d: %s (%d)", @@ -391,6 +407,7 @@ free(map); } else { free(map); + rule_name = "channel map parsing"; goto fail; } } @@ -405,7 +422,7 @@ return split; fail: - pa_log_warn("Invalid SplitPCM ALSA UCM rule for device %s", device_name); + pa_log_warn("Invalid SplitPCM ALSA UCM %s for device %s (%s)", rule_name, pcm_name, device_name); pa_xfree(split); return NULL; } @@ -2383,7 +2400,7 @@ dev->eld_device = pcm_device; } -static snd_pcm_t* mapping_open_pcm(pa_alsa_ucm_config *ucm, pa_alsa_mapping *m, int mode) { +static snd_pcm_t* mapping_open_pcm(pa_alsa_ucm_config *ucm, pa_alsa_mapping *m, int mode, bool max_channels) { snd_pcm_t* pcm; pa_sample_spec try_ss = ucm->default_sample_spec; pa_channel_map try_map; @@ -2391,6 +2408,11 @@ bool exact_channels = m->channel_map.channels > 0; if (!m->split) { + if (max_channels) { + errno = EINVAL; + return NULL; + } + if (exact_channels) { try_map = m->channel_map; try_ss.channels = try_map.channels; @@ -2402,8 +2424,8 @@ return NULL; } - exact_channels = true; - try_ss.channels = m->split->hw_channels; + exact_channels = false; + try_ss.channels = max_channels ? PA_CHANNELS_MAX : m->split->hw_channels; pa_channel_map_init_extend(&try_map, try_ss.channels, PA_CHANNEL_MAP_AUX); } @@ -2416,15 +2438,40 @@ &try_map, mode, &try_period_size, &try_buffer_size, 0, NULL, NULL, NULL, NULL, exact_channels); if (pcm) { - if (!exact_channels) + if (m->split) { + const char *mode_name = mode == SND_PCM_STREAM_PLAYBACK ? "Playback" : "Capture"; + + if (try_map.channels < m->split->hw_channels) { + pa_logl((max_channels ? PA_LOG_NOTICE : PA_LOG_DEBUG), + "Error in ALSA UCM profile for %s (%s): %sChannels=%d > avail %d", + m->device_strings0, m->name, mode_name, m->split->hw_channels, try_map.channels); + + /* Retry with max channel count, in case ALSA rounded down */ + if (!max_channels) { + pa_alsa_close(&pcm); + return mapping_open_pcm(ucm, m, mode, true); + } + + /* Just accept whatever we got... Some of the routings won't get connected + * anywhere */ + m->split->hw_channels = try_map.channels; + m->split->broken = true; + } else if (try_map.channels > m->split->hw_channels) { + pa_log_notice("Error in ALSA UCM profile for %s (%s): %sChannels=%d < avail %d", + m->device_strings0, m->name, mode_name, m->split->hw_channels, try_map.channels); + m->split->hw_channels = try_map.channels; + m->split->broken = true; + } + } else if (!exact_channels) { m->channel_map = try_map; + } mapping_init_eld(m, pcm); } return pcm; } -static void pa_alsa_init_proplist_split_pcm(pa_idxset *mappings, pa_alsa_mapping *leader, pa_direction_t direction) +static void pa_alsa_init_split_pcm(pa_idxset *mappings, pa_alsa_mapping *leader, pa_direction_t direction) { pa_proplist *props = pa_proplist_new(); uint32_t idx; @@ -2445,6 +2492,9 @@ pa_proplist_update(m->output_proplist, PA_UPDATE_REPLACE, props); else pa_proplist_update(m->input_proplist, PA_UPDATE_REPLACE, props); + + /* Update HW channel count to match probed one */ + m->split->hw_channels = leader->split->hw_channels; } pa_proplist_free(props); @@ -2464,7 +2514,7 @@ if (!m->split) pa_alsa_init_proplist_pcm(NULL, m->output_proplist, m->output_pcm); else - pa_alsa_init_proplist_split_pcm(p->output_mappings, m, PA_DIRECTION_OUTPUT); + pa_alsa_init_split_pcm(p->output_mappings, m, PA_DIRECTION_OUTPUT); pa_alsa_close(&m->output_pcm); } @@ -2479,7 +2529,7 @@ if (!m->split) pa_alsa_init_proplist_pcm(NULL, m->input_proplist, m->input_pcm); else - pa_alsa_init_proplist_split_pcm(p->input_mappings, m, PA_DIRECTION_INPUT); + pa_alsa_init_split_pcm(p->input_mappings, m, PA_DIRECTION_INPUT); pa_alsa_close(&m->input_pcm); } @@ -2521,7 +2571,7 @@ pa_log_info("Set ucm verb to %s", verb_name); if ((snd_use_case_set(ucm->ucm_mgr, "_verb", verb_name)) < 0) { - pa_log("Failed to set verb %s", verb_name); + pa_log("Profile '%s': failed to set verb %s", p->name, verb_name); p->supported = false; continue; } @@ -2536,8 +2586,10 @@ if (m->split && !m->split->leader) continue; - m->output_pcm = mapping_open_pcm(ucm, m, SND_PCM_STREAM_PLAYBACK); + m->output_pcm = mapping_open_pcm(ucm, m, SND_PCM_STREAM_PLAYBACK, false); if (!m->output_pcm) { + pa_log_info("Profile '%s' mapping '%s': output PCM open failed", + p->name, m->name); p->supported = false; break; } @@ -2554,8 +2606,10 @@ if (m->split && !m->split->leader) continue; - m->input_pcm = mapping_open_pcm(ucm, m, SND_PCM_STREAM_CAPTURE); + m->input_pcm = mapping_open_pcm(ucm, m, SND_PCM_STREAM_CAPTURE, false); if (!m->input_pcm) { + pa_log_info("Profile '%s' mapping '%s': input PCM open failed", + p->name, m->name); p->supported = false; break; } @@ -2564,6 +2618,7 @@ if (!p->supported) { profile_finalize_probing(p); + pa_log_info("Profile %s not supported", p->name); continue; }
View file
_service:download_url:pipewire-1.4.0.tar.bz2/spa/plugins/alsa/acp/alsa-ucm.h -> _service:download_url:pipewire-1.4.1.tar.bz2/spa/plugins/alsa/acp/alsa-ucm.h
Changed
@@ -185,6 +185,7 @@ int channels; int idxPA_CHANNELS_MAX; enum snd_pcm_chmap_position posPA_CHANNELS_MAX; + bool broken; }; struct pa_alsa_ucm_device {
View file
_service:download_url:pipewire-1.4.0.tar.bz2/spa/plugins/alsa/alsa-seq-bridge.c -> _service:download_url:pipewire-1.4.1.tar.bz2/spa/plugins/alsa/alsa-seq-bridge.c
Changed
@@ -931,6 +931,7 @@ this->quantum_limit = 8192; this->min_pool_size = 500; this->max_pool_size = 2000; + this->ump = true; for (i = 0; info && i < info->n_items; i++) { const char *k = info->itemsi.key; @@ -949,6 +950,8 @@ spa_atou32(s, &this->min_pool_size, 0); } else if (spa_streq(k, "api.alsa.seq.max-pool")) { spa_atou32(s, &this->max_pool_size, 0); + } else if (spa_streq(k, "api.alsa.seq.ump")) { + this->ump = spa_atob(s); } } @@ -992,6 +995,7 @@ ""SPA_KEY_API_ALSA_DISABLE_LONGNAME"=<bool, default false> " " api.alsa.seq.min-pool=<min-pool, default 500> " " api.alsa.seq.max-pool=<max-pool, default 2000>" + " api.alsa.seq.ump = <boolean> " }, };
View file
_service:download_url:pipewire-1.4.0.tar.bz2/spa/plugins/alsa/alsa-seq.c -> _service:download_url:pipewire-1.4.1.tar.bz2/spa/plugins/alsa/alsa-seq.c
Changed
@@ -24,7 +24,7 @@ #define CHECK(s,msg,...) if ((res = (s)) < 0) { spa_log_error(state->log, msg ": %s", ##__VA_ARGS__, snd_strerror(res)); return res; } -static int seq_open(struct seq_state *state, struct seq_conn *conn, bool with_queue) +static int seq_open(struct seq_state *state, struct seq_conn *conn, bool with_queue, bool probe_ump) { struct props *props = &state->props; int res; @@ -37,11 +37,28 @@ 0)) < 0) return res; - if ((res = snd_seq_set_client_midi_version(conn->hndl, SND_SEQ_CLIENT_UMP_MIDI_2_0)) < 0) { - snd_seq_close(conn->hndl); - spa_log_info(state->log, "%p: ALSA failed to enable UMP MIDI: %s", - state, snd_strerror(res)); - return res; + if (!state->ump) { + spa_log_info(state->log, "%p: ALSA UMP MIDI disabled", state); + return 0; + } + +#ifdef HAVE_ALSA_UMP + res = snd_seq_set_client_midi_version(conn->hndl, SND_SEQ_CLIENT_UMP_MIDI_2_0); +#else + res = -EOPNOTSUPP; +#endif + if (res < 0) { + spa_log_lev(state->log, (probe_ump ? SPA_LOG_LEVEL_INFO : SPA_LOG_LEVEL_ERROR), + "%p: ALSA failed to enable UMP MIDI: %s", state, snd_strerror(res)); + if (!probe_ump) { + snd_seq_close(conn->hndl); + return res; /* either all are UMP or none are UMP */ + } + + state->ump = false; + } else { + spa_log_debug(state->log, "%p: ALSA UMP MIDI enabled", state); + state->ump = true; } return 0; @@ -172,7 +189,32 @@ } } -static void debug_event(struct seq_state *state, snd_seq_ump_event_t *ev) +static void debug_event(struct seq_state *state, snd_seq_event_t *ev) +{ + if (SPA_LIKELY(!spa_log_level_topic_enabled(state->log, SPA_LOG_TOPIC_DEFAULT, SPA_LOG_LEVEL_TRACE))) + return; + + spa_log_trace(state->log, "event type:%d flags:0x%x", ev->type, ev->flags); + switch (ev->flags & SND_SEQ_TIME_STAMP_MASK) { + case SND_SEQ_TIME_STAMP_TICK: + spa_log_trace(state->log, " time: %d ticks", ev->time.tick); + break; + case SND_SEQ_TIME_STAMP_REAL: + spa_log_trace(state->log, " time = %d.%09d", + (int)ev->time.time.tv_sec, + (int)ev->time.time.tv_nsec); + break; + } + spa_log_trace(state->log, " source:%d.%d dest:%d.%d queue:%d", + ev->source.client, + ev->source.port, + ev->dest.client, + ev->dest.port, + ev->queue); +} + +#ifdef HAVE_ALSA_UMP +static void debug_ump_event(struct seq_state *state, snd_seq_ump_event_t *ev) { if (SPA_LIKELY(!spa_log_level_topic_enabled(state->log, SPA_LOG_TOPIC_DEFAULT, SPA_LOG_LEVEL_TRACE))) return; @@ -195,22 +237,50 @@ ev->dest.port, ev->queue); } +#endif static void alsa_seq_on_sys(struct spa_source *source) { struct seq_state *state = source->data; - snd_seq_ump_event_t *ev; + const bool ump = state->ump; int res; - while (snd_seq_ump_event_input(state->sys.hndl, &ev) > 0) { - const snd_seq_addr_t *addr = &ev->data.addr; + while (1) { + const snd_seq_addr_t *addr; + snd_seq_event_type_t type; + + if (ump) { +#ifdef HAVE_ALSA_UMP + snd_seq_ump_event_t *ev; + + res = snd_seq_ump_event_input(state->sys.hndl, &ev); + if (res <= 0) + break; + + debug_ump_event(state, ev); + + addr = &ev->data.addr; + type = ev->type; +#else + spa_assert_not_reached(); +#endif + } else { + snd_seq_event_t *ev; + + res = snd_seq_event_input(state->sys.hndl, &ev); + if (res <= 0) + break; + + debug_event(state, ev); + + addr = &ev->data.addr; + type = ev->type; + } if (addr->client == state->event.addr.client) continue; - debug_event(state, ev); - - switch (ev->type) { + switch (type) { case SND_SEQ_EVENT_CLIENT_START: case SND_SEQ_EVENT_CLIENT_CHANGE: spa_log_info(state->log, "client add/change %d", addr->client); @@ -244,7 +314,7 @@ break; default: spa_log_info(state->log, "unhandled event %d: %d:%d", - ev->type, addr->client, addr->port); + type, addr->client, addr->port); break; } @@ -269,8 +339,8 @@ spa_zero(reserve); for (i = 0; i < 16; i++) { - spa_log_debug(state->log, "close %d", i); - if ((res = seq_open(state, &reservei, false)) < 0) + spa_log_debug(state->log, "open %d", i); + if ((res = seq_open(state, &reservei, false, (i == 0))) < 0) break; } if (i >= 2) { @@ -529,21 +599,58 @@ static int process_read(struct seq_state *state) { - snd_seq_ump_event_t *ev; struct seq_stream *stream = &state->streamsSPA_DIRECTION_OUTPUT; + const bool ump = state->ump; uint32_t i; uint32_t *data; + uint8_t midi1_dataMAX_EVENT_SIZE; + uint32_t ump_dataMAX_EVENT_SIZE; long size; - int res; + int res = -1; /* copy all new midi events into their port buffers */ - while ((res = snd_seq_ump_event_input(state->event.hndl, &ev)) > 0) { - const snd_seq_addr_t *addr = &ev->source; + while (1) { + const snd_seq_addr_t *addr; struct seq_port *port; uint64_t ev_time, diff; uint32_t offset; + void *event; + uint8_t *midi1_ptr; + size_t midi1_size = 0; + uint64_t ump_state = 0; + snd_seq_event_type_t SPA_UNUSED type; + + if (ump) { +#ifdef HAVE_ALSA_UMP + snd_seq_ump_event_t *ev; + + res = snd_seq_ump_event_input(state->event.hndl, &ev); + if (res <= 0) + break; + + debug_ump_event(state, ev); + + event = ev; + addr = &ev->source; + ev_time = SPA_TIMESPEC_TO_NSEC(&ev->time.time); + type = ev->type; +#else + spa_assert_not_reached(); +#endif + } else { + snd_seq_event_t *ev; - debug_event(state, ev); + res = snd_seq_event_input(state->event.hndl, &ev); + if (res <= 0) + break; + + debug_event(state, ev); + + event = ev; + addr = &ev->source; + ev_time = SPA_TIMESPEC_TO_NSEC(&ev->time.time); + type = ev->type; + } if ((port = find_port(state, stream, addr)) == NULL) { spa_log_debug(state->log, "unknown port %d.%d", @@ -559,12 +666,8 @@ continue; } - data = (uint32_t*)&ev->ump0; - size = spa_ump_message_size(snd_ump_msg_hdr_type(ev->ump0)) * 4; - /* queue_time is the estimated current time of the queue as calculated by * the DLL. Calculate the age of the event. */ - ev_time = SPA_TIMESPEC_TO_NSEC(&ev->time.time); if (state->queue_time > ev_time) diff = state->queue_time - ev_time; else @@ -577,19 +680,54 @@ else offset = 0; - spa_log_trace_fp(state->log, "event %d time:%"PRIu64" offset:%d size:%ld port:%d.%d", - ev->type, ev_time, offset, size, addr->client, addr->port); + if (ump) { +#ifdef HAVE_ALSA_UMP + snd_seq_ump_event_t *ev = event; - spa_pod_builder_control(&port->builder, offset, SPA_CONTROL_UMP); - spa_pod_builder_bytes(&port->builder, data, size); + data = (uint32_t*)&ev->ump0; + size = spa_ump_message_size(snd_ump_msg_hdr_type(ev->ump0)) * 4; +#else + spa_assert_not_reached(); +#endif + } else { + snd_seq_event_t *ev = event; - /* make sure we can fit at least one control event of max size otherwise - * we keep the event in the queue and try to copy it in the next cycle */ - if (port->builder.state.offset + - sizeof(struct spa_pod_control) + - MAX_EVENT_SIZE > port->buffer->buf->datas0.maxsize) - break; + snd_midi_event_reset_decode(stream->codec); + if ((size = snd_midi_event_decode(stream->codec, midi1_data, sizeof(midi1_data), ev)) < 0) { + spa_log_warn(state->log, "decode failed: %s", snd_strerror(size)); + continue; + } + + midi1_ptr = midi1_data; + midi1_size = size; + } + + do { + if (!ump) { + data = ump_data; + size = spa_ump_from_midi(&midi1_ptr, &midi1_size, + ump_data, sizeof(ump_data), 0, &ump_state); + if (size <= 0) + break; + } + + spa_log_trace_fp(state->log, "event %d time:%"PRIu64" offset:%d size:%ld port:%d.%d", + type, ev_time, offset, size, addr->client, addr->port); + + spa_pod_builder_control(&port->builder, offset, SPA_CONTROL_UMP); + spa_pod_builder_bytes(&port->builder, data, size); + + /* make sure we can fit at least one control event of max size otherwise + * we keep the event in the queue and try to copy it in the next cycle */ + if (port->builder.state.offset + + sizeof(struct spa_pod_control) + + MAX_EVENT_SIZE > port->buffer->buf->datas0.maxsize) + goto done; + + } while (!ump); } + +done: if (res < 0 && res != -EAGAIN) spa_log_warn(state->log, "event read failed: %s", snd_strerror(res)); @@ -651,6 +789,7 @@ static int process_write(struct seq_state *state) { struct seq_stream *stream = &state->streamsSPA_DIRECTION_INPUT; + const bool ump = state->ump; uint32_t i; int err, res = 0; @@ -661,7 +800,6 @@ struct spa_pod_sequence *pod; struct spa_data *d; struct spa_pod_control *c; - snd_seq_ump_event_t ev; uint64_t out_time; snd_seq_real_time_t out_rt; @@ -695,25 +833,55 @@ body = SPA_POD_BODY(&c->value); body_size = SPA_POD_BODY_SIZE(&c->value); - spa_zero(ev); - - memcpy(ev.ump, body, SPA_MIN(sizeof(ev.ump), (size_t)body_size)); - - snd_seq_ev_set_source(&ev, state->event.addr.port); - snd_seq_ev_set_dest(&ev, port->addr.client, port->addr.port); out_time = state->queue_time + NSEC_FROM_CLOCK(&state->rate, c->offset); - out_rt.tv_nsec = out_time % SPA_NSEC_PER_SEC; out_rt.tv_sec = out_time / SPA_NSEC_PER_SEC; - snd_seq_ev_schedule_real(&ev, state->event.queue_id, 0, &out_rt); - spa_log_trace_fp(state->log, "event %d time:%"PRIu64" offset:%d size:%zd port:%d.%d", - ev.type, out_time, c->offset, body_size, port->addr.client, port->addr.port); + spa_log_trace_fp(state->log, "event time:%"PRIu64" offset:%d size:%zd port:%d.%d", + out_time, c->offset, body_size, port->addr.client, port->addr.port); + + if (ump) { +#ifdef HAVE_ALSA_UMP + snd_seq_ump_event_t ev; + + snd_seq_ump_ev_clear(&ev); + snd_seq_ev_set_ump_data(&ev, body, SPA_MIN(sizeof(ev.ump), (size_t)body_size)); + snd_seq_ev_set_source(&ev, state->event.addr.port); + snd_seq_ev_set_dest(&ev, port->addr.client, port->addr.port); + snd_seq_ev_schedule_real(&ev, state->event.queue_id, 0, &out_rt); + + if ((err = snd_seq_ump_event_output(state->event.hndl, &ev)) < 0) { + spa_log_warn(state->log, "failed to output event: %s", + snd_strerror(err)); + } +#else + spa_assert_not_reached(); +#endif + } else { + snd_seq_event_t ev; + uint8_t dataMAX_EVENT_SIZE; + int size; + + if ((size = spa_ump_to_midi((uint32_t *)body, body_size, data, sizeof(data))) <= 0) + continue; + + snd_seq_ev_clear(&ev); + + snd_midi_event_reset_encode(stream->codec); + if ((size = snd_midi_event_encode(stream->codec, data, size, &ev)) <= 0) { + spa_log_warn(state->log, "failed to encode event: %s", snd_strerror(size)); + continue; + } + + snd_seq_ev_set_source(&ev, state->event.addr.port); + snd_seq_ev_set_dest(&ev, port->addr.client, port->addr.port); + snd_seq_ev_schedule_real(&ev, state->event.queue_id, 0, &out_rt); - if ((err = snd_seq_ump_event_output(state->event.hndl, &ev)) < 0) { - spa_log_warn(state->log, "failed to output event: %s", - snd_strerror(err)); + if ((err = snd_seq_event_output(state->event.hndl, &ev)) < 0) { + spa_log_warn(state->log, "failed to output event: %s", + snd_strerror(err)); + } } } }
View file
_service:download_url:pipewire-1.4.0.tar.bz2/spa/plugins/alsa/alsa-seq.h -> _service:download_url:pipewire-1.4.1.tar.bz2/spa/plugins/alsa/alsa-seq.h
Changed
@@ -12,8 +12,12 @@ #include <stddef.h> #include <math.h> +#include "config.h" + #include <alsa/asoundlib.h> +#ifdef HAVE_ALSA_UMP #include <alsa/ump_msg.h> +#endif #include <spa/support/plugin.h> #include <spa/support/loop.h> @@ -153,6 +157,7 @@ unsigned int opened:1; unsigned int started:1; unsigned int following:1; + unsigned int ump:1; struct seq_stream streams2;
View file
_service:download_url:pipewire-1.4.0.tar.bz2/spa/plugins/audioconvert/audioconvert.c -> _service:download_url:pipewire-1.4.1.tar.bz2/spa/plugins/audioconvert/audioconvert.c
Changed
@@ -210,7 +210,6 @@ uint32_t src_idx; uint32_t dst_idx; uint32_t final_idx; - uint32_t n_datas; struct port *ctrlport; }; @@ -219,8 +218,6 @@ bool passthrough; uint32_t in_idx; uint32_t out_idx; - uint32_t n_in; - uint32_t n_out; void *data; void (*run) (struct stage *stage, struct stage_context *c); }; @@ -1003,13 +1000,13 @@ { int res; char rate_str64; - struct dir *in; + struct dir *dir; if (graph == NULL) return 0; - in = &this->dirSPA_DIRECTION_INPUT; - snprintf(rate_str, sizeof(rate_str), "%d", in->format.info.raw.rate); + dir = &this->dirSPA_DIRECTION_REVERSE(this->direction); + snprintf(rate_str, sizeof(rate_str), "%d", dir->format.info.raw.rate); spa_filter_graph_deactivate(graph); res = spa_filter_graph_activate(graph, @@ -1971,13 +1968,19 @@ struct dir *in = &this->dirSPA_DIRECTION_INPUT; struct dir *out = &this->dirSPA_DIRECTION_OUTPUT; int res; + uint32_t channels; + + if (this->direction == SPA_DIRECTION_INPUT) + channels = in->format.info.raw.channels; + else + channels = out->format.info.raw.channels; spa_log_info(this->log, "%p: %s/%d@%d->%s/%d@%d", this, spa_debug_type_find_name(spa_type_audio_format, SPA_AUDIO_FORMAT_DSP_F32), - out->format.info.raw.channels, + channels, in->format.info.raw.rate, spa_debug_type_find_name(spa_type_audio_format, SPA_AUDIO_FORMAT_DSP_F32), - out->format.info.raw.channels, + channels, out->format.info.raw.rate); if (this->props.resample_disabled && !this->resample_peaks && @@ -1987,7 +1990,7 @@ if (this->resample.free) resample_free(&this->resample); - this->resample.channels = out->format.info.raw.channels; + this->resample.channels = channels; this->resample.i_rate = in->format.info.raw.rate; this->resample.o_rate = out->format.info.raw.rate; this->resample.log = this->log; @@ -3217,8 +3220,6 @@ s->passthrough = false; s->in_idx = ctx->src_idx; s->out_idx = ctx->src_idx; - s->n_in = ctx->n_datas; - s->n_out = ctx->n_datas; s->data = NULL; s->run = run_wav_stage; spa_log_trace(impl->log, "%p: stage %d", impl, impl->n_stages); @@ -3230,7 +3231,7 @@ struct impl *impl = s->impl; struct dir *dir = &impl->dirSPA_DIRECTION_OUTPUT; uint32_t i; - for (i = 0; i < s->n_in; i++) { + for (i = 0; i < dir->conv.n_channels; i++) { c->datass->out_idxi = c->datass->in_idxdir->remapi; spa_log_trace_fp(impl->log, "%p: output remap %d -> %d", impl, i, dir->remapi); } @@ -3242,8 +3243,6 @@ s->passthrough = false; s->in_idx = ctx->dst_idx; s->out_idx = CTX_DATA_REMAP_DST; - s->n_in = ctx->n_datas; - s->n_out = ctx->n_datas; s->data = NULL; s->run = run_dst_remap_stage; spa_log_trace(impl->log, "%p: stage %d", impl, impl->n_stages); @@ -3269,8 +3268,6 @@ s->passthrough = false; s->in_idx = ctx->src_idx; s->out_idx = CTX_DATA_REMAP_SRC; - s->n_in = ctx->n_datas; - s->n_out = ctx->n_datas; s->data = NULL; s->run = run_src_remap_stage; spa_log_trace(impl->log, "%p: stage %d", impl, impl->n_stages); @@ -3304,8 +3301,6 @@ s->passthrough = false; s->in_idx = ctx->src_idx; s->out_idx = ctx->dst_idx; - s->n_in = ctx->n_datas; - s->n_out = ctx->n_datas; s->data = NULL; s->run = run_src_convert_stage; spa_log_trace(impl->log, "%p: stage %d", impl, impl->n_stages); @@ -3334,8 +3329,6 @@ s->passthrough = false; s->in_idx = ctx->src_idx; s->out_idx = ctx->dst_idx; - s->n_in = ctx->n_datas; - s->n_out = ctx->n_datas; s->data = NULL; s->run = run_resample_stage; spa_log_trace(impl->log, "%p: stage %d", impl, impl->n_stages); @@ -3383,8 +3376,6 @@ s->passthrough = false; s->in_idx = ctx->src_idx; s->out_idx = ctx->dst_idx; - s->n_in = ctx->n_datas; - s->n_out = ctx->n_datas; s->data = fg; s->run = run_filter_stage; spa_log_trace(impl->log, "%p: stage %d", impl, impl->n_stages); @@ -3399,8 +3390,6 @@ s->passthrough = false; s->in_idx = ctx->src_idx; s->out_idx = ctx->dst_idx; - s->n_in = ctx->n_datas; - s->n_out = ctx->n_datas; s->data = NULL; s->run = run_channelmix_stage; spa_log_trace(impl->log, "%p: stage %d", impl, impl->n_stages); @@ -3434,8 +3423,6 @@ s->passthrough = false; s->in_idx = ctx->src_idx; s->out_idx = ctx->final_idx; - s->n_in = ctx->n_datas; - s->n_out = ctx->n_datas; s->data = NULL; s->run = run_dst_convert_stage; spa_log_trace(impl->log, "%p: stage %d", impl, impl->n_stages); @@ -3828,14 +3815,14 @@ ctx.in_samples = n_samples; ctx.n_samples = n_samples; ctx.n_out = n_out; - ctx.src_idx = CTX_DATA_SRC; - ctx.dst_idx = CTX_DATA_DST; - ctx.final_idx = CTX_DATA_DST; - ctx.n_datas = dir->conv.n_channels; ctx.ctrlport = ctrlport; - if (this->recalc) + if (SPA_UNLIKELY(this->recalc)) { + ctx.src_idx = CTX_DATA_SRC; + ctx.dst_idx = CTX_DATA_DST; + ctx.final_idx = CTX_DATA_DST; recalc_stages(this, &ctx); + } for (i = 0; i < this->n_stages; i++) { struct stage *s = &this->stagesi;
View file
_service:download_url:pipewire-1.4.0.tar.bz2/spa/plugins/bluez5/backend-native.c -> _service:download_url:pipewire-1.4.1.tar.bz2/spa/plugins/bluez5/backend-native.c
Changed
@@ -1406,18 +1406,44 @@ struct rfcomm_call_data *call_data = data; struct rfcomm *rfcomm = call_data->rfcomm; struct impl *backend = rfcomm->backend; + struct spa_bt_telephony_call *call, *tcall; + bool found_held = false; + bool hfp_hf_in_progress = false; char reply20; bool res; + spa_list_for_each(call, &rfcomm->telephony_ag->call_list, link) { + if (call->state == CALL_STATE_HELD) + found_held = true; + } + switch (call_data->call->state) { case CALL_STATE_ACTIVE: case CALL_STATE_DIALING: case CALL_STATE_ALERTING: case CALL_STATE_INCOMING: - rfcomm_send_cmd(rfcomm, "AT+CHUP"); + if (found_held) { + if (!rfcomm->chld_supported) { + *err = BT_TELEPHONY_ERROR_NOT_SUPPORTED; + return; + } else if (rfcomm->hfp_hf_in_progress) { + *err = BT_TELEPHONY_ERROR_IN_PROGRESS; + return; + } + + rfcomm_send_cmd(rfcomm, "AT+CHLD=1"); + hfp_hf_in_progress = true; + } else { + rfcomm_send_cmd(rfcomm, "AT+CHUP"); + } break; case CALL_STATE_WAITING: + if (rfcomm->hfp_hf_in_progress) { + *err = BT_TELEPHONY_ERROR_IN_PROGRESS; + return; + } rfcomm_send_cmd(rfcomm, "AT+CHLD=0"); + hfp_hf_in_progress = true; break; default: spa_log_info(backend->log, "Call not incoming, waiting or active: skip hangup"); @@ -1435,6 +1461,24 @@ return; } + if (hfp_hf_in_progress) { + if (call_data->call->state != CALL_STATE_WAITING) { + spa_list_for_each_safe(call, tcall, &rfcomm->telephony_ag->call_list, link) { + if (call->state == CALL_STATE_ACTIVE) { + call->state = CALL_STATE_DISCONNECTED; + telephony_call_notify_updated_props(call); + telephony_call_destroy(call); + } + } + spa_list_for_each(call, &rfcomm->telephony_ag->call_list, link) { + if (call->state == CALL_STATE_HELD) { + call->state = CALL_STATE_ACTIVE; + telephony_call_notify_updated_props(call); + } + } + } + rfcomm->hfp_hf_in_progress = true; + } *err = BT_TELEPHONY_ERROR_NONE; } @@ -2286,6 +2330,26 @@ } SPA_FALLTHROUGH; case hfp_hf_chld: + rfcomm->slc_configured = true; + + if (!rfcomm->codec_negotiation_supported) { + if (rfcomm_new_transport(rfcomm, HFP_AUDIO_CODEC_CVSD) < 0) { + // TODO: We should manage the missing transport + } else { + spa_bt_device_connect_profile(rfcomm->device, rfcomm->profile); + } + } + + rfcomm->telephony_ag = telephony_ag_new(backend->telephony, 0); + rfcomm->telephony_ag->address = strdup(rfcomm->device->address); + telephony_ag_set_callbacks(rfcomm->telephony_ag, + &telephony_ag_callbacks, rfcomm); + if (rfcomm->transport) { + rfcomm->telephony_ag->transport.codec = rfcomm->transport->codec; + rfcomm->telephony_ag->transport.state = rfcomm->transport->state; + } + telephony_ag_register(rfcomm->telephony_ag); + rfcomm_send_cmd(rfcomm, "AT+CLIP=1"); rfcomm->hf_state = hfp_hf_clip; break; @@ -2312,25 +2376,6 @@ SPA_FALLTHROUGH; case hfp_hf_nrec: rfcomm->hf_state = hfp_hf_slc1; - rfcomm->slc_configured = true; - - if (!rfcomm->codec_negotiation_supported) { - if (rfcomm_new_transport(rfcomm, HFP_AUDIO_CODEC_CVSD) < 0) { - // TODO: We should manage the missing transport - } else { - spa_bt_device_connect_profile(rfcomm->device, rfcomm->profile); - } - } - - rfcomm->telephony_ag = telephony_ag_new(backend->telephony, 0); - rfcomm->telephony_ag->address = strdup(rfcomm->device->address); - telephony_ag_set_callbacks(rfcomm->telephony_ag, - &telephony_ag_callbacks, rfcomm); - if (rfcomm->transport) { - rfcomm->telephony_ag->transport.codec = rfcomm->transport->codec; - rfcomm->telephony_ag->transport.state = rfcomm->transport->state; - } - telephony_ag_register(rfcomm->telephony_ag); if (rfcomm->hfp_hf_clcc) { rfcomm_send_cmd(rfcomm, "AT+CLCC"); @@ -3318,6 +3363,7 @@ } else if (profile == SPA_BT_PROFILE_HFP_AG) { /* Start SLC connection */ unsigned int hf_features = SPA_BT_HFP_HF_FEATURE_CLIP | SPA_BT_HFP_HF_FEATURE_3WAY | + SPA_BT_HFP_HF_FEATURE_ECNR | SPA_BT_HFP_HF_FEATURE_ENHANCED_CALL_STATUS | SPA_BT_HFP_HF_FEATURE_ESCO_S4; bool has_msbc = device_supports_codec(backend, rfcomm->device, HFP_AUDIO_CODEC_MSBC);
View file
_service:download_url:pipewire-1.4.0.tar.bz2/src/daemon/systemd/user/pipewire.service.in -> _service:download_url:pipewire-1.4.1.tar.bz2/src/daemon/systemd/user/pipewire.service.in
Changed
@@ -14,6 +14,7 @@ # After=pipewire.socket is not needed, as it is already implicit in the # socket-service relationship, see systemd.socket(5). Requires=pipewire.socket +ConditionUser=!root Service LockPersonality=yes
View file
_service:download_url:pipewire-1.4.0.tar.bz2/src/daemon/systemd/user/pipewire.socket -> _service:download_url:pipewire-1.4.1.tar.bz2/src/daemon/systemd/user/pipewire.socket
Changed
@@ -1,5 +1,6 @@ Unit Description=PipeWire Multimedia System Sockets +ConditionUser=!root Socket Priority=6
View file
_service:download_url:pipewire-1.4.0.tar.bz2/src/modules/meson.build -> _service:download_url:pipewire-1.4.1.tar.bz2/src/modules/meson.build
Changed
@@ -620,7 +620,7 @@ endif summary({'raop-sink (requires OpenSSL)': build_module_raop}, bool_yn: true, section: 'Optional Modules') -roc_dep = dependency('roc', version: '>= 0.3.0', required: get_option('roc')) +roc_dep = dependency('roc', version: '>= 0.4.0', required: get_option('roc')) summary({'ROC': roc_dep.found()}, bool_yn: true, section: 'Streaming between daemons') pipewire_module_rtp_source = shared_library('pipewire-module-rtp-source',
View file
_service:download_url:pipewire-1.4.0.tar.bz2/src/pipewire/loop.h -> _service:download_url:pipewire-1.4.1.tar.bz2/src/pipewire/loop.h
Changed
@@ -141,7 +141,7 @@ PW_API_LOOP_IMPL void pw_loop_destroy_source(struct pw_loop *object, struct spa_source *source) { - return spa_loop_utils_destroy_source(object->utils, source); + spa_loop_utils_destroy_source(object->utils, source); } /**
View file
_service:download_url:pipewire-1.4.0.tar.bz2/src/pipewire/stream.c -> _service:download_url:pipewire-1.4.1.tar.bz2/src/pipewire/stream.c
Changed
@@ -446,7 +446,7 @@ if (impl->n_buffers == 0 || (impl->direction == SPA_DIRECTION_OUTPUT && update_requested(impl) <= 0)) return; - if (impl->rt_callbacks.funcs) + if (impl->rt_callbacks.funcs && !impl->disconnecting) spa_callbacks_call_fast(&impl->rt_callbacks, struct pw_stream_events, process, 0); }
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
.