Projects
Essentials
pipewire-aptx
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 58
View file
pipewire-aptx.changes
Changed
@@ -1,4 +1,9 @@ ------------------------------------------------------------------- +Mon Sep 15 15:03:26 UTC 2025 - Bjørn Lie <zaitor@opensuse.org> + +- Update to version 1.4.8 + +------------------------------------------------------------------- Thu Aug 7 08:53:42 UTC 2025 - Bjørn Lie <zaitor@opensuse.org> - Update to version 1.4.7
View file
pipewire-aptx.spec
Changed
@@ -8,7 +8,7 @@ %define minimum_version 1.4.0 Name: pipewire-aptx -Version: 1.4.7 +Version: 1.4.8 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.7/pipewire-1.4.7.tar.bz2</param> + <param name="path">/pipewire/pipewire/-/archive/1.4.8/pipewire-1.4.8.tar.bz2</param> </service> </services> \ No newline at end of file
View file
_service:download_url:pipewire-1.4.7.tar.bz2/NEWS -> _service:download_url:pipewire-1.4.8.tar.bz2/NEWS
Changed
@@ -1,3 +1,50 @@ +# PipeWire 1.4.8 (2025-09-11) + +This is a bugfix release that is API and ABI compatible with +previous 1.x releases. + +## Highlights + - Low latency for Firewire devices using the ALSA drivers. + - Fix potential wrong pointers in memory mappings. + - Improve compatibility with Apple Home Pod Minis. + - JACK now implements the rename_callback. + - Various improvements and bug fixes. + + +## PipeWire + - Make sure we can only queue buffers that were previously dequeued, + to avoid some API misuse. + - Fix potential wrong pointers in memory mappings. (#4884) + - Improve the node unprepare function. (#4840) + +## Modules + - Add fp_sap25 encryption to the ROAP module for compatibility with + Apple Home Pod Minis. + - Write a correct ALAC end tag in RAOP. (#4853) + - Avoid VBAN problems with too long session names. + - Fix a potential crash in the link-factory. (#4691) + +## SPA + - Show correct values in the ALSA api.alsa.period-num property. + - Add better support for Razer BlackShark v3. + - Use only 3 periods in ALSA when in Pro-Audio mode. This gives + better latency on some drivers. Also set the period count before + the period size for improved compatibility. (#4785) + - Force IRQ mode for firewire devices in pro-audio mode even if + there are multiple capture and playback devices. + - Add a new flag in the sync_timeline metadata to track if a + release_point will be signaled or not. (#4885) + +## JACK + - Support the rename_callback. (#4761) + +## Tools + - Fix the -C option in pw-dump. + - Log more info from sndfile when opening a file failed. + + +Older versions: + # PipeWire 1.4.7 (2025-07-23) This is a bugfix release that is API and ABI compatible with @@ -29,7 +76,6 @@ ## GStreamer - Add some format validations. - # PipeWire 1.4.6 (2025-06-27) This is a bugfix release that is API and ABI compatible with @@ -61,9 +107,6 @@ ## GStreamer - Fix a refcount issue in the device provider. - -Older versions: - # PipeWire 1.4.5 (2025-06-04) This is a quick bugfix release that is API and ABI compatible with
View file
_service:download_url:pipewire-1.4.7.tar.bz2/meson.build -> _service:download_url:pipewire-1.4.8.tar.bz2/meson.build
Changed
@@ -1,5 +1,5 @@ project('pipewire', 'c' , - version : '1.4.7', + version : '1.4.8', 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.7.tar.bz2/pipewire-jack/src/pipewire-jack.c -> _service:download_url:pipewire-1.4.8.tar.bz2/pipewire-jack/src/pipewire-jack.c
Changed
@@ -102,6 +102,7 @@ #define NOTIFY_TYPE_SHUTDOWN ((7<<4)|NOTIFY_ACTIVE_FLAG) #define NOTIFY_TYPE_LATENCY ((8<<4)|NOTIFY_ACTIVE_FLAG) #define NOTIFY_TYPE_TOTAL_LATENCY ((9<<4)|NOTIFY_ACTIVE_FLAG) +#define NOTIFY_TYPE_PORT_RENAME ((10<<4)|NOTIFY_ACTIVE_FLAG) int type; struct object *object; int arg1; @@ -171,6 +172,7 @@ } port_link; struct { unsigned long flags; + char old_nameREAL_JACK_PORT_NAME_SIZE+1; char nameREAL_JACK_PORT_NAME_SIZE+1; char alias1REAL_JACK_PORT_NAME_SIZE+1; char alias2REAL_JACK_PORT_NAME_SIZE+1; @@ -1083,6 +1085,16 @@ notify->arg1, c->portregistration_arg); break; + case NOTIFY_TYPE_PORT_RENAME: + if (o->registered != notify->arg1) + break; + pw_log_debug("%p: port rename %u %s->%s", c, o->serial, + o->port.old_name, o->port.name); + do_callback(c, rename_callback, c->active, + o->serial, + o->port.old_name, o->port.name, + c->rename_arg); + break; case NOTIFY_TYPE_CONNECT: if (o->registered == notify->arg1) break; @@ -1183,6 +1195,9 @@ emit = c->portregistration_callback != NULL && o != NULL; o->visible = arg1; break; + case NOTIFY_TYPE_PORT_RENAME: + emit = c->rename_callback != NULL && o != NULL; + break; case NOTIFY_TYPE_CONNECT: emit = c->connect_callback != NULL && o != NULL; break; @@ -3674,6 +3689,67 @@ .info = node_info, }; +#define FILTER_NAME " ().:*$" +#define FILTER_PORT " ().*$" + +static void filter_name(char *str, const char *filter, char filter_char) +{ + char *p; + for (p = str; *p; p++) { + if (strchr(filter, *p) != NULL) + *p = filter_char; + } +} + +static int update_port_name(struct object *o, const char *name) +{ + struct object *ot = o->port.node, *op; + struct client *c = o->client; + char tmpREAL_JACK_PORT_NAME_SIZE+1; + char port_nameREAL_JACK_PORT_NAME_SIZE+1; + + if (o->port.is_monitor && !c->merge_monitor) + snprintf(tmp, sizeof(tmp), "%.*s%s:%s", + (int)(JACK_CLIENT_NAME_SIZE-(sizeof(MONITOR_EXT)-1)), + ot->node.name, MONITOR_EXT, name); + else + snprintf(tmp, sizeof(tmp), "%s:%s", ot->node.name, name); + + if (c->filter_name) + filter_name(tmp, FILTER_PORT, c->filter_char); + + op = find_port_by_name(c, tmp); + if (op != NULL && op != o) + snprintf(port_name, sizeof(port_name), "%.*s-%u", + (int)(sizeof(tmp)-11), tmp, o->serial); + else + snprintf(port_name, sizeof(port_name), "%s", tmp); + + if (spa_streq(port_name, o->port.name)) + return 0; + + strcpy(o->port.old_name, o->port.name); + strcpy(o->port.name, port_name); + return 1; +} + +static void port_info(void *data, const struct pw_port_info *info) +{ + struct object *o = data; + struct client *c = o->client; + + if (info->change_mask & PW_PORT_CHANGE_MASK_PROPS) { + const char *str = spa_dict_lookup(info->props, PW_KEY_PORT_NAME); + if (str != NULL) { + if (update_port_name(o, str) > 0) { + pw_log_info("%p: port rename %u %s->%s", c, o->serial, + o->port.old_name, o->port.name); + queue_notify(c, NOTIFY_TYPE_PORT_RENAME, o, 1, NULL); + } + } + } +} + static void port_param(void *data, int seq, uint32_t id, uint32_t index, uint32_t next, const struct spa_pod *param) @@ -3696,27 +3772,16 @@ static const struct pw_port_events port_events = { PW_VERSION_PORT_EVENTS, + .info = port_info, .param = port_param, }; -#define FILTER_NAME " ().:*$" -#define FILTER_PORT " ().*$" - -static void filter_name(char *str, const char *filter, char filter_char) -{ - char *p; - for (p = str; *p; p++) { - if (strchr(filter, *p) != NULL) - *p = filter_char; - } -} - static void registry_event_global(void *data, uint32_t id, uint32_t permissions, const char *type, uint32_t version, const struct spa_dict *props) { struct client *c = (struct client *) data; - struct object *o, *ot, *op; + struct object *o, *ot; const char *str; bool do_emit = true, do_sync = false; uint32_t serial; @@ -3837,6 +3902,7 @@ uint32_t node_id; bool is_monitor = false; char tmpREAL_JACK_PORT_NAME_SIZE+1; + const char *name; if ((str = spa_dict_lookup(props, PW_KEY_FORMAT_DSP)) == NULL) str = "other"; @@ -3852,7 +3918,7 @@ spa_strstartswith(str, "jack:flags:")) flags = atoi(str+11); - if ((str = spa_dict_lookup(props, PW_KEY_PORT_NAME)) == NULL) + if ((name = spa_dict_lookup(props, PW_KEY_PORT_NAME)) == NULL) goto exit; if (type_id == TYPE_ID_UMP && c->flag_midi2) @@ -3888,7 +3954,7 @@ o = NULL; if (node_id == c->node_id) { - snprintf(tmp, sizeof(tmp), "%s:%s", c->name, str); + snprintf(tmp, sizeof(tmp), "%s:%s", c->name, name); o = find_port_by_name(c, tmp); if (o != NULL) pw_log_info("%p: %s found our port %p", c, tmp, o); @@ -3906,6 +3972,7 @@ o->port.node = ot; o->port.latencySPA_DIRECTION_INPUT = SPA_LATENCY_INFO(SPA_DIRECTION_INPUT); o->port.latencySPA_DIRECTION_OUTPUT = SPA_LATENCY_INFO(SPA_DIRECTION_OUTPUT); + o->port.type_id = type_id; do_emit = node_is_active(c, ot); @@ -3927,27 +3994,12 @@ pthread_mutex_lock(&c->context.lock); spa_list_append(&c->context.objects, &o->link); pthread_mutex_unlock(&c->context.lock); - - if (is_monitor && !c->merge_monitor) - snprintf(tmp, sizeof(tmp), "%.*s%s:%s", - (int)(JACK_CLIENT_NAME_SIZE-(sizeof(MONITOR_EXT)-1)), - ot->node.name, MONITOR_EXT, str); - else - snprintf(tmp, sizeof(tmp), "%s:%s", ot->node.name, str); - - if (c->filter_name) - filter_name(tmp, FILTER_PORT, c->filter_char); - - op = find_port_by_name(c, tmp); - if (op != NULL) - snprintf(o->port.name, sizeof(o->port.name), "%.*s-%u", - (int)(sizeof(tmp)-11), tmp, serial); - else - snprintf(o->port.name, sizeof(o->port.name), "%s", tmp); - - o->port.type_id = type_id; } + o->port.flags = flags; + o->port.node_id = node_id; + o->port.is_monitor = is_monitor; + if (c->fill_aliases) { if ((str = spa_dict_lookup(props, PW_KEY_OBJECT_PATH)) != NULL) snprintf(o->port.alias1, sizeof(o->port.alias1), "%s", str); @@ -3955,7 +4007,6 @@ if ((str = spa_dict_lookup(props, PW_KEY_PORT_ALIAS)) != NULL) snprintf(o->port.alias2, sizeof(o->port.alias2), "%s", str); } - if ((str = spa_dict_lookup(props, PW_KEY_PORT_ID)) != NULL) { o->port.system_id = atoi(str); snprintf(o->port.system, sizeof(o->port.system), "system:%s_%d", @@ -3964,9 +4015,8 @@ o->port.system_id+1); } - o->port.flags = flags; - o->port.node_id = node_id; - o->port.is_monitor = is_monitor; + if (node_id != c->node_id) + update_port_name(o, name); pw_log_debug("%p: %p add port %d name:%s %d", c, o, id, o->port.name, type_id);
View file
_service:download_url:pipewire-1.4.7.tar.bz2/pipewire-v4l2/src/pipewire-v4l2.c -> _service:download_url:pipewire-1.4.8.tar.bz2/pipewire-v4l2/src/pipewire-v4l2.c
Changed
@@ -772,6 +772,19 @@ return do_dup(oldfd, FD_MAP_DUP); } +/* Deferred PipeWire init (called on first device access) */ +static void pipewire_init_func(void) +{ + pw_init(NULL, NULL); + PW_LOG_TOPIC_INIT(v4l2_log_topic); +} + +static void ensure_pipewire_init(void) +{ + static pthread_once_t pipewire_once = PTHREAD_ONCE_INIT; + pthread_once(&pipewire_once, pipewire_init_func); +} + static int v4l2_openat(int dirfd, const char *path, int oflag, mode_t mode) { int res, flags; @@ -795,6 +808,8 @@ if (passthrough) return globals.old_fops.openat(dirfd, path, oflag, mode); + ensure_pipewire_init(); + pw_log_info("path:%s oflag:%d mode:%d", path, oflag, mode); if ((file = find_file_by_dev(dev_id)) != NULL) { @@ -1385,7 +1400,6 @@ spa_list_for_each(p, &g->param_list, link) { const struct format_info *fi; uint32_t media_type, media_subtype, format; - struct spa_rectangle size; if (p->id != SPA_PARAM_EnumFormat || p->param == NULL) continue; @@ -1409,22 +1423,96 @@ if (fi->fourcc != arg->pixel_format) continue; - if (spa_pod_parse_object(p->param, - SPA_TYPE_OBJECT_Format, NULL, - SPA_FORMAT_VIDEO_size, SPA_POD_Rectangle(&size)) < 0) + + const struct spa_pod_prop *size_prop = spa_pod_find_prop(p->param, NULL, SPA_FORMAT_VIDEO_size); + if (!size_prop) continue; - arg->type = V4L2_FRMSIZE_TYPE_DISCRETE; - arg->discrete.width = size.width; - arg->discrete.height = size.height; + uint32_t n_sizes, choice; + const struct spa_pod *size_pods = spa_pod_get_values(&size_prop->value, &n_sizes, &choice); + if (!size_pods || n_sizes <= 0) + continue; + + const struct spa_rectangle *sizes = SPA_POD_BODY_CONST(size_pods); + if (size_pods->type != SPA_TYPE_Rectangle || size_pods->size != sizeof(*sizes)) + continue; + + switch (choice) { + case SPA_CHOICE_Enum: + n_sizes -= 1; + sizes += 1; + SPA_FALLTHROUGH; + case SPA_CHOICE_None: + arg->type = V4L2_FRMSIZE_TYPE_DISCRETE; + + for (size_t i = 0; i < n_sizes; i++, count++) { + arg->discrete.width = sizesi.width; + arg->discrete.height = sizesi.height; + + pw_log_debug("count:%u %.4s %ux%u", count, (char*)&fi->fourcc, + arg->discrete.width, arg->discrete.height); + + if (count == arg->index) { + found = true; + break; + } + } - pw_log_debug("count:%d %.4s %dx%d", count, (char*)&fi->fourcc, - size.width, size.height); - if (count == arg->index) { - found = true; break; + case SPA_CHOICE_Range: + if (n_sizes < 3) + continue; + + arg->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; + arg->stepwise.min_width = sizes1.width; + arg->stepwise.min_height = sizes1.height; + arg->stepwise.max_width = sizes2.width; + arg->stepwise.max_height = sizes2.height; + arg->stepwise.step_width = arg->stepwise.step_height = 1; + + pw_log_debug("count:%u %.4s (%ux%u)-(%ux%u)", count, (char*)&fi->fourcc, + arg->stepwise.min_width, arg->stepwise.min_height, + arg->stepwise.max_width, arg->stepwise.max_height); + + if (count == arg->index) { + found = true; + break; + } + + count++; + + break; + case SPA_CHOICE_Step: + if (n_sizes < 4) + continue; + + arg->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; + arg->stepwise.min_width = sizes1.width; + arg->stepwise.min_height = sizes1.height; + arg->stepwise.max_width = sizes2.width; + arg->stepwise.max_height = sizes2.height; + arg->stepwise.step_width = sizes3.width; + arg->stepwise.step_height = sizes3.height; + + pw_log_debug("count:%u %.4s (%ux%u)-(%ux%u)/(+%u,%u)", count, (char*)&fi->fourcc, + arg->stepwise.min_width, arg->stepwise.min_height, + arg->stepwise.min_width, arg->stepwise.min_height, + arg->stepwise.step_width, arg->stepwise.step_height); + + if (count == arg->index) { + found = true; + break; + } + + count++; + + break; + default: + continue; } - count++; + + if (found) + break; } pw_thread_loop_unlock(file->loop); @@ -2100,7 +2188,7 @@ { V4L2_CID_SATURATION, SPA_PROP_saturation }, { V4L2_CID_HUE, SPA_PROP_hue }, { V4L2_CID_GAMMA, SPA_PROP_gamma }, - { V4L2_CID_EXPOSURE, SPA_PROP_exposure }, + { V4L2_CID_EXPOSURE_ABSOLUTE, SPA_PROP_exposure }, { V4L2_CID_GAIN, SPA_PROP_gain }, { V4L2_CID_SHARPNESS, SPA_PROP_sharpness }, }; @@ -2563,10 +2651,14 @@ globals.old_fops.ioctl = dlsym(RTLD_NEXT, "ioctl"); globals.old_fops.mmap = dlsym(RTLD_NEXT, "mmap64"); globals.old_fops.munmap = dlsym(RTLD_NEXT, "munmap"); - - pw_init(NULL, NULL); - PW_LOG_TOPIC_INIT(v4l2_log_topic); - + /* NOTE: + * We avoid calling pw_init() here (constructor/early init path) because + * that can deadlock in certain host processes (e.g. Zoom >= 5.0) when + * the preload causes PipeWire initialisation to run too early. + * + * PipeWire initialisation (pw_init + PW_LOG_TOPIC_INIT) is deferred + * to ensure it runs on-demand in the first actual V4L2 open call. + */ pthread_mutex_init(&globals.lock, NULL); pw_array_init(&globals.file_maps, 1024); pw_array_init(&globals.fd_maps, 256);
View file
_service:download_url:pipewire-1.4.7.tar.bz2/spa/include/spa/buffer/meta.h -> _service:download_url:pipewire-1.4.8.tar.bz2/spa/include/spa/buffer/meta.h
Changed
@@ -184,6 +184,9 @@ * layout with 2 extra fds. */ struct spa_meta_sync_timeline { +#define SPA_META_SYNC_TIMELINE_UNSCHEDULED_RELEASE (1<<0) /**< this flag is set by the producer and cleared + * by the consumer when it promises to signal + * the release point */ uint32_t flags; uint32_t padding; uint64_t acquire_point; /**< the timeline acquire point, this is when the data
View file
_service:download_url:pipewire-1.4.7.tar.bz2/spa/include/spa/control/ump-utils.h -> _service:download_url:pipewire-1.4.8.tar.bz2/spa/include/spa/control/ump-utils.h
Changed
@@ -197,15 +197,15 @@ break; case 0xf2: to_consume = 3; - prefix = 0x10000000; + prefix |= 0x10000000; break; case 0xf1: case 0xf3: to_consume = 2; - prefix = 0x10000000; + prefix |= 0x10000000; break; case 0xf4 ... 0xff: to_consume = 1; - prefix = 0x10000000; + prefix |= 0x10000000; break; default: return -EIO;
View file
_service:download_url:pipewire-1.4.7.tar.bz2/spa/include/spa/param/audio/raw-types.h -> _service:download_url:pipewire-1.4.8.tar.bz2/spa/include/spa/param/audio/raw-types.h
Changed
@@ -192,7 +192,7 @@ { SPA_AUDIO_CHANNEL_TFRC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TFRC", NULL }, { SPA_AUDIO_CHANNEL_TSL, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TSL", NULL }, { SPA_AUDIO_CHANNEL_TSR, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "TSR", NULL }, - { SPA_AUDIO_CHANNEL_LLFE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "LLFR", NULL }, + { SPA_AUDIO_CHANNEL_LLFE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "LLFE", NULL }, { SPA_AUDIO_CHANNEL_RLFE, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "RLFE", NULL }, { SPA_AUDIO_CHANNEL_BC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "BC", NULL }, { SPA_AUDIO_CHANNEL_BLC, SPA_TYPE_Int, SPA_TYPE_INFO_AUDIO_CHANNEL_BASE "BLC", NULL },
View file
_service:download_url:pipewire-1.4.7.tar.bz2/spa/plugins/alsa/90-pipewire-alsa.rules -> _service:download_url:pipewire-1.4.8.tar.bz2/spa/plugins/alsa/90-pipewire-alsa.rules
Changed
@@ -137,8 +137,13 @@ ATTRS{idVendor}=="9886", ATTRS{idProduct}=="0038", ENV{ACP_PROFILE_SET}="usb-gaming-headset.conf" # ID 9886:0045 is for the Astro A20 Gen2 ATTRS{idVendor}=="9886", ATTRS{idProduct}=="0045", ENV{ACP_PROFILE_SET}="usb-gaming-headset.conf" + # ID 1532:0520 is for the Razer Kraken Tournament Edition ATTRS{idVendor}=="1532", ATTRS{idProduct}=="0520", ENV{ACP_PROFILE_SET}="usb-gaming-headset.conf" +# ID 1532:0579 is Razer BlackShark v3 (usb direct to headset) +ATTRS{idVendor}=="1532", ATTRS{idProduct}=="0579", ENV{ACP_PROFILE_SET}="usb-gaming-headset.conf" +# ID 1532:057a is Razer BlackShark v3 (2.4GHz dongle) +ATTRS{idVendor}=="1532", ATTRS{idProduct}=="057a", ENV{ACP_PROFILE_SET}="usb-gaming-headset.conf" # ID 1038:1250 is for the Arctis 5
View file
_service:download_url:pipewire-1.4.7.tar.bz2/spa/plugins/alsa/acp/acp.c -> _service:download_url:pipewire-1.4.8.tar.bz2/spa/plugins/alsa/acp/acp.c
Changed
@@ -453,7 +453,14 @@ } snd_ctl_close(ctl_hndl); - if (n_capture == 1 && n_playback == 1) { + /* FireWire ALSA driver latency is determined by the buffer size and not the + * period. Timer-based scheduling is then not really useful on these devices as + * the latency is fixed. Enable IRQ scheduling unconditionally for these devices, + * so that controlling the latency works properly. + */ + bool is_firewire = spa_streq(pa_proplist_gets(impl->proplist, "device.bus"), "firewire"); + + if ((n_capture == 1 && n_playback == 1) || is_firewire) { PA_IDXSET_FOREACH(m, ap->output_mappings, idx) { pa_proplist_setf(m->output_proplist, "node.group", "pro-audio-%u", index); pa_proplist_setf(m->output_proplist, "node.link-group", "pro-audio-%u", index);
View file
_service:download_url:pipewire-1.4.7.tar.bz2/spa/plugins/alsa/alsa-acp-device.c -> _service:download_url:pipewire-1.4.8.tar.bz2/spa/plugins/alsa/alsa-acp-device.c
Changed
@@ -160,7 +160,7 @@ char codecs512; struct spa_device_object_info info; struct acp_card *card = this->card; - const char *stream, *card_id; + const char *stream, *card_id, *bus; info = SPA_DEVICE_OBJECT_INFO_INIT(); info.type = SPA_TYPE_INTERFACE_Node; @@ -175,7 +175,7 @@ info.change_mask = SPA_DEVICE_OBJECT_CHANGE_MASK_PROPS; - items = alloca((dev->props.n_items + 11) * sizeof(*items)); + items = alloca((dev->props.n_items + 12) * sizeof(*items)); n_items = 0; snprintf(card_index, sizeof(card_index), "%d", card->index); @@ -193,6 +193,8 @@ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_API_ALSA_PCM_STREAM, stream); itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_PORT_GROUP, stream); itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_ICON_NAME, "audio-card-analog"); + bus = acp_dict_lookup(&card->props, SPA_KEY_DEVICE_BUS); + itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_BUS, bus); snprintf(channels, sizeof(channels), "%d", dev->format.channels); itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_AUDIO_CHANNELS, channels);
View file
_service:download_url:pipewire-1.4.7.tar.bz2/spa/plugins/alsa/alsa-pcm.c -> _service:download_url:pipewire-1.4.8.tar.bz2/spa/plugins/alsa/alsa-pcm.c
Changed
@@ -1005,6 +1005,8 @@ state->num_bind_ctls = i; /* We'll do the actual binding after checking the card exists */ + } else if (spa_streq(k, SPA_KEY_DEVICE_BUS)) { + state->is_firewire = spa_streq(s, "firewire"); } else { alsa_set_param(state, k, s); } @@ -2052,6 +2054,13 @@ if (rate != 0 && state->rate != 0) latency = SPA_SCALE32_UP(latency, rate, state->rate); + if (state->is_firewire) { + /* XXX: For ALSA FireWire drivers, unlike for other ALSA drivers, buffer size + * XXX: contributes extra latency (as of kernel 6.16). + */ + latency += state->buffer_frames; + } + state->latencystate->port_direction.min_rate = state->latencystate->port_direction.max_rate = latency; } @@ -2326,6 +2335,35 @@ } } + if (state->default_period_num != 0) { + /* period number given use that */ + periods = state->default_period_num; + } else if (state->disable_tsched) { + /* IRQ mode, use 3 periods. This is a bit of a workaround + * for Firewire devices, which seem to only work with 3 periods. + * For PipeWire it does not actually matter how many periods + * are used, we will always keep 1 filled, so we can work fine + * with anything from 2 periods to MAX. */ + periods = 3; + } else { + periods = UINT_MAX; + } + + if (state->default_period_size == 0) { + /* Some devices (FireWire) don't produce audio if period number is too + * small, so force a minimum. This will restrict possible period sizes if + * the device has small buffer (like FireWire), so force it only if + * period size was not set manually. + */ + snd_pcm_uframes_t period_size_max; + unsigned int periods_min = (periods == UINT_MAX) ? 3 : periods; + + CHECK(snd_pcm_hw_params_set_periods_min(hndl, params, &periods_min, &dir), "set_periods_min"); + CHECK(snd_pcm_hw_params_get_period_size_max(params, &period_size_max, &dir), "get_period_size_max"); + if (period_size > period_size_max) + period_size = SPA_MIN(period_size, flp2(period_size_max)); + } + CHECK(snd_pcm_hw_params_set_period_size_near(hndl, params, &period_size, &dir), "set_period_size_near"); if (period_size == 0) { @@ -2335,8 +2373,7 @@ state->period_frames = period_size; - if (state->default_period_num != 0) { - periods = state->default_period_num; + if (periods != UINT_MAX) { CHECK(snd_pcm_hw_params_set_periods_near(hndl, params, &periods, &dir), "set_periods"); state->buffer_frames = period_size * periods; } else { @@ -3866,7 +3903,7 @@ itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_MEDIA_CLASS, state->props.media_class); itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_DRIVER, "true"); - if (state->have_format) + if (state->have_format && !state->disable_tsched) snprintf(latency, sizeof(latency), "%lu/%d", state->buffer_frames / (2 * state->frame_scale), state->rate); itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_MAX_LATENCY, latency0 ? latency : NULL); @@ -3881,7 +3918,7 @@ snprintf(nperiods, sizeof(nperiods), "%lu", state->period_frames != 0 ? state->buffer_frames / state->period_frames : 0); else if (state->default_period_num) - snprintf(nperiods, sizeof(nperiods), "%u", state->default_period_size); + snprintf(nperiods, sizeof(nperiods), "%u", state->default_period_num); itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.period-num", nperiods0 ? nperiods : NULL); if (state->have_format)
View file
_service:download_url:pipewire-1.4.7.tar.bz2/spa/plugins/alsa/alsa-pcm.h -> _service:download_url:pipewire-1.4.8.tar.bz2/spa/plugins/alsa/alsa-pcm.h
Changed
@@ -155,6 +155,7 @@ unsigned int disable_batch:1; unsigned int disable_tsched:1; unsigned int is_split_parent:1; + unsigned int is_firewire:1; char clock_name64; uint32_t quantum_limit;
View file
_service:download_url:pipewire-1.4.7.tar.bz2/spa/plugins/audioconvert/peaks-ops.h -> _service:download_url:pipewire-1.4.8.tar.bz2/spa/plugins/audioconvert/peaks-ops.h
Changed
@@ -6,6 +6,11 @@ #include <stdio.h> #include <spa/utils/defs.h> +#include <spa/support/log.h> + +#undef SPA_LOG_TOPIC_DEFAULT +#define SPA_LOG_TOPIC_DEFAULT &resample_log_topic +extern struct spa_log_topic resample_log_topic; struct peaks { uint32_t cpu_flags;
View file
_service:download_url:pipewire-1.4.7.tar.bz2/spa/plugins/audioconvert/resample-native-impl.h -> _service:download_url:pipewire-1.4.8.tar.bz2/spa/plugins/audioconvert/resample-native-impl.h
Changed
@@ -5,9 +5,14 @@ #include <math.h> #include <spa/utils/defs.h> +#include <spa/support/log.h> #include "resample.h" +#undef SPA_LOG_TOPIC_DEFAULT +#define SPA_LOG_TOPIC_DEFAULT &resample_log_topic +extern struct spa_log_topic resample_log_topic; + typedef void (*resample_func_t)(struct resample *r, const void * SPA_RESTRICT src, uint32_t ioffs, uint32_t *in_len, void * SPA_RESTRICT dst, uint32_t ooffs, uint32_t *out_len);
View file
_service:download_url:pipewire-1.4.7.tar.bz2/spa/plugins/audioconvert/resample-native.c -> _service:download_url:pipewire-1.4.8.tar.bz2/spa/plugins/audioconvert/resample-native.c
Changed
@@ -11,6 +11,8 @@ #include "resample-native-precomp.h" #endif +SPA_LOG_TOPIC_DEFINE(resample_log_topic, "spa.resample"); + struct quality { uint32_t n_taps; double cutoff;
View file
_service:download_url:pipewire-1.4.7.tar.bz2/spa/plugins/audiomixer/audiomixer.c -> _service:download_url:pipewire-1.4.8.tar.bz2/spa/plugins/audiomixer/audiomixer.c
Changed
@@ -343,7 +343,7 @@ SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), - SPA_FORMAT_AUDIO_format, SPA_POD_CHOICE_ENUM_Int(12, + SPA_FORMAT_AUDIO_format, SPA_POD_CHOICE_ENUM_Id(12, SPA_AUDIO_FORMAT_S8, SPA_AUDIO_FORMAT_U8, SPA_AUDIO_FORMAT_S16, @@ -921,7 +921,8 @@ for (i = 0; i < MAX_PORTS; i++) free(this->in_portsi); - mix_ops_free(&this->ops); + if (this->ops.free) + mix_ops_free(&this->ops); return 0; } @@ -984,6 +985,7 @@ this->info.max_output_ports = 1; this->info.change_mask |= SPA_NODE_CHANGE_MASK_FLAGS; this->info.flags = SPA_NODE_FLAG_RT | SPA_NODE_FLAG_IN_DYNAMIC_PORTS; + this->info_all = this->info.change_mask; port = GET_OUT_PORT(this, 0); port->valid = true; @@ -993,6 +995,7 @@ port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS; port->info.flags = SPA_PORT_FLAG_DYNAMIC_DATA; port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; + port->info_all = port->info.change_mask; port->params0 = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ); port->params1 = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ); port->params2 = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
View file
_service:download_url:pipewire-1.4.7.tar.bz2/spa/plugins/audiomixer/mixer-dsp.c -> _service:download_url:pipewire-1.4.8.tar.bz2/spa/plugins/audiomixer/mixer-dsp.c
Changed
@@ -921,6 +921,7 @@ this->info.max_output_ports = 1; this->info.change_mask |= SPA_NODE_CHANGE_MASK_FLAGS; this->info.flags = SPA_NODE_FLAG_RT | SPA_NODE_FLAG_IN_DYNAMIC_PORTS; + this->info_all = this->info.change_mask; port = GET_OUT_PORT(this, 0); port->valid = true; @@ -930,6 +931,7 @@ port->info.change_mask |= SPA_PORT_CHANGE_MASK_FLAGS; port->info.flags = SPA_PORT_FLAG_DYNAMIC_DATA; port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; + port->info_all = port->info.change_mask; port->params0 = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ); port->params1 = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ); port->params2 = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);
View file
_service:download_url:pipewire-1.4.7.tar.bz2/spa/plugins/v4l2/v4l2-utils.c -> _service:download_url:pipewire-1.4.8.tar.bz2/spa/plugins/v4l2/v4l2-utils.c
Changed
@@ -1132,7 +1132,7 @@ { V4L2_CID_SATURATION, SPA_PROP_saturation }, { V4L2_CID_HUE, SPA_PROP_hue }, { V4L2_CID_GAMMA, SPA_PROP_gamma }, - { V4L2_CID_EXPOSURE, SPA_PROP_exposure }, + { V4L2_CID_EXPOSURE_ABSOLUTE, SPA_PROP_exposure }, { V4L2_CID_GAIN, SPA_PROP_gain }, { V4L2_CID_SHARPNESS, SPA_PROP_sharpness }, };
View file
_service:download_url:pipewire-1.4.7.tar.bz2/src/daemon/systemd/user/pipewire.service.in -> _service:download_url:pipewire-1.4.8.tar.bz2/src/daemon/systemd/user/pipewire.service.in
Changed
@@ -22,7 +22,7 @@ NoNewPrivileges=yes RestrictNamespaces=yes SystemCallArchitectures=native -SystemCallFilter=@system-service +SystemCallFilter=@system-service mincore Type=simple ExecStart=@PW_BINARY@ Restart=on-failure
View file
_service:download_url:pipewire-1.4.7.tar.bz2/src/modules/module-link-factory.c -> _service:download_url:pipewire-1.4.8.tar.bz2/src/modules/module-link-factory.c
Changed
@@ -193,8 +193,7 @@ static void global_destroy(void *data) { struct link_data *ld = data; - struct factory_data *d = ld->data; - pw_work_queue_cancel(d->work, ld, SPA_ID_INVALID); + spa_hook_remove(&ld->global_listener); ld->global = NULL; } @@ -213,6 +212,7 @@ spa_hook_remove(&ld->global_listener); if (ld->resource) spa_hook_remove(&ld->resource_listener); + pw_work_queue_cancel(ld->data->work, ld, SPA_ID_INVALID); } static void link_initialized(void *data)
View file
_service:download_url:pipewire-1.4.7.tar.bz2/src/modules/module-raop-discover.c -> _service:download_url:pipewire-1.4.8.tar.bz2/src/modules/module-raop-discover.c
Changed
@@ -71,7 +71,7 @@ * #raop.domain = "" * #raop.device = "" * #raop.transport = "udp" | "tcp" - * #raop.encryption.type = "RSA" | "auth_setup" | "none" + * #raop.encryption.type = "none" | "RSA" | "auth_setup" | "fp_sap25" * #raop.audio.codec = "PCM" | "ALAC" | "AAC" | "AAC-ELD" * #audio.channels = 2 * #audio.format = "S16" | "S24" | "S32" @@ -244,10 +244,12 @@ * 3 = FairPlay, * 4 = MFiSAP (/auth-setup), * 5 = FairPlay SAPv2.5 */ - if (str_in_list(value, ",", "1")) - value = "RSA"; + if (str_in_list(value, ",", "5")) + value = "fp_sap25"; else if (str_in_list(value, ",", "4")) value = "auth_setup"; + else if (str_in_list(value, ",", "1")) + value = "RSA"; else value = "none"; pw_properties_set(props, "raop.encryption.type", value);
View file
_service:download_url:pipewire-1.4.7.tar.bz2/src/modules/module-raop-sink.c -> _service:download_url:pipewire-1.4.8.tar.bz2/src/modules/module-raop-sink.c
Changed
@@ -197,6 +197,7 @@ CRYPTO_NONE, CRYPTO_RSA, CRYPTO_AUTH_SETUP, + CRYPTO_FP_SAP25, }; enum { CODEC_PCM, @@ -442,6 +443,7 @@ bit_writer(&bp, &bpos, *(d + 2), 8); d += 4; } + bit_writer(&bp, &bpos, 7, 3); /* end tag */ return bp - b + 1; } @@ -892,9 +894,9 @@ interval.tv_nsec = 0; // feedback timer is only needed for auth_setup encryption - if (impl->encryption == CRYPTO_AUTH_SETUP && !impl->feedback_timer) { - - impl->feedback_timer = pw_loop_add_timer(impl->loop, rtsp_do_post_feedback, impl); + if (impl->encryption == CRYPTO_FP_SAP25) { + if (!impl->feedback_timer) + impl->feedback_timer = pw_loop_add_timer(impl->loop, rtsp_do_post_feedback, impl); pw_loop_update_timer(impl->loop, impl->feedback_timer, &timeout, &interval, false); } @@ -910,7 +912,6 @@ rtp_stream_set_first(impl->stream); impl->sync = 0; - impl->sync_period = impl->rate / (impl->mtu / impl->stride); impl->recording = true; rtsp_send_volume(impl); @@ -1239,6 +1240,7 @@ switch (impl->encryption) { case CRYPTO_NONE: + case CRYPTO_FP_SAP25: sdp = spa_aprintf("v=0\r\n" "o=iTunes %s 0 IN IP%d %s\r\n" "s=iTunes\r\n" @@ -1252,6 +1254,7 @@ if (!sdp) return -errno; break; + case CRYPTO_AUTH_SETUP: sdp = spa_aprintf("v=0\r\n" "o=iTunes %s 0 IN IP%d %s\r\n" @@ -1877,6 +1880,8 @@ impl->encryption = CRYPTO_RSA; else if (spa_streq(str, "auth_setup")) impl->encryption = CRYPTO_AUTH_SETUP; + else if (spa_streq(str, "fp_sap25")) + impl->encryption = CRYPTO_FP_SAP25; else { pw_log_error( "can't handle encryption type %s", str); res = -EINVAL; @@ -1911,8 +1916,6 @@ impl->rate = RAOP_RATE; impl->latency = msec_to_samples(impl, RAOP_LATENCY_MS); impl->stride = RAOP_STRIDE; - impl->mtu = impl->stride * impl->psamples; - impl->sync_period = impl->rate / impl->psamples; if ((str = pw_properties_get(props, "raop.latency.ms")) == NULL) str = SPA_STRINGIFY(DEFAULT_LATENCY_MS); @@ -1938,10 +1941,8 @@ pw_properties_set(props, PW_KEY_NODE_VIRTUAL, "true"); if (pw_properties_get(props, PW_KEY_MEDIA_CLASS) == NULL) pw_properties_set(props, PW_KEY_MEDIA_CLASS, "Audio/Sink"); - if (pw_properties_get(props, PW_KEY_MEDIA_FORMAT) == NULL) - pw_properties_setf(props, PW_KEY_MEDIA_FORMAT, "%d", SPA_AUDIO_FORMAT_S16_LE); if (pw_properties_get(props, "net.mtu") == NULL) - pw_properties_setf(props, "net.mtu", "%d", impl->mtu); + pw_properties_set(props, "net.mtu", "1448"); if (pw_properties_get(props, "rtp.sender-ts-offset") == NULL) pw_properties_setf(props, "rtp.sender-ts-offset", "%d", 0); if (pw_properties_get(props, "sess.ts-direct") == NULL) @@ -1977,6 +1978,8 @@ copy_props(impl, props, "sess.ts-refclk"); copy_props(impl, props, "sess.ts-direct"); + impl->mtu = pw_properties_get_uint32(impl->props, "net.mtu", 1448); + impl->sync_period = impl->rate / (impl->mtu / impl->stride); impl->core = pw_context_get_object(impl->context, PW_TYPE_INTERFACE_Core); if (impl->core == NULL) { str = pw_properties_get(props, PW_KEY_REMOTE_NAME);
View file
_service:download_url:pipewire-1.4.7.tar.bz2/src/modules/module-vban/stream.c -> _service:download_url:pipewire-1.4.8.tar.bz2/src/modules/module-vban/stream.c
Changed
@@ -298,7 +298,7 @@ impl->header.format_bit = impl->format_info->format_bit; if ((str = pw_properties_get(props, "sess.name")) == NULL) str = "Stream1"; - strcpy(impl->header.stream_name, str); + snprintf(impl->header.stream_name, sizeof(impl->header.stream_name), "%s", str); break; case SPA_MEDIA_SUBTYPE_control: impl->stream_info = impl->info; @@ -319,7 +319,7 @@ impl->header.format_bit = impl->format_info->format_bit; if ((str = pw_properties_get(props, "sess.name")) == NULL) str = "Midi1"; - strcpy(impl->header.stream_name, str); + snprintf(impl->header.stream_name, sizeof(impl->header.stream_name), "%s", str); break; default: spa_assert_not_reached();
View file
_service:download_url:pipewire-1.4.7.tar.bz2/src/pipewire/filter.c -> _service:download_url:pipewire-1.4.8.tar.bz2/src/pipewire/filter.c
Changed
@@ -36,7 +36,7 @@ struct pw_buffer this; uint32_t id; #define BUFFER_FLAG_MAPPED (1 << 0) -#define BUFFER_FLAG_QUEUED (1 << 1) +#define BUFFER_FLAG_DEQUEUED (1 << 1) #define BUFFER_FLAG_ADDED (1 << 2) uint32_t flags; }; @@ -356,11 +356,9 @@ { uint32_t index; - if (SPA_FLAG_IS_SET(buffer->flags, BUFFER_FLAG_QUEUED)) + if (buffer->id >= port->n_buffers) return -EINVAL; - SPA_FLAG_SET(buffer->flags, BUFFER_FLAG_QUEUED); - spa_ringbuffer_get_write_index(&queue->ring, &index); queue->idsindex & MASK_BUFFERS = buffer->id; spa_ringbuffer_write_update(&queue->ring, index + 1); @@ -382,7 +380,6 @@ spa_ringbuffer_read_update(&queue->ring, index + 1); buffer = &port->buffersid; - SPA_FLAG_CLEAR(buffer->flags, BUFFER_FLAG_QUEUED); return buffer; } @@ -941,6 +938,7 @@ pw_log_debug("%p: got buffer id:%d datas:%d mapped size %d", filter, i, buffersi->n_datas, size); } + port->n_buffers = n_buffers; for (i = 0; i < n_buffers; i++) { struct buffer *b = &port->buffersi; @@ -953,11 +951,9 @@ } SPA_FLAG_SET(b->flags, BUFFER_FLAG_ADDED); + pw_filter_emit_add_buffer(filter, port->user_data, &b->this); } - - port->n_buffers = n_buffers; - return 0; } @@ -970,9 +966,7 @@ return -EINVAL; pw_log_trace("%p: recycle buffer %d", impl, buffer_id); - if (buffer_id < port->n_buffers) - push_queue(port, &port->queued, &port->buffersbuffer_id); - + push_queue(port, &port->queued, &port->buffersbuffer_id); return 0; } @@ -2013,6 +2007,7 @@ return NULL; } pw_log_trace_fp("%p: dequeue buffer %d", p->filter, b->id); + SPA_FLAG_SET(b->flags, BUFFER_FLAG_DEQUEUED); return &b->this; } @@ -2022,6 +2017,13 @@ { struct port *p = SPA_CONTAINER_OF(port_data, struct port, user_data); struct buffer *b = SPA_CONTAINER_OF(buffer, struct buffer, this); + + if (!SPA_FLAG_IS_SET(b->flags, BUFFER_FLAG_DEQUEUED)) { + pw_log_warn("%p: tried to queue cleared buffer %d", p->filter, b->id); + return -EINVAL; + } + SPA_FLAG_CLEAR(b->flags, BUFFER_FLAG_DEQUEUED); + pw_log_trace_fp("%p: queue buffer %d", p->filter, b->id); return push_queue(p, &p->queued, b); }
View file
_service:download_url:pipewire-1.4.7.tar.bz2/src/pipewire/impl-node.c -> _service:download_url:pipewire-1.4.8.tar.bz2/src/pipewire/impl-node.c
Changed
@@ -219,17 +219,21 @@ { struct pw_impl_node *this = user_data; struct pw_node_target *t; - int old_state; + int old_state, new_state; uint64_t trigger = 0; pw_log_trace("%p: unprepare %d remote:%d exported:%d", this, this->rt.prepared, this->remote, this->exported); - /* We mark ourself as finished now, this will avoid going further into the process loop - * in case our fd was ready (removing ourselfs from the loop should avoid that as well). - * If we were supposed to be scheduled make sure we continue the graph for the peers we - * were supposed to trigger */ - old_state = SPA_ATOMIC_XCHG(this->rt.target.activation->status, PW_NODE_ACTIVATION_INACTIVE); + /* The remote client will INACTIVE itself and remove itself from the loop to avoid + * being scheduled. + * The server will mark remote nodes as FINISHED. This will make sure the node will not + * trigger the peers anymore when it will stop because we do that on the server side + * because the client might simply be dead and not able to resume anything. + */ + new_state = this->remote ? PW_NODE_ACTIVATION_FINISHED : PW_NODE_ACTIVATION_INACTIVE; + + old_state = SPA_ATOMIC_XCHG(this->rt.target.activation->status, new_state); if (PW_NODE_ACTIVATION_PENDING_TRIGGER(old_state)) trigger = get_time_ns(this->rt.target.system);
View file
_service:download_url:pipewire-1.4.7.tar.bz2/src/pipewire/mem.c -> _service:download_url:pipewire-1.4.8.tar.bz2/src/pipewire/mem.c
Changed
@@ -167,7 +167,7 @@ impl->pagesize = sysconf(_SC_PAGESIZE); - pw_log_debug("%p: new", this); + pw_log_debug("%p: new pagesize:%" PRIu32 "", this, impl->pagesize); spa_hook_list_init(&impl->listener_list); pw_map_init(&impl->map, 64, 64); @@ -393,7 +393,6 @@ struct mempool *p = SPA_CONTAINER_OF(block->pool, struct mempool, this); struct mapping *m; struct memmap *mm; - struct pw_map_range range; struct stat sb; if (b->this.fd == -1) { @@ -418,13 +417,15 @@ return NULL; } - pw_map_range_init(&range, offset, size, p->pagesize); - m = memblock_find_mapping(b, flags, offset, size); - if (m == NULL) + if (m == NULL) { + struct pw_map_range range; + pw_map_range_init(&range, offset, size, p->pagesize); + m = memblock_map(b, flags, range.offset, range.size); - if (m == NULL) - return NULL; + if (m == NULL) + return NULL; + } mm = calloc(1, sizeof(struct memmap)); if (mm == NULL) { @@ -439,7 +440,7 @@ mm->this.flags = flags; mm->this.offset = offset; mm->this.size = size; - mm->this.ptr = SPA_PTROFF(m->ptr, range.start, void); + mm->this.ptr = SPA_PTROFF(m->ptr, offset - m->offset, void); pw_log_debug("%p: map:%p block:%p fd:%d flags:%08x ptr:%p (%u %u) mapping:%p ref:%d", p, &mm->this, b, b->this.fd, b->this.flags, mm->this.ptr, offset, size, m, m->ref);
View file
_service:download_url:pipewire-1.4.7.tar.bz2/src/pipewire/mem.h -> _service:download_url:pipewire-1.4.8.tar.bz2/src/pipewire/mem.h
Changed
@@ -7,6 +7,8 @@ #include <pipewire/properties.h> +struct spa_hook; + #ifdef __cplusplus extern "C" { #endif
View file
_service:download_url:pipewire-1.4.7.tar.bz2/src/pipewire/stream.c -> _service:download_url:pipewire-1.4.8.tar.bz2/src/pipewire/stream.c
Changed
@@ -38,7 +38,7 @@ struct pw_buffer this; uint32_t id; #define BUFFER_FLAG_MAPPED (1 << 0) -#define BUFFER_FLAG_QUEUED (1 << 1) +#define BUFFER_FLAG_DEQUEUED (1 << 1) #define BUFFER_FLAG_ADDED (1 << 2) uint32_t flags; struct spa_meta_busy *busy; @@ -340,11 +340,9 @@ { uint32_t index; - if (SPA_FLAG_IS_SET(buffer->flags, BUFFER_FLAG_QUEUED) || - buffer->id >= stream->n_buffers) + if (buffer->id >= stream->n_buffers) return -EINVAL; - SPA_FLAG_SET(buffer->flags, BUFFER_FLAG_QUEUED); queue->incount += buffer->this.size; spa_ringbuffer_get_write_index(&queue->ring, &index); @@ -375,7 +373,6 @@ buffer = &stream->buffersid; queue->outcount += buffer->this.size; - SPA_FLAG_CLEAR(buffer->flags, BUFFER_FLAG_QUEUED); return buffer; } @@ -1020,8 +1017,7 @@ { struct stream *d = object; pw_log_trace("%p: recycle buffer %d", d, buffer_id); - if (buffer_id < d->n_buffers) - queue_push(d, &d->queued, &d->buffersbuffer_id); + queue_push(d, &d->queued, &d->buffersbuffer_id); return 0; } @@ -2478,6 +2474,9 @@ return NULL; } } + + SPA_FLAG_SET(b->flags, BUFFER_FLAG_DEQUEUED); + return &b->this; } @@ -2488,6 +2487,13 @@ struct buffer *b = SPA_CONTAINER_OF(buffer, struct buffer, this); int res; + if (!SPA_FLAG_IS_SET(b->flags, BUFFER_FLAG_DEQUEUED)) { + pw_log_warn("%p: tried to queue cleared buffer %d", stream, b->id); + return -EINVAL; + } + + SPA_FLAG_CLEAR(b->flags, BUFFER_FLAG_DEQUEUED); + if (b->busy) SPA_ATOMIC_DEC(b->busy->count); @@ -2517,7 +2523,6 @@ index -= 1; queue->idsindex & MASK_BUFFERS = buffer->id; queue->outcount -= buffer->this.size; - SPA_FLAG_SET(buffer->flags, BUFFER_FLAG_QUEUED); spa_ringbuffer_read_update(&queue->ring, index); return ret;
View file
_service:download_url:pipewire-1.4.7.tar.bz2/src/tools/midifile.c -> _service:download_url:pipewire-1.4.8.tar.bz2/src/tools/midifile.c
Changed
@@ -58,6 +58,17 @@ return (in0 << 24) | (in1 << 16) | (in2 << 8) | in3; } +static inline int mf_seek(struct midi_file *mf, long offs) +{ + int res; + if (mf->pos == offs) + return 0; + if ((res = fseek(mf->file, offs, SEEK_SET)) != 0) + return -errno; + mf->pos = offs; + return 0; +} + static inline int mf_read(struct midi_file *mf, void *data, size_t size) { if (fread(data, size, 1, mf->file) != 1) @@ -178,10 +189,8 @@ tr->id = i; if (i + 1 < mf->info.ntracks && - fseek(mf->file, tr->start + tr->size, SEEK_SET) != 0) { - res = -errno; + (res = mf_seek(mf, tr->start + tr->size)) < 0) goto exit_close; - } } mf->mode = 1; *info = mf->info; @@ -218,7 +227,7 @@ struct midi_track *tr = &mf->tracks0; int res; - fseek(mf->file, 0, SEEK_SET); + mf_seek(mf, 0); mf->length = 6; CHECK_RES(write_n(mf->file, "MThd", 4)); @@ -351,7 +360,6 @@ uint32_t size; uint8_t status, meta; int res, running; - long offs; event->data = NULL; @@ -360,11 +368,8 @@ tr = &mf->tracksevent->track; - offs = tr->pos; - if (offs != mf->pos) { - if (fseek(mf->file, offs, SEEK_SET) != 0) - return -errno; - } + if ((res = mf_seek(mf, tr->pos)) < 0) + return res; mf_read(mf, &status, 1);
View file
_service:download_url:pipewire-1.4.7.tar.bz2/src/tools/pw-cat.c -> _service:download_url:pipewire-1.4.8.tar.bz2/src/tools/pw-cat.c
Changed
@@ -1485,6 +1485,11 @@ if (!data->file) { fprintf(stderr, "sndfile: failed to open audio file \"%s\": %s\n", data->filename, sf_strerror(NULL)); + if (data->verbose) { + char loginfo4096; + if (sf_command(NULL, SFC_GET_LOG_INFO, &loginfo, sizeof(loginfo)) > 0) + fprintf(stderr, "%s\n", loginfo); + } return -EIO; }
View file
_service:download_url:pipewire-1.4.7.tar.bz2/src/tools/pw-dump.c -> _service:download_url:pipewire-1.4.8.tar.bz2/src/tools/pw-dump.c
Changed
@@ -1541,7 +1541,7 @@ colors = true; setlinebuf(data.out); - while ((c = getopt_long(argc, argv, "hVr:mNC", long_options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "hVr:mNC::", long_options, NULL)) != -1) { switch (c) { case 'h' : show_help(&data, argv0, false);
View file
_service:download_url:pipewire-1.4.7.tar.bz2/test/meson.build -> _service:download_url:pipewire-1.4.8.tar.bz2/test/meson.build
Changed
@@ -53,6 +53,7 @@ 'test-properties.c', 'test-array.c', 'test-map.c', + 'test-mempool.c', 'test-utils.c', include_directories: pwtest_inc, dependencies: spa_dep ,
View file
_service:download_url:pipewire-1.4.8.tar.bz2/test/test-mempool.c
Added
@@ -0,0 +1,49 @@ +/* PipeWire */ +/* SPDX-FileCopyrightText: Copyright © 2025 PipeWire authors */ +/* SPDX-License-Identifier: MIT */ + +#include <unistd.h> + +#include <pipewire/mem.h> +#include <spa/buffer/buffer.h> + +#include "pwtest.h" + +PWTEST(mempool_issue4884) +{ + /* + * See https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/4884. This + * test checks if the offset is correctly applied when a mapping is reused. + */ + + long page_size = sysconf(_SC_PAGESIZE); + pwtest_errno_ok(page_size); + pwtest_int_ge(page_size, 8); + + struct pw_mempool *p = pw_mempool_new(NULL); + pwtest_ptr_notnull(p); + + struct pw_memblock *b = pw_mempool_alloc(p, PW_MEMBLOCK_FLAG_READWRITE, SPA_DATA_MemFd, 2 * page_size); + pwtest_ptr_notnull(b); + + struct pw_memmap *m1 = pw_mempool_map_id(p, b->id, PW_MEMMAP_FLAG_READWRITE, page_size / 2, page_size, NULL); + pwtest_ptr_notnull(m1); + pwtest_ptr_eq(m1->block, b); + + struct pw_memmap *m2 = pw_mempool_map_id(p, b->id, PW_MEMMAP_FLAG_READWRITE, 3 * page_size / 2, page_size / 2, NULL); + pwtest_ptr_notnull(m2); + pwtest_ptr_eq(m2->block, b); + + pwtest_int_eq(SPA_PTRDIFF(m2->ptr, m1->ptr), page_size); + + pw_mempool_destroy(p); + + return PWTEST_PASS; +} + +PWTEST_SUITE(pw_mempool) +{ + pwtest_add(mempool_issue4884, PWTEST_NOARG); + + return PWTEST_PASS; +}
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
.