Projects
Essentials
pipewire-aptx
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 39
View file
pipewire-aptx.changes
Changed
@@ -1,4 +1,9 @@ ------------------------------------------------------------------- +Fri Nov 24 19:29:49 UTC 2023 - Bjørn Lie <zaitor@opensuse.org> + +- Update to version 0.3.85 + +------------------------------------------------------------------- Fri Nov 3 13:41:27 UTC 2023 - Bjørn Lie <zaitor@opensuse.org> - Update to version 0.3.84
View file
pipewire-aptx.spec
Changed
@@ -7,7 +7,7 @@ %define soversion 0_2 Name: pipewire-aptx -Version: 0.3.84 +Version: 0.3.85 Release: 0 Summary: PipeWire Bluetooth aptX codec plugin License: MIT
View file
pipewire-0.3.84.tar.gz/NEWS -> pipewire-0.3.85.tar.gz/NEWS
Changed
@@ -1,3 +1,61 @@ +# PipeWire 0.3.85 (2023-11-16) + +This is the fifth (and last) 1.0 release candidate that is API and ABI +compatible with previous 0.3.x releases. + +## Highlights + - Fix an issue where a link could end up paused while not negotiated. + - Fix an infinite recursion issue when finding runnable nodes. + - Support XDG base directories when loading ACP config. + - Fix MIDI event recording preview in Ardour. + - Many more small fixes, cleanups and improvements. + + +## PipeWire + - Fix an issue where a link could end up paused while not negotiated. + (#3619) + - Fix an infinite recursion issue when finding runnable nodes by stopping + the scan on feedback links around the driver. (#3621) + - The system service now has better socket permissions. + +## Modules + - Add support for uclamp. This allows the scheduler to make better informed + decisions about where tasks should be placed, and what pstate to set + for the CPU it is running on. + - Emit warnings when applications are not doing the right locking instead + of crashing. + - Improve media.name for RAOP sinks. (#3801) + - Support pause/resume in pipe-tunnel. (#3197) + - Remove time rlimit when probing for realtime to avoid SIGXCPU. + +## SPA + - Fix a bug where the resampler would be activated even when there is an + ALSA pitch element. (#3628) + - Improve resume from suspend in ALSA. (#3646) + - Add option to expose ALSA controls as prop params. + - Support XDG base directories when loading ACP config. This makes it possible + to override the ACP config files. + +## Bluetooth + - Schedule nodes in the same ISO group together. + - More BAP fixes and cleanups. + +## JACK + - Fix MIDI events from peer ports. This makes the MIDI event recording preview + of Ardour work correctly. + +## GStreamer + - Fix some error handling in the source and sink. + +## ALSA plugin + - Improve poll descriptor handling. (#3648) + +## Docs + - Many improvements to the layout and organization. + +Older versions: + + # PipeWire 0.3.84 (2023-11-02) This is the fourth 1.0 release candidate that is API and ABI compatible @@ -56,9 +114,6 @@ ## ALSA - The ALSA plugin now handles NULL values from mmap_areas. (#3600) -Older versions: - - # PipeWire 0.3.83 (2023-10-19) This is the third 1.0 release candidate that is API and ABI compatible
View file
pipewire-0.3.84.tar.gz/doc/Doxyfile.in -> pipewire-0.3.85.tar.gz/doc/Doxyfile.in
Changed
@@ -1,7 +1,7 @@ PROJECT_NAME = PipeWire PROJECT_NUMBER = @PACKAGE_VERSION@ OUTPUT_DIRECTORY = "@output_directory@" -FULL_PATH_NAMES = NO +FULL_PATH_NAMES = YES JAVADOC_AUTOBRIEF = YES TAB_SIZE = 8 OPTIMIZE_OUTPUT_FOR_C = YES @@ -36,6 +36,9 @@ SEARCHENGINE = YES GENERATE_LATEX = NO +TOC_INCLUDE_HEADINGS = 0 +LAYOUT_FILE = @layout@ + MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = YES PREDEFINED = PA_C_DECL_BEGIN= \
View file
pipewire-0.3.85.tar.gz/doc/DoxygenLayout.xml
Added
@@ -0,0 +1,238 @@ +<doxygenlayout version="1.0"> + <navindex> + <tab type="mainpage" visible="yes" title=""/> + <tab type="pages" visible="yes" title="Pages" intro=""/> + <tab type="modules" visible="yes" title="API Reference" intro="" /> + <tab type="namespaces" visible="no" title=""> + <tab type="namespacelist" visible="yes" title="" intro=""/> + <tab type="namespacemembers" visible="yes" title="" intro=""/> + </tab> + <tab type="concepts" visible="no" title=""> + </tab> + <tab type="interfaces" visible="no" title=""> + <tab type="interfacelist" visible="yes" title="" intro=""/> + <tab type="interfaceindex" visible="$ALPHABETICAL_INDEX" title=""/> + <tab type="interfacehierarchy" visible="yes" title="" intro=""/> + </tab> + <tab type="classes" visible="yes" title=""> + <tab type="classlist" visible="yes" title="" intro=""/> + <tab type="classindex" visible="yes" title=""/> + <tab type="hierarchy" visible="yes" title="" intro=""/> + <tab type="classmembers" visible="no" title="" intro=""/> + </tab> + <tab type="structs" visible="no" title=""> + <tab type="structlist" visible="yes" title="" intro=""/> + <tab type="structindex" visible="$ALPHABETICAL_INDEX" title=""/> + </tab> + <tab type="exceptions" visible="no" title=""> + <tab type="exceptionlist" visible="yes" title="" intro=""/> + <tab type="exceptionindex" visible="$ALPHABETICAL_INDEX" title=""/> + <tab type="exceptionhierarchy" visible="yes" title="" intro=""/> + </tab> + <tab type="files" visible="yes" title=""> + <tab type="filelist" visible="yes" title="" intro=""/> + <tab type="globals" visible="no" title="" intro=""/> + </tab> + <tab type="examples" visible="yes" title="" intro=""/> + </navindex> + + <!-- Layout definition for a class page --> + <class> + <briefdescription visible="yes"/> + <includes visible="$SHOW_HEADERFILE"/> + <inheritancegraph visible="$CLASS_GRAPH"/> + <collaborationgraph visible="$COLLABORATION_GRAPH"/> + <memberdecl> + <nestedclasses visible="yes" title=""/> + <publictypes title=""/> + <services title=""/> + <interfaces title=""/> + <publicslots title=""/> + <signals title=""/> + <publicmethods title=""/> + <publicstaticmethods title=""/> + <publicattributes title=""/> + <publicstaticattributes title=""/> + <protectedtypes title=""/> + <protectedslots title=""/> + <protectedmethods title=""/> + <protectedstaticmethods title=""/> + <protectedattributes title=""/> + <protectedstaticattributes title=""/> + <packagetypes title=""/> + <packagemethods title=""/> + <packagestaticmethods title=""/> + <packageattributes title=""/> + <packagestaticattributes title=""/> + <properties title=""/> + <events title=""/> + <privatetypes title=""/> + <privateslots title=""/> + <privatemethods title=""/> + <privatestaticmethods title=""/> + <privateattributes title=""/> + <privatestaticattributes title=""/> + <friends title=""/> + <related title="" subtitle=""/> + <membergroups visible="yes"/> + </memberdecl> + <detaileddescription title=""/> + <memberdef> + <inlineclasses title=""/> + <typedefs title=""/> + <enums title=""/> + <services title=""/> + <interfaces title=""/> + <constructors title=""/> + <functions title=""/> + <related title=""/> + <variables title=""/> + <properties title=""/> + <events title=""/> + </memberdef> + <allmemberslink visible="yes"/> + <usedfiles visible="$SHOW_USED_FILES"/> + <authorsection visible="yes"/> + </class> + + <!-- Layout definition for a namespace page --> + <namespace> + <briefdescription visible="yes"/> + <memberdecl> + <nestednamespaces visible="yes" title=""/> + <constantgroups visible="yes" title=""/> + <interfaces visible="yes" title=""/> + <classes visible="yes" title=""/> + <concepts visible="yes" title=""/> + <structs visible="yes" title=""/> + <exceptions visible="yes" title=""/> + <typedefs title=""/> + <sequences title=""/> + <dictionaries title=""/> + <enums title=""/> + <functions title=""/> + <variables title=""/> + <membergroups visible="yes"/> + </memberdecl> + <detaileddescription title=""/> + <memberdef> + <inlineclasses title=""/> + <typedefs title=""/> + <sequences title=""/> + <dictionaries title=""/> + <enums title=""/> + <functions title=""/> + <variables title=""/> + </memberdef> + <authorsection visible="yes"/> + </namespace> + + <!-- Layout definition for a concept page --> + <concept> + <briefdescription visible="yes"/> + <includes visible="$SHOW_HEADERFILE"/> + <definition visible="yes" title=""/> + <detaileddescription title=""/> + <authorsection visible="yes"/> + </concept> + + <!-- Layout definition for a file page --> + <file> + <briefdescription visible="yes"/> + <includes visible="$SHOW_INCLUDE_FILES"/> + <includegraph visible="$INCLUDE_GRAPH"/> + <includedbygraph visible="$INCLUDED_BY_GRAPH"/> + <sourcelink visible="yes"/> + <memberdecl> + <interfaces visible="yes" title=""/> + <classes visible="yes" title=""/> + <structs visible="yes" title=""/> + <exceptions visible="yes" title=""/> + <namespaces visible="yes" title=""/> + <concepts visible="yes" title=""/> + <constantgroups visible="yes" title=""/> + <defines title=""/> + <typedefs title=""/> + <sequences title=""/> + <dictionaries title=""/> + <enums title=""/> + <functions title=""/> + <variables title=""/> + <membergroups visible="yes"/> + </memberdecl> + <detaileddescription title=""/> + <memberdef> + <inlineclasses title=""/> + <defines title=""/> + <typedefs title=""/> + <sequences title=""/> + <dictionaries title=""/> + <enums title=""/> + <functions title=""/> + <variables title=""/> + </memberdef> + <authorsection/> + </file> + + <!-- Layout definition for a group page --> + <group> + <briefdescription visible="yes"/> + <groupgraph visible="$GROUP_GRAPHS"/> + <memberdecl> + <nestedgroups visible="yes" title=""/> + <dirs visible="yes" title=""/> + <files visible="yes" title=""/> + <namespaces visible="yes" title=""/> + <concepts visible="yes" title=""/> + <classes visible="yes" title=""/> + <typedefs title=""/> + <sequences title=""/> + <dictionaries title=""/> + <enums title=""/> + <enumvalues title=""/> + <defines title=""/> + <functions title=""/> + <variables title=""/> + <signals title=""/> + <publicslots title=""/> + <protectedslots title=""/> + <privateslots title=""/> + <events title=""/> + <properties title=""/> + <friends title=""/> + <membergroups visible="yes"/> + </memberdecl> + <detaileddescription title=""/> + <memberdef> + <pagedocs/> + <inlineclasses title=""/> + <typedefs title=""/> + <sequences title=""/> + <dictionaries title=""/> + <enums title=""/> + <enumvalues title=""/> + <defines title=""/> + <functions title=""/> + <variables title=""/> + <signals title=""/> + <publicslots title=""/> + <protectedslots title=""/> + <privateslots title=""/> + <events title=""/> + <properties title=""/> + <friends title=""/> + </memberdef> + <authorsection visible="yes"/> + </group> + + <!-- Layout definition for a directory page --> + <directory> + <briefdescription visible="yes"/> + <directorygraph visible="yes"/> + <memberdecl> + <dirs visible="yes"/> + <files visible="yes"/> + </memberdecl> + <detaileddescription title=""/> + </directory> +</doxygenlayout>
View file
pipewire-0.3.84.tar.gz/doc/api-tree.dox -> pipewire-0.3.85.tar.gz/doc/api-tree.dox
Changed
@@ -89,6 +89,7 @@ \addtogroup spa_hooks \addtogroup spa_interfaces \addtogroup spa_json +\addtogroup spa_json_pod \addtogroup spa_keys \addtogroup spa_names \addtogroup spa_result @@ -119,8 +120,4 @@ \{ \} -\defgroup pwtest Test Suite -\{ -\} - */
View file
pipewire-0.3.84.tar.gz/doc/custom.css -> pipewire-0.3.85.tar.gz/doc/custom.css
Changed
@@ -17,3 +17,20 @@ --fragment-link: #729fcf; } } + +#nav-tree .arrow { + opacity: 1; + padding-right: 0.25em; +} + +.textblock h1 { + font-size: 150%; +} +.textblock h2 { + font-size: 100%; +} +.textblock h3, .textblock h4, .textblock h5, .textblock h6 { + font-size: 100%; + font-style: italic; + font-size: medium; +}
View file
pipewire-0.3.84.tar.gz/doc/index.dox -> pipewire-0.3.85.tar.gz/doc/index.dox
Changed
@@ -43,4 +43,13 @@ - Intoduction to PipeWire(https://bootlin.com/blog/an-introduction-to-pipewire/) - A custom PipeWire node(https://bootlin.com/blog/a-custom-pipewire-node/) + +\page page_overview +\page page_pipewire +\page page_tools +\page page_pipewire_modules +\page page_api +\page page_spa +\page page_tutorial + */
View file
pipewire-0.3.84.tar.gz/doc/manpage.dox.in -> pipewire-0.3.85.tar.gz/doc/manpage.dox.in
Changed
@@ -1,5 +1,7 @@ /** \page @pagename@ @title@ +\brief Manual page for @title@ + \verbinclude @filename@ */
View file
pipewire-0.3.84.tar.gz/doc/meson.build -> pipewire-0.3.85.tar.gz/doc/meson.build
Changed
@@ -68,7 +68,6 @@ foreach h : module_sources inputs += meson.project_source_root() / 'src' / 'modules' / h endforeach -inputs += meson.project_source_root() / 'test' / 'pwtest.h' input_dirs = meson.project_source_root() / 'spa' / 'include' / 'spa' path_prefixes = @@ -141,11 +140,16 @@ configuration: pw_tools_dox_conf) input_dirs += 'doc/pipewire-tools.dox' +doxygen_layout = meson.project_source_root() / 'doc' / 'DoxygenLayout.xml' +doxygen_filter_c = meson.project_source_root() / 'doc' / 'input-filter.sh' +doxygen_filter_h = meson.project_source_root() / 'doc' / 'input-filter-h.sh' + doxyfile_conf.set('inputs', ' '.join(inputs + input_dirs)) doxyfile_conf.set('cssfiles', ' '.join(cssfiles)) +doxyfile_conf.set('layout', doxygen_layout) doxyfile_conf.set('path_prefixes', ' '.join(path_prefixes)) -doxyfile_conf.set('c_input_filter', meson.project_source_root() / 'doc' / 'input-filter.sh') -doxyfile_conf.set('h_input_filter', meson.project_source_root() / 'doc' / 'input-filter-h.sh') +doxyfile_conf.set('c_input_filter', doxygen_filter_c) +doxyfile_conf.set('h_input_filter', doxygen_filter_h) doxyfile = configure_file(input: 'Doxyfile.in', output: 'Doxyfile', @@ -157,7 +161,7 @@ endif html_target = custom_target('pipewire-docs', - input: doxyfile, examples_dox, pw_tools_dox + inputs + cssfiles + man_doxygen, + input: doxyfile, doxygen_layout, examples_dox, pw_tools_dox, doxygen_filter_c, doxygen_filter_h + inputs + cssfiles + man_doxygen, output: 'html' , command: doxygen, doxyfile , install: true,
View file
pipewire-0.3.84.tar.gz/doc/pipewire.dox -> pipewire-0.3.85.tar.gz/doc/pipewire.dox
Changed
@@ -17,10 +17,8 @@ # Components - \subpage page_daemon -- \subpage page_tools - \subpage page_session_manager - # Backends - \subpage page_pulseaudio
View file
pipewire-0.3.84.tar.gz/doc/tutorial4.c -> pipewire-0.3.85.tar.gz/doc/tutorial4.c
Changed
@@ -42,6 +42,8 @@ stride = sizeof(int16_t) * DEFAULT_CHANNELS; n_frames = buf->datas0.maxsize / stride; + if (b->requested) + n_frames = SPA_MIN(b->requested, n_frames); for (i = 0; i < n_frames; i++) { data->accumulator += M_PI_M2 * 440 / DEFAULT_RATE;
View file
pipewire-0.3.84.tar.gz/meson.build -> pipewire-0.3.85.tar.gz/meson.build
Changed
@@ -1,5 +1,5 @@ project('pipewire', 'c' , - version : '0.3.84', + version : '0.3.85', license : 'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' , meson_version : '>= 0.61.1', default_options : 'warning_level=3', @@ -219,8 +219,7 @@ cdata.set_quoted('PIPEWIRE_CONFIG_DIR', pipewire_configdir) cdata.set_quoted('PLUGINDIR', spa_plugindir) cdata.set_quoted('SPADATADIR', spa_datadir) -cdata.set_quoted('PA_ALSA_PATHS_DIR', alsadatadir / 'paths') -cdata.set_quoted('PA_ALSA_PROFILE_SETS_DIR', alsadatadir / 'profile-sets') +cdata.set_quoted('PA_ALSA_DATA_DIR', alsadatadir) if host_machine.endian() == 'big' cdata.set('WORDS_BIGENDIAN', 1)
View file
pipewire-0.3.84.tar.gz/pipewire-alsa/alsa-plugins/pcm_pipewire.c -> pipewire-0.3.85.tar.gz/pipewire-alsa/alsa-plugins/pcm_pipewire.c
Changed
@@ -89,7 +89,7 @@ static int snd_pcm_pipewire_stop(snd_pcm_ioplug_t *io); -static int check_active(snd_pcm_ioplug_t *io) +static int update_active(snd_pcm_ioplug_t *io) { snd_pcm_pipewire_t *pw = io->private_data; snd_pcm_sframes_t avail; @@ -97,7 +97,10 @@ avail = snd_pcm_ioplug_avail(io, pw->hw_ptr, io->appl_ptr); - if (io->state == SND_PCM_STATE_DRAINING) { + if (pw->error > 0) { + active = true; + } + else if (io->state == SND_PCM_STATE_DRAINING) { active = pw->drained; } else if (avail >= 0 && avail < (snd_pcm_sframes_t)pw->min_avail) { @@ -105,33 +108,27 @@ } else if (avail >= (snd_pcm_sframes_t)pw->min_avail) { active = true; - } else { + } + else { active = false; } if (pw->active != active) { + uint64_t val; + pw_log_trace("%p: avail:%lu min-avail:%lu state:%s hw:%lu appl:%lu active:%d->%d state:%s", pw, avail, pw->min_avail, snd_pcm_state_name(io->state), pw->hw_ptr, io->appl_ptr, pw->active, active, snd_pcm_state_name(io->state)); + + pw->active = active; + if (active) + spa_system_eventfd_write(pw->system, io->poll_fd, 1); + else + spa_system_eventfd_read(pw->system, io->poll_fd, &val); } return active; } - -static int update_active(snd_pcm_ioplug_t *io) -{ - snd_pcm_pipewire_t *pw = io->private_data; - pw->active = check_active(io); - uint64_t val; - - if (pw->active || pw->error < 0) - spa_system_eventfd_write(pw->system, io->poll_fd, 1); - else - spa_system_eventfd_read(pw->system, io->poll_fd, &val); - - return pw->active; -} - static void snd_pcm_pipewire_free(snd_pcm_pipewire_t *pw) { if (pw == NULL) @@ -162,15 +159,6 @@ return 0; } -static int snd_pcm_pipewire_poll_descriptors(snd_pcm_ioplug_t *io, struct pollfd *pfds, unsigned int space) -{ - snd_pcm_pipewire_t *pw = io->private_data; - update_active(io); - pfds->fd = pw->fd; - pfds->events = POLLIN | POLLERR | POLLNVAL; - return 1; -} - static int snd_pcm_pipewire_poll_revents(snd_pcm_ioplug_t *io, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) @@ -183,10 +171,10 @@ return pw->error; *revents = pfds0.revents & ~(POLLIN | POLLOUT); - if (pfds0.revents & POLLIN && check_active(io)) { + if (pfds0.revents & POLLIN && update_active(io)) *revents |= (io->stream == SND_PCM_STREAM_PLAYBACK) ? POLLOUT : POLLIN; - update_active(io); - } + + pw_log_trace_fp("poll %d", *revents); return 0; } @@ -911,7 +899,6 @@ .delay = snd_pcm_pipewire_delay, .drain = snd_pcm_pipewire_drain, .prepare = snd_pcm_pipewire_prepare, - .poll_descriptors = snd_pcm_pipewire_poll_descriptors, .poll_revents = snd_pcm_pipewire_poll_revents, .hw_params = snd_pcm_pipewire_hw_params, .sw_params = snd_pcm_pipewire_sw_params,
View file
pipewire-0.3.84.tar.gz/pipewire-jack/src/pipewire-jack.c -> pipewire-0.3.85.tar.gz/pipewire-jack/src/pipewire-jack.c
Changed
@@ -110,6 +110,10 @@ static struct globals globals; static bool mlock_warned = false; +#define MIDI_SCRATCH_FRAMES 8192 +static float midi_scratchMIDI_SCRATCH_FRAMES; + + #define OBJECT_CHUNK 8 #define RECYCLE_THRESHOLD 128 @@ -122,9 +126,10 @@ struct client *client; -#define INTERFACE_Port 0 -#define INTERFACE_Node 1 -#define INTERFACE_Link 2 +#define INTERFACE_Invalid 0 +#define INTERFACE_Port 1 +#define INTERFACE_Node 2 +#define INTERFACE_Link 3 uint32_t type; uint32_t id; uint32_t serial; @@ -502,7 +507,7 @@ pthread_mutex_lock(&globals.lock); spa_list_for_each_safe(o, t, &c->context.objects, link) { if (o->removed) { - pw_log_info("%p: recycle object:%p type:%d id:%u/%u", + pw_log_debug("%p: recycle object:%p type:%d id:%u/%u", c, o, o->type, o->id, o->serial); spa_list_remove(&o->link); memset(o, 0, sizeof(struct object)); @@ -531,6 +536,15 @@ } +static inline struct object *port_to_object(const jack_port_t *port) +{ + return (struct object*)port; +} +static inline jack_port_t *object_to_port(struct object *o) +{ + return (jack_port_t*)o; +} + struct io_info { struct mix *mix; void *data; @@ -2522,6 +2536,17 @@ return 0; } +static void midi_init_buffer(void *data, uint32_t max_frames) +{ + struct midi_buffer *mb = data; + mb->magic = MIDI_BUFFER_MAGIC; + mb->buffer_size = max_frames * sizeof(float); + mb->nframes = max_frames; + mb->write_pos = 0; + mb->event_count = 0; + mb->lost_events = 0; +} + static inline void *init_buffer(struct port *p) { struct client *c = p->client; @@ -2531,12 +2556,7 @@ if (p->object->port.type_id == TYPE_ID_MIDI) { struct midi_buffer *mb = data; - mb->magic = MIDI_BUFFER_MAGIC; - mb->buffer_size = c->max_frames * sizeof(float); - mb->nframes = c->max_frames; - mb->write_pos = 0; - mb->event_count = 0; - mb->lost_events = 0; + midi_init_buffer(data, c->max_frames); pw_log_debug("port %p: init midi buffer size:%d", p, mb->buffer_size); } else memset(data, 0, c->max_frames * sizeof(float)); @@ -3218,7 +3238,7 @@ } static const struct pw_node_events node_events = { - PW_VERSION_NODE, + PW_VERSION_NODE_EVENTS, .info = node_info, }; @@ -3243,7 +3263,7 @@ } static const struct pw_port_events port_events = { - PW_VERSION_PORT, + PW_VERSION_PORT_EVENTS, .param = port_param, }; @@ -5005,7 +5025,7 @@ goto error_free; } - return (jack_port_t *) o; + return object_to_port(o); error_free: free_port(c, p, true); @@ -5037,7 +5057,7 @@ int jack_port_unregister (jack_client_t *client, jack_port_t *port) { struct client *c = (struct client *) client; - struct object *o = (struct object *) port; + struct object *o = port_to_object(port); struct port *p; int res; @@ -5214,41 +5234,58 @@ SPA_EXPORT void * jack_port_get_buffer (jack_port_t *port, jack_nframes_t frames) { - struct object *o = (struct object *) port; - struct port *p; - void *ptr; + struct object *o = port_to_object(port); + struct port *p = NULL; + void *ptr = NULL; return_val_if_fail(o != NULL, NULL); if (o->type != INTERFACE_Port || o->client == NULL) - return NULL; + goto done; if ((p = o->port.port) == NULL) { struct mix *mix; struct buffer *b; if ((mix = find_mix_peer(o->client, o->id)) == NULL) - return NULL; + goto done; pw_log_trace("peer mix: %p %d", mix, mix->peer_id); if ((b = get_mix_buffer(mix, frames)) == NULL) - return NULL; + goto done; - return get_buffer_data(b, frames); + if (o->port.type_id == TYPE_ID_MIDI) { + struct spa_pod_sequence *seq1; + struct spa_data *d; + void *pod; + + ptr = midi_scratch; + midi_init_buffer(ptr, MIDI_SCRATCH_FRAMES); + + d = &b->datas0; + if ((pod = spa_pod_from_data(d->data, d->maxsize, + d->chunk->offset, d->chunk->size)) == NULL) + goto done; + if (!spa_pod_is_sequence(pod)) + goto done; + seq0 = pod; + convert_to_midi(seq, 1, ptr, o->client->fix_midi_events); + } else { + ptr = get_buffer_data(b, frames); + } + } else if (p->valid) { + ptr = p->get_buffer(p, frames); } - if (!p->valid) - return NULL; - - ptr = p->get_buffer(p, frames); - pw_log_trace_fp("%p: port %p buffer %p empty:%u", p->client, p, ptr, p->empty_out); +done: + pw_log_trace_fp("%p: port %p buffer %p", p->client, p, ptr); return ptr; } SPA_EXPORT jack_uuid_t jack_port_uuid (const jack_port_t *port) { - struct object *o = (struct object *) port; + struct object *o = port_to_object(port); return_val_if_fail(o != NULL, 0); return jack_port_uuid_generate(o->serial); } @@ -5269,47 +5306,57 @@ SPA_EXPORT const char * jack_port_name (const jack_port_t *port) { - struct object *o = (struct object *) port; + struct object *o = port_to_object(port); return_val_if_fail(o != NULL, NULL); + if (o->type != INTERFACE_Port) + return NULL; return port_name(o); } SPA_EXPORT const char * jack_port_short_name (const jack_port_t *port) { - struct object *o = (struct object *) port; + struct object *o = port_to_object(port); return_val_if_fail(o != NULL, NULL); + if (o->type != INTERFACE_Port) + return NULL; return strchr(port_name(o), ':') + 1; } SPA_EXPORT int jack_port_flags (const jack_port_t *port) { - struct object *o = (struct object *) port; + struct object *o = port_to_object(port); return_val_if_fail(o != NULL, 0); + if (o->type != INTERFACE_Port) + return 0; return o->port.flags; } SPA_EXPORT const char * jack_port_type (const jack_port_t *port) { - struct object *o = (struct object *) port; + struct object *o = port_to_object(port); return_val_if_fail(o != NULL, NULL); + if (o->type != INTERFACE_Port) + return NULL; return type_to_string(o->port.type_id); } SPA_EXPORT jack_port_type_id_t jack_port_type_id (const jack_port_t *port) { - struct object *o = (struct object *) port; + struct object *o = port_to_object(port); return_val_if_fail(o != NULL, 0); + if (o->type != INTERFACE_Port) + return TYPE_ID_OTHER; return o->port.type_id; } SPA_EXPORT int jack_port_is_mine (const jack_client_t *client, const jack_port_t *port) { - struct object *o = (struct object *) port; + struct object *o = port_to_object(port); return_val_if_fail(o != NULL, 0); return o->type == INTERFACE_Port && o->port.port != NULL && @@ -5319,7 +5366,7 @@ SPA_EXPORT int jack_port_connected (const jack_port_t *port) { - struct object *o = (struct object *) port; + struct object *o = port_to_object(port); struct client *c; struct object *l; int res = 0; @@ -5349,7 +5396,7 @@ int jack_port_connected_to (const jack_port_t *port, const char *port_name) { - struct object *o = (struct object *) port; + struct object *o = port_to_object(port); struct client *c; struct object *p, *l; int res = 0; @@ -5389,7 +5436,7 @@ SPA_EXPORT const char ** jack_port_get_connections (const jack_port_t *port) { - struct object *o = (struct object *) port; + struct object *o = port_to_object(port); return_val_if_fail(o != NULL, NULL); if (o->type != INTERFACE_Port || o->client == NULL) @@ -5403,7 +5450,7 @@ const jack_port_t *port) { struct client *c = (struct client *) client; - struct object *o = (struct object *) port; + struct object *o = port_to_object(port); struct object *p, *l; const char **res; int count = 0; @@ -5446,8 +5493,8 @@ SPA_EXPORT int jack_port_tie (jack_port_t *src, jack_port_t *dst) { - struct object *s = (struct object *) src; - struct object *d = (struct object *) dst; + struct object *s = port_to_object(src); + struct object *d = port_to_object(dst); struct port *sp, *dp; sp = s->port.port; @@ -5464,7 +5511,7 @@ SPA_EXPORT int jack_port_untie (jack_port_t *port) { - struct object *o = (struct object *) port; + struct object *o = port_to_object(port); struct port *p; p = o->port.port; @@ -5485,7 +5532,7 @@ int jack_port_rename (jack_client_t* client, jack_port_t *port, const char *port_name) { struct client *c = (struct client *) client; - struct object *o = (struct object *) port; + struct object *o = port_to_object(port); struct port *p; int res = 0; @@ -5527,7 +5574,7 @@ SPA_EXPORT int jack_port_set_alias (jack_port_t *port, const char *alias) { - struct object *o = (struct object *) port; + struct object *o = port_to_object(port); struct client *c; struct port *p; const char *key; @@ -5583,7 +5630,7 @@ SPA_EXPORT int jack_port_unset_alias (jack_port_t *port, const char *alias) { - struct object *o = (struct object *) port; + struct object *o = port_to_object(port); struct client *c; struct port *p; const char *key; @@ -5634,7 +5681,7 @@ SPA_EXPORT int jack_port_get_aliases (const jack_port_t *port, char* const aliases2) { - struct object *o = (struct object *) port; + struct object *o = port_to_object(port); int res = 0; return_val_if_fail(o != NULL, -EINVAL); @@ -5657,7 +5704,7 @@ SPA_EXPORT int jack_port_request_monitor (jack_port_t *port, int onoff) { - struct object *o = (struct object *) port; + struct object *o = port_to_object(port); return_val_if_fail(o != NULL, -EINVAL); @@ -5688,13 +5735,13 @@ return -1; } - return jack_port_request_monitor((jack_port_t*)p, onoff); + return jack_port_request_monitor(object_to_port(p), onoff); } SPA_EXPORT int jack_port_ensure_monitor (jack_port_t *port, int onoff) { - struct object *o = (struct object *) port; + struct object *o = port_to_object(port); return_val_if_fail(o != NULL, -EINVAL); @@ -5711,7 +5758,7 @@ SPA_EXPORT int jack_port_monitoring_input (jack_port_t *port) { - struct object *o = (struct object *) port; + struct object *o = port_to_object(port); return_val_if_fail(o != NULL, -EINVAL); return o->port.monitor_requests > 0; } @@ -5889,7 +5936,7 @@ int jack_port_disconnect (jack_client_t *client, jack_port_t *port) { struct client *c = (struct client *) client; - struct object *o = (struct object *) port; + struct object *o = port_to_object(port); struct object *l; int res; @@ -5950,7 +5997,7 @@ SPA_EXPORT void jack_port_set_latency (jack_port_t *port, jack_nframes_t frames) { - struct object *o = (struct object *) port; + struct object *o = port_to_object(port); struct client *c; jack_latency_range_t range = { frames, frames }; @@ -5970,17 +6017,20 @@ SPA_EXPORT void jack_port_get_latency_range (jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range) { - struct object *o = (struct object *) port; + struct object *o = port_to_object(port); struct client *c; jack_nframes_t nframes, rate; int direction; struct spa_latency_info *info; return_if_fail(o != NULL); - if (o->type != INTERFACE_Port || o->client == NULL) - return; c = o->client; + if (o->type != INTERFACE_Port || c == NULL) { + range->min = range->max = 0; + return; + } + if (mode == JackCaptureLatency) direction = SPA_DIRECTION_OUTPUT; else @@ -6012,7 +6062,7 @@ SPA_EXPORT void jack_port_set_latency_range (jack_port_t *port, jack_latency_callback_mode_t mode, jack_latency_range_t *range) { - struct object *o = (struct object *) port; + struct object *o = port_to_object(port); struct client *c; enum spa_direction direction; struct spa_latency_info latency; @@ -6065,7 +6115,7 @@ static jack_nframes_t port_get_latency (jack_port_t *port) { - struct object *o = (struct object *) port; + struct object *o = port_to_object(port); jack_latency_range_t range = { 0, 0 }; return_val_if_fail(o != NULL, 0); @@ -6265,7 +6315,7 @@ if (res == NULL) pw_log_info("%p: port \"%s\" not found", c, port_name); - return (jack_port_t *)res; + return object_to_port(res); } SPA_EXPORT @@ -6287,7 +6337,7 @@ if (res == NULL) pw_log_info("%p: port %d not found", c, port_id); - return (jack_port_t *)res; + return object_to_port(res); } SPA_EXPORT
View file
pipewire-0.3.84.tar.gz/spa/include/spa/debug/log.h -> pipewire-0.3.85.tar.gz/spa/include/spa/debug/log.h
Changed
@@ -38,7 +38,7 @@ SPA_PRINTF_FUNC(2,3) static inline void spa_debug_log_log(struct spa_debug_context *ctx, const char *fmt, ...) { - struct spa_debug_log_ctx *c = (struct spa_debug_log_ctx*)ctx; + struct spa_debug_log_ctx *c = SPA_CONTAINER_OF(ctx, struct spa_debug_log_ctx, ctx); va_list args; va_start(args, fmt); spa_log_logtv(c->log, c->level, c->topic, c->file, c->line, c->func, fmt, args);
View file
pipewire-0.3.84.tar.gz/spa/include/spa/param/props.h -> pipewire-0.3.85.tar.gz/spa/include/spa/param/props.h
Changed
@@ -64,24 +64,26 @@ SPA_PROP_patternType, SPA_PROP_ditherType, SPA_PROP_truncate, - SPA_PROP_channelVolumes, /**< a volume array, one volume per channel + SPA_PROP_channelVolumes, /**< a volume array, one (linear) volume per channel * (Array of Float). 0.0 is silence, 1.0 is - * without attenuation. This is the effective volume - * that is applied. It can result in a hardware volume - * and software volume (see softVolumes) */ + * without attenuation. This is the effective + * volume that is applied. It can result + * in a hardware volume and software volume + * (see softVolumes) */ SPA_PROP_volumeBase, /**< a volume base (Float) */ SPA_PROP_volumeStep, /**< a volume step (Float) */ SPA_PROP_channelMap, /**< a channelmap array * (Array (Id enum spa_audio_channel)) */ SPA_PROP_monitorMute, /**< mute (Bool) */ - SPA_PROP_monitorVolumes, /**< a volume array, one volume per + SPA_PROP_monitorVolumes, /**< a volume array, one (linear) volume per * channel (Array of Float) */ SPA_PROP_latencyOffsetNsec, /**< delay adjustment */ SPA_PROP_softMute, /**< mute (Bool) applied in software */ - SPA_PROP_softVolumes, /**< a volume array, one volume per channel + SPA_PROP_softVolumes, /**< a volume array, one (linear) volume per channel * (Array of Float). 0.0 is silence, 1.0 is without - * attenuation. This is the volume applied in software, - * there might be a part applied in hardware. */ + * attenuation. This is the volume applied in + * software, there might be a part applied in + * hardware. */ SPA_PROP_iec958Codecs, /**< enabled IEC958 (S/PDIF) codecs, * (Array (Id enum spa_audio_iec958_codec) */
View file
pipewire-0.3.84.tar.gz/spa/include/spa/utils/keys.h -> pipewire-0.3.85.tar.gz/spa/include/spa/utils/keys.h
Changed
@@ -44,6 +44,7 @@ #define SPA_KEY_API_ALSA_OPEN_UCM "api.alsa.open.ucm" /**< if UCM should be opened card */ #define SPA_KEY_API_ALSA_DISABLE_LONGNAME \ "api.alsa.disable-longname" /**< if card long name should not be passed to MIDI port */ +#define SPA_KEY_API_ALSA_BIND_CTLS "api.alsa.bind-ctls" /**< alsa controls to bind as params */ /** info from alsa card_info */ #define SPA_KEY_API_ALSA_CARD_ID "api.alsa.card.id" /**< id from card_info */
View file
pipewire-0.3.84.tar.gz/spa/plugins/alsa/acp/alsa-mixer.c -> pipewire-0.3.85.tar.gz/spa/plugins/alsa/acp/alsa-mixer.c
Changed
@@ -2795,20 +2795,6 @@ return 0; } -static const char *get_default_paths_dir(void) { - const char *str; -#ifdef HAVE_RUNNING_FROM_BUILD_TREE - if (pa_run_from_build_tree()) - return PA_SRCDIR "mixer/paths"; - else -#endif - if (getenv("ACP_BUILDDIR") != NULL) - return "mixer/paths"; - if ((str = getenv("ACP_PATHS_DIR")) != NULL) - return str; - return PA_ALSA_PATHS_DIR; -} - pa_alsa_path* pa_alsa_path_new(const char *paths_dir, const char *fname, pa_alsa_direction_t direction) { pa_alsa_path *p; char *fn; @@ -2873,10 +2859,9 @@ items2.data = &p->description; items3.data = &mute_during_activation; - if (!paths_dir) - paths_dir = get_default_paths_dir(); + fn = get_data_path(paths_dir, "paths", fname); - fn = pa_maybe_prefix_path(fname, paths_dir); + pa_log_info("Loading path config: %s", fn); r = pa_config_parse(fn, NULL, items, p->proplist, false, p); pa_xfree(fn); @@ -4827,20 +4812,6 @@ pa_xfree(db_values); } -static const char *get_default_profile_dir(void) { - const char *str; -#ifdef HAVE_RUNNING_FROM_BUILD_TREE - if (pa_run_from_build_tree()) - return PA_SRCDIR "mixer/profile-sets"; - else -#endif - if (getenv("ACP_BUILDDIR") != NULL) - return "mixer/profile-sets"; - if ((str = getenv("ACP_PROFILES_DIR")) != NULL) - return str; - return PA_ALSA_PROFILE_SETS_DIR; -} - pa_alsa_profile_set* pa_alsa_profile_set_new(const char *fname, const pa_channel_map *bonus) { pa_alsa_profile_set *ps; pa_alsa_profile *p; @@ -4890,13 +4861,14 @@ items0.data = &ps->auto_profiles; - fn = pa_maybe_prefix_path(fname ? fname : "default.conf", - get_default_profile_dir()); + fn = get_data_path(NULL, "profile-sets", fname ? fname : "default.conf"); + + pa_log_info("Loading profile set: %s", fn); + if ((r = access(fn, R_OK)) != 0) { if (fname != NULL) { pa_log_warn("profile-set '%s' can't be accessed: %m", fn); - fn = pa_maybe_prefix_path("default.conf", - get_default_profile_dir()); + fn = get_data_path(NULL, "profile-sets", "default.conf"); r = access(fn, R_OK); } if (r != 0) {
View file
pipewire-0.3.84.tar.gz/spa/plugins/alsa/acp/compat.c -> pipewire-0.3.85.tar.gz/spa/plugins/alsa/acp/compat.c
Changed
@@ -18,9 +18,13 @@ along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. ***/ +#include <spa/utils/string.h> +#include <spa/utils/cleanup.h> + #include "compat.h" #include "device-port.h" #include "alsa-mixer.h" +#include "config.h" static const char *port_types = { PA_DEVICE_PORT_TYPE_UNKNOWN = "unknown", @@ -208,3 +212,76 @@ return true; } + +static char *try_path(const char *fname, const char *path) +{ + char *result = pa_maybe_prefix_path(fname, path); + + pa_log_trace("Check for file: %s", result); + + if (access(result, R_OK) == 0) + return result; + + pa_xfree(result); + return NULL; +} + +static char *get_xdg_home(const char *key, const char *fallback) +{ + const char *e; + + e = getenv(key); + if (e && *e) { + return strdup(e); + } else { + e = getenv("HOME"); + if (!(e && *e)) + e = getenv("USERPROFILE"); + if (e && *e) + return spa_aprintf("%s/%s", e, fallback); + } + return NULL; +} + +char *get_data_path(const char *data_dir, const char *data_type, const char *fname) +{ + static const char * const subpaths = { + "alsa-card-profile/mixer", + "alsa-card-profile", + }; + const char *e; + spa_autofree char *base = NULL; + char *result; + + if (data_dir) + if ((result = try_path(fname, data_dir)) != NULL) + return result; + + e = getenv("ACP_PATHS_DIR"); + if (e && *e && spa_streq(data_type, "paths")) + if ((result = try_path(fname, e)) != NULL) + return result; + + e = getenv("ACP_PROFILES_DIR"); + if (e && *e && spa_streq(data_type, "profile-sets")) + if ((result = try_path(fname, e)) != NULL) + return result; + + base = get_xdg_home("XDG_CONFIG_HOME", ".config"); + if (base) { + SPA_FOR_EACH_ELEMENT_VAR(subpaths, subpath) { + spa_autofree char *path = spa_aprintf("%s/%s/%s", base, *subpath, data_type); + if ((result = try_path(fname, path)) != NULL) + return result; + } + } + + SPA_FOR_EACH_ELEMENT_VAR(subpaths, subpath) { + spa_autofree char *path = spa_aprintf("/etc/%s/%s", *subpath, data_type); + if ((result = try_path(fname, path)) != NULL) + return result; + } + + spa_autofree char *path = spa_aprintf("%s/%s", PA_ALSA_DATA_DIR, data_type); + return pa_maybe_prefix_path(fname, path); +}
View file
pipewire-0.3.84.tar.gz/spa/plugins/alsa/acp/compat.h -> pipewire-0.3.85.tar.gz/spa/plugins/alsa/acp/compat.h
Changed
@@ -214,6 +214,7 @@ PA_LOG_NOTICE = 2, /* Notice messages */ PA_LOG_INFO = 3, /* Info messages */ PA_LOG_DEBUG = 4, /* Debug messages */ + PA_LOG_TRACE = 5, PA_LOG_LEVEL_MAX } pa_log_level_t; @@ -245,6 +246,7 @@ #define pa_log_notice(fmt,...) pa_logl(PA_LOG_NOTICE, fmt, ##__VA_ARGS__) #define pa_log_info(fmt,...) pa_logl(PA_LOG_INFO, fmt, ##__VA_ARGS__) #define pa_log_debug(fmt,...) pa_logl(PA_LOG_DEBUG, fmt, ##__VA_ARGS__) +#define pa_log_trace(fmt,...) pa_logl(PA_LOG_TRACE, fmt, ##__VA_ARGS__) #define pa_log pa_log_error #define pa_assert_se(expr) \ @@ -677,6 +679,8 @@ #endif } +char *get_data_path(const char *data_dir, const char *data_type, const char *fname); + #include <spa/support/i18n.h> extern struct spa_i18n *acp_i18n;
View file
pipewire-0.3.84.tar.gz/spa/plugins/alsa/alsa-compress-offload-device.c -> pipewire-0.3.85.tar.gz/spa/plugins/alsa/alsa-compress-offload-device.c
Changed
@@ -86,7 +86,7 @@ * hardware that can capture audio is difficult to do. The only hardware * known is the Wolfson ADSP; the only driver in the kernel that exposes * Compress-Offload capture devices is the one for that hardware. */ - assert(false); + spa_assert_not_reached(); } info.change_mask = SPA_DEVICE_OBJECT_CHANGE_MASK_PROPS;
View file
pipewire-0.3.84.tar.gz/spa/plugins/alsa/alsa-pcm-sink.c -> pipewire-0.3.85.tar.gz/spa/plugins/alsa/alsa-pcm-sink.c
Changed
@@ -8,8 +8,6 @@ #include <spa/node/node.h> #include <spa/node/utils.h> -#include <spa/node/keys.h> -#include <spa/monitor/device.h> #include <spa/utils/keys.h> #include <spa/utils/names.h> #include <spa/utils/string.h> @@ -31,75 +29,6 @@ props->use_chmap = DEFAULT_USE_CHMAP; } -static void emit_node_info(struct state *this, bool full) -{ - uint64_t old = full ? this->info.change_mask : 0; - - if (full) - this->info.change_mask = this->info_all; - if (this->info.change_mask) { - struct spa_dict_item items7; - uint32_t i, n_items = 0; - char latency64, period64, nperiods64, headroom64; - - itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_API, "alsa"); - itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_MEDIA_CLASS, "Audio/Sink"); - itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_DRIVER, "true"); - if (this->have_format) { - snprintf(latency, sizeof(latency), "%lu/%d", this->buffer_frames / 2, this->rate); - itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_MAX_LATENCY, latency); - snprintf(period, sizeof(period), "%lu", this->period_frames); - itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.period-size", period); - snprintf(nperiods, sizeof(nperiods), "%lu", - this->period_frames != 0 ? this->buffer_frames / this->period_frames : 0); - itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.period-num", nperiods); - snprintf(headroom, sizeof(headroom), "%u", this->headroom); - itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.headroom", headroom); - } else { - itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_MAX_LATENCY, NULL); - itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.period-size", NULL); - itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.period-num", NULL); - itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.headroom", NULL); - } - this->info.props = &SPA_DICT_INIT(items, n_items); - - if (this->info.change_mask & SPA_NODE_CHANGE_MASK_PARAMS) { - for (i = 0; i < this->info.n_params; i++) { - if (this->paramsi.user > 0) { - this->paramsi.flags ^= SPA_PARAM_INFO_SERIAL; - this->paramsi.user = 0; - } - } - } - spa_node_emit_info(&this->hooks, &this->info); - - this->info.change_mask = old; - } -} - -static void emit_port_info(struct state *this, bool full) -{ - uint64_t old = full ? this->port_info.change_mask : 0; - - if (full) - this->port_info.change_mask = this->port_info_all; - if (this->port_info.change_mask) { - uint32_t i; - - if (this->port_info.change_mask & SPA_PORT_CHANGE_MASK_PARAMS) { - for (i = 0; i < this->port_info.n_params; i++) { - if (this->port_paramsi.user > 0) { - this->port_paramsi.flags ^= SPA_PARAM_INFO_SERIAL; - this->port_paramsi.user = 0; - } - } - } - spa_node_emit_port_info(&this->hooks, - SPA_DIRECTION_INPUT, 0, &this->port_info); - this->port_info.change_mask = old; - } -} - static int impl_node_enum_params(void *object, int seq, uint32_t id, uint32_t start, uint32_t num, const struct spa_pod *filter) @@ -348,8 +277,8 @@ info.ns = lat_ns; handle_process_latency(this, &info); } - emit_node_info(this, false); - emit_port_info(this, false); + spa_alsa_emit_node_info(this, false); + spa_alsa_emit_port_info(this, false); break; } case SPA_PARAM_ProcessLatency: @@ -362,8 +291,8 @@ handle_process_latency(this, &info); - emit_node_info(this, false); - emit_port_info(this, false); + spa_alsa_emit_node_info(this, false); + spa_alsa_emit_port_info(this, false); break; } default: @@ -425,8 +354,8 @@ spa_hook_list_isolate(&this->hooks, &save, listener, events, data); - emit_node_info(this, true); - emit_port_info(this, true); + spa_alsa_emit_node_info(this, true); + spa_alsa_emit_port_info(this, true); spa_hook_list_join(&this->hooks, &save); @@ -673,7 +602,7 @@ } this->info.change_mask |= SPA_NODE_CHANGE_MASK_PROPS; - emit_node_info(this, false); + spa_alsa_emit_node_info(this, false); this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_RATE; this->port_info.rate = SPA_FRACTION(1, this->rate); @@ -686,7 +615,7 @@ this->port_paramsPORT_Format = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE); this->port_paramsPORT_Buffers = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0); } - emit_port_info(this, false); + spa_alsa_emit_port_info(this, false); return err; } @@ -722,7 +651,7 @@ this->latencyinfo.direction = info; this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; this->port_paramsPORT_Latency.user++; - emit_port_info(this, false); + spa_alsa_emit_port_info(this, false); break; } case SPA_PARAM_Tag: @@ -741,7 +670,7 @@ this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; this->port_paramsPORT_Tag.user++; - emit_port_info(this, false); + spa_alsa_emit_port_info(this, false); } break; }
View file
pipewire-0.3.84.tar.gz/spa/plugins/alsa/alsa-pcm-source.c -> pipewire-0.3.85.tar.gz/spa/plugins/alsa/alsa-pcm-source.c
Changed
@@ -8,12 +8,10 @@ #include <spa/node/node.h> #include <spa/node/utils.h> -#include <spa/node/keys.h> #include <spa/utils/keys.h> #include <spa/utils/names.h> #include <spa/utils/list.h> #include <spa/utils/string.h> -#include <spa/monitor/device.h> #include <spa/param/audio/format.h> #include <spa/pod/filter.h> #include <spa/pod/dynamic.h> @@ -32,73 +30,6 @@ props->use_chmap = DEFAULT_USE_CHMAP; } -static void emit_node_info(struct state *this, bool full) -{ - uint64_t old = full ? this->info.change_mask : 0; - if (full) - this->info.change_mask = this->info_all; - if (this->info.change_mask) { - struct spa_dict_item items7; - uint32_t i, n_items = 0; - char latency64, period64, nperiods64, headroom64; - - itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_API, "alsa"); - itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_MEDIA_CLASS, "Audio/Source"); - itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_DRIVER, "true"); - if (this->have_format) { - snprintf(latency, sizeof(latency), "%lu/%d", this->buffer_frames / 2, this->rate); - itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_MAX_LATENCY, latency); - snprintf(period, sizeof(period), "%lu", this->period_frames); - itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.period-size", period); - snprintf(nperiods, sizeof(nperiods), "%lu", - this->period_frames != 0 ? this->buffer_frames / this->period_frames : 0); - itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.period-num", nperiods); - snprintf(headroom, sizeof(headroom), "%u", this->headroom); - itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.headroom", headroom); - } else { - itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_MAX_LATENCY, NULL); - itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.period-size", NULL); - itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.period-num", NULL); - itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.headroom", NULL); - } - this->info.props = &SPA_DICT_INIT(items, n_items); - - if (this->info.change_mask & SPA_NODE_CHANGE_MASK_PARAMS) { - for (i = 0; i < this->info.n_params; i++) { - if (this->paramsi.user > 0) { - this->paramsi.flags ^= SPA_PARAM_INFO_SERIAL; - this->paramsi.user = 0; - } - } - } - spa_node_emit_info(&this->hooks, &this->info); - this->info.change_mask = old; - } -} - -static void emit_port_info(struct state *this, bool full) -{ - uint64_t old = full ? this->port_info.change_mask : 0; - if (full) - this->port_info.change_mask = this->port_info_all; - if (this->port_info.change_mask) { - uint32_t i; - - if (this->port_info.change_mask & SPA_PORT_CHANGE_MASK_PARAMS) { - for (i = 0; i < this->port_info.n_params; i++) { - if (this->port_paramsi.user > 0) { - this->port_paramsi.flags ^= SPA_PARAM_INFO_SERIAL; - this->port_paramsi.user = 0; - } - } - } - spa_node_emit_port_info(&this->hooks, - SPA_DIRECTION_OUTPUT, 0, &this->port_info); - this->port_info.change_mask = old; - } -} - - static int impl_node_enum_params(void *object, int seq, uint32_t id, uint32_t start, uint32_t num, const struct spa_pod *filter) @@ -311,8 +242,8 @@ handle_process_latency(this, &info); } - emit_node_info(this, false); - emit_port_info(this, false); + spa_alsa_emit_node_info(this, false); + spa_alsa_emit_port_info(this, false); break; } case SPA_PARAM_ProcessLatency: @@ -325,8 +256,8 @@ handle_process_latency(this, &info); - emit_node_info(this, false); - emit_port_info(this, false); + spa_alsa_emit_node_info(this, false); + spa_alsa_emit_port_info(this, false); break; } default: @@ -388,8 +319,8 @@ spa_hook_list_isolate(&this->hooks, &save, listener, events, data); - emit_node_info(this, true); - emit_port_info(this, true); + spa_alsa_emit_node_info(this, true); + spa_alsa_emit_port_info(this, true); spa_hook_list_join(&this->hooks, &save); @@ -607,7 +538,7 @@ } this->info.change_mask |= SPA_NODE_CHANGE_MASK_PROPS; - emit_node_info(this, false); + spa_alsa_emit_node_info(this, false); this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_RATE; this->port_info.rate = SPA_FRACTION(1, this->rate); @@ -620,7 +551,7 @@ this->port_paramsPORT_Format = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE); this->port_paramsPORT_Buffers = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0); } - emit_port_info(this, false); + spa_alsa_emit_port_info(this, false); return err; } @@ -656,7 +587,7 @@ this->latencyinfo.direction = info; this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; this->port_paramsPORT_Latency.user++; - emit_port_info(this, false); + spa_alsa_emit_port_info(this, false); break; } case SPA_PARAM_Tag: @@ -675,7 +606,7 @@ this->port_info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; this->port_paramsPORT_Tag.user++; - emit_port_info(this, false); + spa_alsa_emit_port_info(this, false); } break; }
View file
pipewire-0.3.84.tar.gz/spa/plugins/alsa/alsa-pcm.c -> pipewire-0.3.85.tar.gz/spa/plugins/alsa/alsa-pcm.c
Changed
@@ -13,6 +13,8 @@ #include <spa/utils/result.h> #include <spa/support/system.h> #include <spa/utils/keys.h> +#include <spa/node/keys.h> +#include <spa/monitor/device.h> #include "alsa-pcm.h" @@ -184,6 +186,69 @@ return 0; } +static struct spa_pod *enum_bind_ctl_propinfo(struct state *state, uint32_t idx, struct spa_pod_builder *b) +{ + char param_name1024; + char param_desc1024; + snd_ctl_elem_info_t *info = state->bound_ctlsidx.info; + + if (!info) { + // This will end iteration early, so print a warning + spa_log_warn(state->log, "Don't have prop info for bind ctl, bailing"); + return NULL; + } + + snprintf(param_name, sizeof(param_name), "api.alsa.bind-ctl.%s", + snd_ctl_elem_info_get_name(info)); + snprintf(param_desc, sizeof(param_desc), "Value of ALSA control '%s'", + snd_ctl_elem_info_get_name(info)); + + // We don't have meaningful default values + switch (snd_ctl_elem_info_get_type(info)) { + case SND_CTL_ELEM_TYPE_BOOLEAN: + return spa_pod_builder_add_object(b, + SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo, + SPA_PROP_INFO_name, SPA_POD_String(param_name), + SPA_PROP_INFO_description, SPA_POD_String(param_desc), + SPA_PROP_INFO_type, SPA_POD_Bool(false), + SPA_PROP_INFO_params, SPA_POD_Bool(true)); + + case SND_CTL_ELEM_TYPE_INTEGER: + return spa_pod_builder_add_object(b, + SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo, + SPA_PROP_INFO_name, SPA_POD_String(param_name), + SPA_PROP_INFO_description, SPA_POD_String(param_desc), + SPA_PROP_INFO_type, SPA_POD_Int(0), + SPA_PROP_INFO_params, SPA_POD_Bool(true)); + break; + + case SND_CTL_ELEM_TYPE_INTEGER64: + return spa_pod_builder_add_object(b, + SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo, + SPA_PROP_INFO_name, SPA_POD_String(param_name), + SPA_PROP_INFO_description, SPA_POD_String(param_desc), + SPA_PROP_INFO_type, SPA_POD_Long(0), + SPA_PROP_INFO_params, SPA_POD_Bool(true)); + break; + + case SND_CTL_ELEM_TYPE_ENUMERATED: + return spa_pod_builder_add_object(b, + SPA_TYPE_OBJECT_PropInfo, SPA_PARAM_PropInfo, + SPA_PROP_INFO_name, SPA_POD_String(param_name), + SPA_PROP_INFO_description, SPA_POD_String(param_desc), + SPA_PROP_INFO_type, SPA_POD_Int(0), + SPA_PROP_INFO_params, SPA_POD_Bool(true)); + break; + + default: + // FIXME: we can probably support bytes but the length seems unknown in the API + spa_log_warn(state->log, "%s ctl '%s' not supported", + snd_ctl_elem_type_name(snd_ctl_elem_info_get_type(info)), + snd_ctl_elem_info_get_name(info)); + return NULL; + } +} + struct spa_pod *spa_alsa_enum_propinfo(struct state *state, uint32_t idx, struct spa_pod_builder *b) { @@ -346,12 +411,67 @@ SPA_PROP_INFO_type, SPA_POD_String(state->clock_name), SPA_PROP_INFO_params, SPA_POD_Bool(true)); break; + // While adding params here, update the math in default too default: - return NULL; + idx -= 17; + if (idx <= state->num_bind_ctls) + param = enum_bind_ctl_propinfo(state, idx - 1, b); + else + return NULL; } return param; } +static void add_bind_ctl_param(struct state *state, const snd_ctl_elem_value_t *elem, const snd_ctl_elem_info_t *info, + struct spa_pod_builder *b) +{ + char param_name1024; + + snprintf(param_name, sizeof(param_name), "api.alsa.bind-ctl.%s", + snd_ctl_elem_info_get_name(info)); + spa_pod_builder_string(b, param_name); + + switch (snd_ctl_elem_info_get_type(info)) { + case SND_CTL_ELEM_TYPE_BOOLEAN: + spa_pod_builder_bool(b, snd_ctl_elem_value_get_boolean(elem, 0)); + break; + + case SND_CTL_ELEM_TYPE_INTEGER: + spa_pod_builder_int(b, snd_ctl_elem_value_get_integer(elem, 0)); + break; + + case SND_CTL_ELEM_TYPE_INTEGER64: + spa_pod_builder_long(b, snd_ctl_elem_value_get_integer64(elem, 0)); + break; + + case SND_CTL_ELEM_TYPE_ENUMERATED: + spa_pod_builder_int(b, snd_ctl_elem_value_get_enumerated(elem, 0)); + break; + + default: + // FIXME: we can probably support bytes but the length seems unknown in the API + spa_log_warn(state->log, "%s ctl '%s' not supported", + snd_ctl_elem_type_name(snd_ctl_elem_info_get_type(info)), + snd_ctl_elem_info_get_name(info)); + break; + } +} + +static void add_bind_ctl_params(struct state *state, struct spa_pod_builder *b) +{ + int err; + + for (unsigned int i = 0; i < state->num_bind_ctls; i++) { + err = snd_ctl_elem_read(state->ctl, state->bound_ctlsi.value); + if (err < 0) { + spa_log_warn(state->log, "Could not read elem value for '%s': %s", + state->bound_ctlsi.name, snd_strerror(err)); + } + + add_bind_ctl_param(state, state->bound_ctlsi.value, state->bound_ctlsi.info, b); + } +} + int spa_alsa_add_prop_params(struct state *state, struct spa_pod_builder *b) { struct spa_pod_frame f1; @@ -419,6 +539,8 @@ spa_pod_builder_string(b, "clock.name"); spa_pod_builder_string(b, state->clock_name); + add_bind_ctl_params(state, b); + spa_pod_builder_pop(b, &f0); return 0; } @@ -498,6 +620,123 @@ { } +static void fill_device_name(struct state *state, const char *params, char device_name, size_t len) +{ + spa_scnprintf(device_name, len, "%s%s%s", + state->card->ucm_prefix ? state->card->ucm_prefix : "", + state->props.device, params ? params : ""); +} + +static void bind_ctl_event(struct spa_source *source) +{ + // We don't know if a bound element changed or not, so let's find out + struct state *state = source->data; + snd_ctl_elem_value_t *old_value; + bool changed = false; + + snd_ctl_elem_value_alloca(&old_value); + + for (unsigned int i = 0; i < state->num_bind_ctls; i++) { + int err; + + snd_ctl_elem_value_copy(old_value, state->bound_ctlsi.value); + + err = snd_ctl_elem_read(state->ctl, state->bound_ctlsi.value); + if (err < 0) { + spa_log_warn(state->log, "Could not read ctl '%s': %s", + state->bound_ctlsi.name, snd_strerror(err)); + continue; + } + + if (snd_ctl_elem_value_compare(old_value, state->bound_ctlsi.value) != 0) { + // We don't need to check all the ctls, if one changed, + // we'll emit a notification and they'll be read when + // the props are read + spa_log_debug(state->log, "bound ctl '%s' has changed", state->bound_ctlsi.name); + changed = true; + break; + } + } + + if (changed) { + state->info.change_mask |= SPA_NODE_CHANGE_MASK_PARAMS; + state->paramsNODE_Props.user++; + spa_alsa_emit_node_info(state, false); + } +} + +static void bind_ctls_for_params(struct state *state) +{ + struct pollfd pfds16; + int err; + + if (state->num_bind_ctls == 0) + return; + + if (!state->ctl) { + char device_name256; + + fill_device_name(state, NULL, device_name, sizeof(device_name)); + + err = snd_ctl_open(&state->ctl, device_name, SND_CTL_NONBLOCK); + if (err < 0) { + spa_log_info(state->log, "%s could not find ctl device: %s", + state->props.device, snd_strerror(err)); + state->ctl = NULL; + return; + } + } + + state->ctl_n_fds = snd_ctl_poll_descriptors_count(state->ctl); + if (state->ctl_n_fds > (int)SPA_N_ELEMENTS(state->ctl_sources)) { + spa_log_warn(state->log, "Too many poll descriptors (%d), listening to a subset", state->ctl_n_fds); + state->ctl_n_fds = SPA_N_ELEMENTS(state->ctl_sources); + } + + if ((err = snd_ctl_poll_descriptors(state->ctl, pfds, state->ctl_n_fds)) < 0) { + spa_log_warn(state->log, "Could not get poll descriptors: %s", snd_strerror(err)); + return; + } + + snd_ctl_subscribe_events(state->ctl, 1); + + for (int i = 0; i < state->ctl_n_fds; i++) { + state->ctl_sourcesi.func = bind_ctl_event; + state->ctl_sourcesi.data = state; + state->ctl_sourcesi.fd = pfdsi.fd; + state->ctl_sourcesi.mask = SPA_IO_IN; + state->ctl_sourcesi.rmask = 0; + spa_loop_add_source(state->data_loop, &state->ctl_sourcesi); + } + + for (unsigned int i = 0; i < state->num_bind_ctls; i++) { + snd_ctl_elem_id_t *id; + + snd_ctl_elem_id_alloca(&id); + snd_ctl_elem_id_set_name(id, state->bound_ctlsi.name); + snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_PCM); + + snd_ctl_elem_info_malloc(&state->bound_ctlsi.info); + snd_ctl_elem_info_set_id(state->bound_ctlsi.info, id); + + err = snd_ctl_elem_info(state->ctl, state->bound_ctlsi.info); + if (err < 0) { + spa_log_warn(state->log, "Could not read elem info for '%s': %s", + state->bound_ctlsi.name, snd_strerror(err)); + + snd_ctl_elem_info_free(state->bound_ctlsi.info); + state->bound_ctlsi.info = NULL; + continue; + } + + snd_ctl_elem_value_malloc(&state->bound_ctlsi.value); + snd_ctl_elem_value_set_id(state->bound_ctlsi.value, id); + + spa_log_debug(state->log, "Binding ctl for '%s'", + snd_ctl_elem_info_get_name(state->bound_ctlsi.info)); + } +} + int spa_alsa_init(struct state *state, const struct spa_dict *info) { uint32_t i; @@ -525,6 +764,24 @@ state->open_ucm = spa_atob(s); } else if (spa_streq(k, "clock.quantum-limit")) { spa_atou32(s, &state->quantum_limit, 0); + } else if (spa_streq(k, SPA_KEY_API_ALSA_BIND_CTLS)) { + struct spa_json it2; + char v256; + unsigned int i = 0; + + /* Read a list of ALSA control names to bind as params */ + spa_json_init(&it0, s, strlen(s)); + if (spa_json_enter_array(&it0, &it1) <= 0) + spa_json_init(&it1, s, strlen(s)); + + while (spa_json_get_string(&it1, v, sizeof(v)) > 0 && + i < SPA_N_ELEMENTS(state->bound_ctls)) { + strncpy(state->bound_ctlsi.name, v, sizeof(state->bound_ctlsi.name)); + i++; + } + state->num_bind_ctls = i; + + /* We'll do the actual binding after checking the card exists */ } else { alsa_set_param(state, k, s); } @@ -558,6 +815,8 @@ state->rate_limit.interval = 2 * SPA_NSEC_PER_SEC; state->rate_limit.burst = 1; + bind_ctls_for_params(state); + return 0; } @@ -578,6 +837,26 @@ free(state->tag0); free(state->tag1); + if (state->ctl) { + for (int i = 0; i < state->ctl_n_fds; i++) { + spa_loop_remove_source(state->data_loop, &state->ctl_sourcesi); + } + + snd_ctl_close(state->ctl); + state->ctl = NULL; + + for (unsigned int i = 0; i < state->num_bind_ctls; i++) { + if (state->bound_ctlsi.info) { + snd_ctl_elem_info_free(state->bound_ctlsi.info); + state->bound_ctlsi.info = NULL; + } + if (state->bound_ctlsi.value) { + snd_ctl_elem_value_free(state->bound_ctlsi.value); + state->bound_ctlsi.value = NULL; + } + } + } + return err; } @@ -589,16 +868,20 @@ state->stream == SND_PCM_STREAM_CAPTURE ? "Capture Pitch 1000000" : "Playback Pitch 1000000"; + bool opened = false; int err; snd_lib_error_set_handler(silence_error_handler); - err = snd_ctl_open(&state->ctl, device_name, SND_CTL_NONBLOCK); - if (err < 0) { - spa_log_info(state->log, "%s could not find ctl device: %s", - device_name, snd_strerror(err)); - state->ctl = NULL; - goto error; + if (!state->ctl) { + err = snd_ctl_open(&state->ctl, device_name, SND_CTL_NONBLOCK); + if (err < 0) { + spa_log_info(state->log, "%s could not find ctl device: %s", + device_name, snd_strerror(err)); + state->ctl = NULL; + goto error; + } + opened = true; } snd_ctl_elem_id_alloca(&id); @@ -616,9 +899,11 @@ snd_ctl_elem_value_free(state->pitch_elem); state->pitch_elem = NULL; - snd_ctl_close(state->ctl); - state->ctl = NULL; - goto error; + if (opened) { + snd_ctl_close(state->ctl); + state->ctl = NULL; + goto error; + } } snd_ctl_elem_value_set_integer(state->pitch_elem, 0, 1000000); @@ -662,9 +947,7 @@ if (state->opened) return 0; - spa_scnprintf(device_name, sizeof(device_name), "%s%s%s", - state->card->ucm_prefix ? state->card->ucm_prefix : "", - props->device, params ? params : ""); + fill_device_name(state, params, device_name, sizeof(device_name)); spa_scnprintf(state->name, sizeof(state->name), "%s%s", props->device, state->stream == SND_PCM_STREAM_CAPTURE ? "c" : "p"); @@ -757,8 +1040,11 @@ snd_ctl_elem_value_free(state->pitch_elem); state->pitch_elem = NULL; - snd_ctl_close(state->ctl); - state->ctl = NULL; + // Close it unless we've got some bind_ctls we're listening to + if (state->ctl_n_fds == 0) { + snd_ctl_close(state->ctl); + state->ctl = NULL; + } } return err; @@ -1982,6 +2268,7 @@ spa_list_init(&this->free); spa_list_init(&this->ready); + this->ready_offset = 0; for (i = 0; i < this->n_buffers; i++) { struct buffer *b = &this->buffersi; @@ -2032,7 +2319,7 @@ static inline int do_drop(struct state *state) { int res; - spa_log_debug(state->log, "%p: snd_pcm_drop %u", state, state->linked); + spa_log_debug(state->log, "%p: snd_pcm_drop linked:%u", state, state->linked); if (!state->linked && (res = snd_pcm_drop(state->hndl)) < 0) { spa_log_error(state->log, "%s: snd_pcm_drop: %s", state->name, snd_strerror(res)); @@ -2045,7 +2332,7 @@ { int res; if (SPA_UNLIKELY(!state->alsa_started)) { - spa_log_debug(state->log, "%p: snd_pcm_start %u", state, state->linked); + spa_log_debug(state->log, "%p: snd_pcm_start linked:%u", state, state->linked); if (!state->linked && (res = snd_pcm_start(state->hndl)) < 0) { spa_log_error(state->log, "%s: snd_pcm_start: %s", state->name, snd_strerror(res)); @@ -2058,9 +2345,9 @@ static inline int check_position_config(struct state *state); -static int alsa_recover(struct state *state, int err) +static int alsa_recover(struct state *state) { - int res, st; + int res, st, retry = 0; snd_pcm_status_t *status; struct state *driver, *follower; @@ -2100,10 +2387,12 @@ case SND_PCM_STATE_SUSPENDED: spa_log_info(state->log, "%s: recover from state %s", state->name, snd_pcm_state_name(st)); - res = snd_pcm_resume(state->hndl); + while (retry++ < 5 && (res = snd_pcm_resume(state->hndl)) == -EAGAIN) + /* wait until suspend flag is released */ + poll(NULL, 0, 1000); if (res >= 0) - return res; - err = -ESTRPIPE; + return res; + /* try to drop and prepare below */ break; default: spa_log_error(state->log, "%s: recover from error state %s", @@ -2112,11 +2401,6 @@ } recover: - if (SPA_UNLIKELY((res = snd_pcm_recover(state->hndl, err, true)) < 0)) { - spa_log_error(state->log, "%s: snd_pcm_recover error: %s", - state->name, snd_strerror(res)); - return res; - } if (state->driver && state->linked) driver = state->driver; else @@ -2139,8 +2423,7 @@ if (follower != driver && follower->linked) do_start(follower); } - - return res; + return 0; } static inline snd_pcm_sframes_t alsa_avail(struct state *state) @@ -2159,7 +2442,7 @@ snd_pcm_sframes_t avail; if (SPA_UNLIKELY((avail = alsa_avail(state)) < 0)) { - if ((res = alsa_recover(state, avail)) < 0) + if ((res = alsa_recover(state)) < 0) return res; if ((avail = alsa_avail(state)) < 0) { if ((suppressed = spa_ratelimit_test(&state->rate_limit, current_time)) >= 0) { @@ -2351,7 +2634,8 @@ 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 = !state->pitch_elem && + (((uint32_t)state->rate != state->driver_rate.denom) || state->matching); recalc_headroom(state); spa_log_info(state->log, "driver clock:'%s'@%d our clock:'%s'@%d matching:%d resample:%d", @@ -2404,7 +2688,8 @@ state->threshold = SPA_SCALE32_UP(state->driver_duration, state->rate, state->driver_rate.denom); state->max_error = SPA_MAX(256.0f, state->threshold / 2.0f); state->max_resync = SPA_MIN(state->threshold, state->max_error); - state->resample = ((uint32_t)state->rate != state->driver_rate.denom) || state->matching; + state->resample = !state->pitch_elem && + (((uint32_t)state->rate != state->driver_rate.denom) || state->matching); state->alsa_sync = true; } return 0; @@ -2420,7 +2705,7 @@ return res; if (SPA_UNLIKELY((res = get_status(state, current_time, &avail, &delay, &target)) < 0)) { - spa_log_error(state->log, "get_status error"); + spa_log_error(state->log, "get_status error: %s", spa_strerror(res)); state->next_time += state->threshold * 1e9 / state->rate; return res; } @@ -2482,7 +2767,7 @@ if (SPA_UNLIKELY((res = snd_pcm_mmap_begin(hndl, &my_areas, &offset, &frames)) < 0)) { spa_log_error(state->log, "%s: snd_pcm_mmap_begin error: %s", state->name, snd_strerror(res)); - alsa_recover(state, res); + alsa_recover(state); return res; } spa_log_trace_fp(state->log, "%p: begin offset:%ld avail:%ld threshold:%d", @@ -2681,7 +2966,7 @@ return res; if (SPA_UNLIKELY((res = get_status(state, current_time, &avail, &delay, &target)) < 0)) { - spa_log_error(state->log, "get_status error"); + spa_log_error(state->log, "get_status error: %s", spa_strerror(res)); state->next_time += state->threshold * 1e9 / state->rate; return res; } @@ -2748,7 +3033,7 @@ if ((res = snd_pcm_mmap_begin(hndl, &my_areas, &offset, &avail)) < 0) { spa_log_error(state->log, "%s: snd_pcm_mmap_begin error: %s", state->name, snd_strerror(res)); - alsa_recover(state, res); + alsa_recover(state); return res; } spa_log_trace_fp(state->log, "%p: begin offs:%ld frames:%ld avail:%ld thres:%d", state, @@ -2919,6 +3204,11 @@ spa_log_trace_fp(state->log, "Woken up with no work to do"); return; } + if (revents & POLLERR) { + spa_log_trace_fp(state->log, "poll error"); + if ((res = alsa_recover(state)) < 0) + return; + } } else { if (SPA_LIKELY(state->started)) { if (SPA_UNLIKELY((res = spa_system_timerfd_read(state->data_system, @@ -3227,3 +3517,74 @@ return 0; } + +void spa_alsa_emit_node_info(struct state *state, bool full) +{ + uint64_t old = full ? state->info.change_mask : 0; + + if (full) + state->info.change_mask = state->info_all; + if (state->info.change_mask) { + struct spa_dict_item items7; + uint32_t i, n_items = 0; + char latency64, period64, nperiods64, headroom64; + + itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_API, "alsa"); + itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_MEDIA_CLASS, + state->stream == SND_PCM_STREAM_PLAYBACK ? "Audio/Sink" : "Audio/Source"); + itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_DRIVER, "true"); + if (state->have_format) { + snprintf(latency, sizeof(latency), "%lu/%d", state->buffer_frames / 2, state->rate); + itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_MAX_LATENCY, latency); + snprintf(period, sizeof(period), "%lu", state->period_frames); + itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.period-size", period); + snprintf(nperiods, sizeof(nperiods), "%lu", + state->period_frames != 0 ? state->buffer_frames / state->period_frames : 0); + itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.period-num", nperiods); + snprintf(headroom, sizeof(headroom), "%u", state->headroom); + itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.headroom", headroom); + } else { + itemsn_items++ = SPA_DICT_ITEM_INIT(SPA_KEY_NODE_MAX_LATENCY, NULL); + itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.period-size", NULL); + itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.period-num", NULL); + itemsn_items++ = SPA_DICT_ITEM_INIT("api.alsa.headroom", NULL); + } + state->info.props = &SPA_DICT_INIT(items, n_items); + + if (state->info.change_mask & SPA_NODE_CHANGE_MASK_PARAMS) { + for (i = 0; i < state->info.n_params; i++) { + if (state->paramsi.user > 0) { + state->paramsi.flags ^= SPA_PARAM_INFO_SERIAL; + state->paramsi.user = 0; + } + } + } + spa_node_emit_info(&state->hooks, &state->info); + + state->info.change_mask = old; + } +} + +void spa_alsa_emit_port_info(struct state *state, bool full) +{ + uint64_t old = full ? state->port_info.change_mask : 0; + + if (full) + state->port_info.change_mask = state->port_info_all; + if (state->port_info.change_mask) { + uint32_t i; + + if (state->port_info.change_mask & SPA_PORT_CHANGE_MASK_PARAMS) { + for (i = 0; i < state->port_info.n_params; i++) { + if (state->port_paramsi.user > 0) { + state->port_paramsi.flags ^= SPA_PARAM_INFO_SERIAL; + state->port_paramsi.user = 0; + } + } + } + spa_node_emit_port_info(&state->hooks, + state->stream == SND_PCM_STREAM_PLAYBACK ? SPA_DIRECTION_INPUT : SPA_DIRECTION_OUTPUT, + 0, &state->port_info); + state->port_info.change_mask = old; + } +}
View file
pipewire-0.3.84.tar.gz/spa/plugins/alsa/alsa-pcm.h -> pipewire-0.3.85.tar.gz/spa/plugins/alsa/alsa-pcm.h
Changed
@@ -92,6 +92,12 @@ unsigned int following:1; }; +struct bound_ctl { + char name256; + snd_ctl_elem_info_t *info; + snd_ctl_elem_value_t *value; +}; + struct state { struct spa_handle handle; struct spa_node node; @@ -240,11 +246,19 @@ struct spa_pod *tag2; - /* Rate match via an ALSA ctl */ + /* for rate match and bind ctls */ snd_ctl_t *ctl; + + /* Rate match via an ALSA ctl */ snd_ctl_elem_value_t *pitch_elem; double last_rate; + /* ALSA ctls exposed as params */ + unsigned int num_bind_ctls; + struct bound_ctl bound_ctls16; + struct spa_source ctl_sourcesMAX_POLL; + int ctl_n_fds; + struct spa_list link; struct spa_list followers; @@ -282,6 +296,9 @@ void spa_alsa_recycle_buffer(struct state *state, uint32_t buffer_id); +void spa_alsa_emit_node_info(struct state *state, bool full); +void spa_alsa_emit_port_info(struct state *state, bool full); + static inline uint32_t spa_alsa_format_from_name(const char *name, size_t len) { int i;
View file
pipewire-0.3.84.tar.gz/spa/plugins/bluez5/bap-codec-lc3.c -> pipewire-0.3.85.tar.gz/spa/plugins/bluez5/bap-codec-lc3.c
Changed
@@ -556,12 +556,13 @@ spa_pod_builder_int(b, 8000); spa_pod_builder_int(b, 8000); } - if (i == 0) - return -EINVAL; if (i > 1) choice->body.type = SPA_CHOICE_Enum; spa_pod_builder_pop(b, &f1); + if (i == 0) + return -EINVAL; + res = channels_to_positions(conf.channels, position); if (res == 0) return -EINVAL; @@ -674,6 +675,8 @@ if (endpoint_qos->latency >= 0x0005 && endpoint_qos->latency <= 0x0FA0) /* Values outside the range are RFU */ qos->latency = endpoint_qos->latency; + if (endpoint_qos->retransmission) + qos->retransmission = endpoint_qos->retransmission; if (endpoint_qos->delay_min) qos->delay = SPA_MAX(qos->delay, endpoint_qos->delay_min); if (endpoint_qos->delay_max)
View file
pipewire-0.3.84.tar.gz/spa/plugins/bluez5/bluez5-dbus.c -> pipewire-0.3.85.tar.gz/spa/plugins/bluez5/bluez5-dbus.c
Changed
@@ -971,6 +971,11 @@ goto error_invalid; } + spa_log_debug(monitor->log, "select qos: interval:%d framing:%d phy:%d sdu:%d " + "rtn:%d latency:%d delay:%d target_latency:%d", + qos.interval, qos.framing, qos.phy, qos.sdu, qos.retransmission, + qos.latency, (int)qos.delay, qos.target_latency); + dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry); dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &entry_key); dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "a{sv}", &variant); @@ -3465,6 +3470,9 @@ SPA_BT_PROFILE_BAP_BROADCAST_SINK | SPA_BT_PROFILE_BAP_BROADCAST_SOURCE))) continue; + if (t->device->adapter != transport->device->adapter) + continue; + if ((transport->profile == SPA_BT_PROFILE_BAP_BROADCAST_SINK) || (transport->profile == SPA_BT_PROFILE_BAP_BROADCAST_SOURCE)) { if (t->bap_big != transport->bap_big) @@ -3587,10 +3595,10 @@ /* For broadcast there initiator moves the transport state to SPA_BT_TRANSPORT_STATE_ACTIVE */ if ((transport->profile == SPA_BT_PROFILE_BAP_BROADCAST_SINK) || (transport->profile == SPA_BT_PROFILE_BAP_BROADCAST_SOURCE)) { - spa_bt_transport_set_state(transport, SPA_BT_TRANSPORT_STATE_ACTIVE); + spa_bt_transport_set_state(t_linked, SPA_BT_TRANSPORT_STATE_ACTIVE); } else { if (!transport->bap_initiator) - spa_bt_transport_set_state(transport, SPA_BT_TRANSPORT_STATE_ACTIVE); + spa_bt_transport_set_state(t_linked, SPA_BT_TRANSPORT_STATE_ACTIVE); } }
View file
pipewire-0.3.84.tar.gz/spa/plugins/bluez5/codec-loader.c -> pipewire-0.3.85.tar.gz/spa/plugins/bluez5/codec-loader.c
Changed
@@ -173,7 +173,7 @@ #undef MEDIA_CODEC_FACTORY_LIB }; - impl = calloc(sizeof(struct impl), 1); + impl = calloc(1, sizeof(struct impl)); if (impl == NULL) return NULL;
View file
pipewire-0.3.84.tar.gz/spa/plugins/bluez5/iso-io.c -> pipewire-0.3.85.tar.gz/spa/plugins/bluez5/iso-io.c
Changed
@@ -37,7 +37,7 @@ struct spa_source source; struct spa_list streams; int timerfd; - uint8_t cig; + uint8_t id; uint64_t next; uint64_t duration; uint32_t paused; @@ -155,7 +155,7 @@ if ((res = spa_system_timerfd_read(group->data_system, group->timerfd, &exp)) < 0) { if (res != -EAGAIN) spa_log_warn(group->log, "%p: ISO group:%u error reading timerfd: %s", - group, group->cig, spa_strerror(res)); + group, group->id, spa_strerror(res)); return; } @@ -178,7 +178,7 @@ if (group->paused) { --group->paused; - spa_log_debug(group->log, "%p: ISO group:%d paused:%u", group, group->cig, group->paused); + spa_log_debug(group->log, "%p: ISO group:%u paused:%u", group, group->id, group->paused); } /* Produce output */ @@ -194,7 +194,7 @@ } if (stream->this.size == 0) { spa_log_debug(group->log, "%p: ISO group:%u miss fd:%d", - group, group->cig, stream->fd); + group, group->id, stream->fd); if (stream_silence(stream) < 0) { fail = true; continue; @@ -208,7 +208,7 @@ } spa_log_trace(group->log, "%p: ISO group:%u sent fd:%d size:%u ts:%u idle:%d res:%d", - group, group->cig, stream->fd, (unsigned)stream->this.size, + group, group->id, stream->fd, (unsigned)stream->this.size, (unsigned)stream->this.timestamp, stream->idle, res); stream->this.size = 0; @@ -243,19 +243,29 @@ struct spa_log *log, struct spa_loop *data_loop, struct spa_system *data_system) { struct group *group; + uint8_t id; if (t->bap_interval <= 5000) { errno = EINVAL; return NULL; } + if (t->profile & (SPA_BT_PROFILE_BAP_SINK | SPA_BT_PROFILE_BAP_SOURCE)) { + id = t->bap_cig; + } else if (t->profile & (SPA_BT_PROFILE_BAP_BROADCAST_SINK | SPA_BT_PROFILE_BAP_BROADCAST_SOURCE)) { + id = t->bap_big; + } else { + errno = EINVAL; + return NULL; + } + group = calloc(1, sizeof(struct group)); if (group == NULL) return NULL; spa_log_topic_init(log, &log_topic); - group->cig = t->bap_cig; + group->id = id; group->log = log; group->data_loop = data_loop; group->data_system = data_system;
View file
pipewire-0.3.84.tar.gz/spa/plugins/bluez5/media-sink.c -> pipewire-0.3.85.tar.gz/spa/plugins/bluez5/media-sink.c
Changed
@@ -1405,6 +1405,21 @@ static void emit_node_info(struct impl *this, bool full) { + char node_group_buf256; + char *node_group = NULL; + + if (this->transport && (this->transport->profile & SPA_BT_PROFILE_BAP_SINK)) { + spa_scnprintf(node_group_buf, sizeof(node_group_buf), "bluez-iso-%s-cig-%d", + this->transport->device->adapter->address, + this->transport->bap_cig); + node_group = node_group_buf; + } else if (this->transport && (this->transport->profile & SPA_BT_PROFILE_BAP_BROADCAST_SINK)) { + spa_scnprintf(node_group_buf, sizeof(node_group_buf), "bluez-iso-%s-big-%d", + this->transport->device->adapter->address, + this->transport->bap_big); + node_group = node_group_buf; + } + struct spa_dict_item node_info_items = { { SPA_KEY_DEVICE_API, "bluez5" }, { SPA_KEY_MEDIA_CLASS, this->is_internal ? "Audio/Sink/Internal" : @@ -1412,6 +1427,7 @@ { "media.name", ((this->transport && this->transport->device->name) ? this->transport->device->name : this->codec->bap ? "BAP" : "A2DP" ) }, { SPA_KEY_NODE_DRIVER, this->is_output ? "true" : "false" }, + { "node.group", node_group }, }; uint64_t old = full ? this->info.change_mask : 0; if (full)
View file
pipewire-0.3.84.tar.gz/spa/plugins/libcamera/libcamera-device.cpp -> pipewire-0.3.85.tar.gz/spa/plugins/libcamera/libcamera-device.cpp
Changed
@@ -106,7 +106,7 @@ uint32_t n_items = 0; struct spa_device_info info; struct spa_param_info params2; - char path256, model256, name256, devices_str128; + char path256, name256, devices_str128; struct spa_strbuf buf; info = SPA_DEVICE_INFO_INIT(); @@ -123,9 +123,10 @@ if (auto location = cameraLoc(impl->camera.get())) ADD_ITEM(SPA_KEY_API_LIBCAMERA_LOCATION, location); - snprintf(model, sizeof(model), "%s", cameraModel(impl->camera.get()).c_str()); - ADD_ITEM(SPA_KEY_DEVICE_PRODUCT_NAME, model); - ADD_ITEM(SPA_KEY_DEVICE_DESCRIPTION, model); + const auto model = cameraModel(impl->camera.get()); + ADD_ITEM(SPA_KEY_DEVICE_PRODUCT_NAME, model.c_str()); + ADD_ITEM(SPA_KEY_DEVICE_DESCRIPTION, model.c_str()); + snprintf(name, sizeof(name), "libcamera_device.%s", impl->device_id.c_str()); ADD_ITEM(SPA_KEY_DEVICE_NAME, name);
View file
pipewire-0.3.84.tar.gz/src/daemon/pipewire-pulse.conf.in -> pipewire-0.3.85.tar.gz/src/daemon/pipewire-pulse.conf.in
Changed
@@ -31,6 +31,8 @@ rt.prio = 65 #rt.time.soft = -1 #rt.time.hard = -1 + #uclamp.min = 0 + #uclamp.max = 1024 } flags = ifexists nofail }
View file
pipewire-0.3.84.tar.gz/src/daemon/pipewire.conf.in -> pipewire-0.3.85.tar.gz/src/daemon/pipewire.conf.in
Changed
@@ -90,13 +90,16 @@ # Uses realtime scheduling to boost the audio thread priorities. This uses # RTKit if the user doesn't have permission to use regular realtime - # scheduling. + # scheduling. You can also clamp utilisation values to improve scheduling + # on embedded and heterogeneous systems, e.g. Arm big.LITTLE devices. { name = libpipewire-module-rt args = { nice.level = -11 #rt.prio = 88 #rt.time.soft = -1 #rt.time.hard = -1 + #uclamp.min = 0 + #uclamp.max = 1024 } flags = ifexists nofail }
View file
pipewire-0.3.84.tar.gz/src/daemon/systemd/system/meson.build -> pipewire-0.3.85.tar.gz/src/daemon/systemd/system/meson.build
Changed
@@ -3,7 +3,7 @@ systemd_system_services_dir = get_option('systemd-system-unit-dir') endif -install_data(sources : 'pipewire.socket', +install_data(sources : 'pipewire.socket', 'pipewire-manager.socket', install_dir : systemd_system_services_dir) systemd_config = configuration_data()
View file
pipewire-0.3.85.tar.gz/src/daemon/systemd/system/pipewire-manager.socket
Added
@@ -0,0 +1,13 @@ +Unit +Description=PipeWire Multimedia System Manager Socket + +Socket +Service=pipewire.service +Priority=6 +ListenStream=%t/pipewire/pipewire-0-manager +SocketUser=pipewire +SocketGroup=pipewire +SocketMode=0600 + +Install +WantedBy=sockets.target
View file
pipewire-0.3.84.tar.gz/src/daemon/systemd/system/pipewire.service.in -> pipewire-0.3.85.tar.gz/src/daemon/systemd/system/pipewire.service.in
Changed
@@ -31,5 +31,5 @@ Environment=PIPEWIRE_RUNTIME_DIR=%t/pipewire Install -Also=pipewire.socket +Also=pipewire.socket pipewire-manager.socket WantedBy=default.target
View file
pipewire-0.3.84.tar.gz/src/daemon/systemd/system/pipewire.socket -> pipewire-0.3.85.tar.gz/src/daemon/systemd/system/pipewire.socket
Changed
@@ -1,10 +1,9 @@ Unit -Description=PipeWire Multimedia System Sockets +Description=PipeWire Multimedia System Socket Socket Priority=6 ListenStream=%t/pipewire/pipewire-0 -ListenStream=%t/pipewire/pipewire-0-manager SocketUser=pipewire SocketGroup=pipewire SocketMode=0660
View file
pipewire-0.3.84.tar.gz/src/gst/gstpipewiresink.c -> pipewire-0.3.85.tar.gz/src/gst/gstpipewiresink.c
Changed
@@ -532,8 +532,13 @@ pw_stream_trigger_process (pwsink->stream); break; case PW_STREAM_STATE_ERROR: - GST_ELEMENT_ERROR (pwsink, RESOURCE, FAILED, - ("stream error: %s", error), (NULL)); + /* make the error permanent, if it is not already; + pw_stream_set_error() will recursively call us again */ + if (pw_stream_get_state (pwsink->stream, NULL) != PW_STREAM_STATE_ERROR) + pw_stream_set_error (pwsink->stream, -EPIPE, "%s", error); + else + GST_ELEMENT_ERROR (pwsink, RESOURCE, FAILED, + ("stream error: %s", error), (NULL)); break; } pw_thread_loop_signal (pwsink->core->loop, FALSE);
View file
pipewire-0.3.84.tar.gz/src/gst/gstpipewiresrc.c -> pipewire-0.3.85.tar.gz/src/gst/gstpipewiresrc.c
Changed
@@ -681,9 +681,13 @@ case PW_STREAM_STATE_STREAMING: break; case PW_STREAM_STATE_ERROR: - pw_stream_set_error (pwsrc->stream, -EPIPE, "%s", error); - GST_ELEMENT_ERROR (pwsrc, RESOURCE, FAILED, - ("stream error: %s", error), (NULL)); + /* make the error permanent, if it is not already; + pw_stream_set_error() will recursively call us again */ + if (pw_stream_get_state (pwsrc->stream, NULL) != PW_STREAM_STATE_ERROR) + pw_stream_set_error (pwsrc->stream, -EPIPE, "%s", error); + else + GST_ELEMENT_ERROR (pwsrc, RESOURCE, FAILED, + ("stream error: %s", error), (NULL)); break; } pw_thread_loop_signal (pwsrc->core->loop, FALSE);
View file
pipewire-0.3.84.tar.gz/src/modules/meson.build -> pipewire-0.3.85.tar.gz/src/modules/meson.build
Changed
@@ -218,8 +218,10 @@ summary({'ffado-driver': build_module_ffado_driver}, bool_yn: true, section: 'Optional Modules') opus_custom_h = cc.has_header('opus/opus_custom.h', dependencies: opus_dep) +opus_custom_lib = cc.has_function('opus_custom_encoder_ctl', dependencies: opus_dep) + # One would imagine that opus_dep is a requirement but for some reason it's not, so we need to manually check that -if opus_dep.found() and opus_custom_h +if opus_dep.found() and opus_custom_h and opus_custom_lib opus_custom_dep = declare_dependency(compile_args: '-DHAVE_OPUS_CUSTOM', dependencies: opus_dep) else opus_custom_dep = dependency('', required: false)
View file
pipewire-0.3.84.tar.gz/src/modules/module-pipe-tunnel.c -> pipewire-0.3.85.tar.gz/src/modules/module-pipe-tunnel.c
Changed
@@ -40,6 +40,7 @@ * ## Module Options * * - `tunnel.mode`: the desired tunnel to create. (Default `playback`) + * - `tunnel.may-pause`: if the tunnel stream is allowed to pause on xrun * - `pipe.filename`: the filename of the pipe. * - `stream.props`: Extra properties for the local stream. * @@ -55,6 +56,12 @@ * When `tunnel.mode` is `source`, a source node is created. Samples read from * the the pipe will be made available on the source. * + * `tunnel.may-pause` allows the tunnel stream to become inactive (paused) when + * there is no data in the fifo or when the fifo is full. For `capture` and + * `playback` `tunnel.mode` this is by default true. For `source` and `sink` + * `tunnel.mode`, this is by default false. A paused stream will consume no + * CPU and will resume when the fifo becomes readable or writable again. + * * When `pipe.filename` is not given, a default fifo in `/tmp/fifo_input` or * `/tmp/fifo_output` will be created that can be written and read respectively, * depending on the selected `tunnel.mode`. @@ -86,6 +93,7 @@ * { name = libpipewire-module-pipe-tunnel * args = { * tunnel.mode = playback + * #tunnel.may-pause = true * # Set the pipe name to tunnel to * pipe.filename = "/tmp/fifo_output" * #audio.format=<sample format> @@ -128,6 +136,7 @@ "( audio.channels=<number of channels> ) " \ "( audio.position=<channel map> ) " \ "( tunnel.mode=capture|playback|sink|source )" \ + "( tunnel.may-pause=<bool, if the stream can pause> )" \ "( pipe.filename=<filename> )" \ "( stream.props=<properties> ) " @@ -141,6 +150,7 @@ struct impl { struct pw_context *context; + struct pw_loop *main_loop; struct pw_loop *data_loop; #define MODE_PLAYBACK 0 @@ -174,6 +184,8 @@ unsigned int do_disconnect:1; unsigned int driving:1; unsigned int have_sync:1; + unsigned int may_pause:1; + unsigned int paused:1; struct spa_ringbuffer ring; void *buffer; @@ -262,7 +274,7 @@ break; case PW_STREAM_STATE_PAUSED: if (impl->direction == PW_DIRECTION_OUTPUT) { - pw_loop_update_io(impl->data_loop, impl->socket, 0); + pw_loop_update_io(impl->data_loop, impl->socket, impl->paused ? SPA_IO_IN : 0); set_timeout(impl, 0); } break; @@ -281,6 +293,26 @@ } } +static int do_pause(struct spa_loop *loop, bool async, uint32_t seq, const void *data, + size_t size, void *user_data) +{ + struct impl *impl = user_data; + const bool *paused = data; + pw_log_info("set paused: %d", *paused); + impl->paused = *paused; + pw_stream_set_active(impl->stream, !*paused); + return 0; +} + +static void pause_stream(struct impl *impl, bool paused) +{ + if (!impl->may_pause) + return; + if (impl->direction == PW_DIRECTION_INPUT) + pw_loop_update_io(impl->data_loop, impl->socket, paused ? SPA_IO_OUT : 0); + pw_loop_invoke(impl->main_loop, do_pause, 1, &paused, sizeof(bool), false, impl); +} + static void playback_stream_process(void *data) { struct impl *impl = data; @@ -308,8 +340,8 @@ continue; } else if (errno == EAGAIN || errno == EWOULDBLOCK) { /* Don't continue writing */ - pw_log_debug("pipe (%s) overrun: %m", - impl->filename); + pw_log_debug("pipe (%s) overrun: %m", impl->filename); + pause_stream(impl, true); break; } else { pw_log_warn("Failed to write to pipe (%s): %m", @@ -370,8 +402,10 @@ if (avail < (int32_t)size) { memset(bd->data, 0, size); - if (avail > 0) + if (avail >= 0) { pw_log_warn("underrun %d < %u", avail, size); + pause_stream(impl, true); + } impl->have_sync = false; } if (avail > (int32_t)RINGBUFFER_SIZE) { @@ -456,6 +490,8 @@ paramsn_params++ = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &impl->info); + impl->paused = false; + if ((res = pw_stream_connect(impl->stream, impl->direction, PW_ID_ANY, @@ -550,6 +586,8 @@ pw_loop_update_io(impl->data_loop, impl->socket, 0); return; } + if (impl->paused) + pause_stream(impl, false); if (mask & SPA_IO_IN) handle_pipe_read(impl); } @@ -839,6 +877,7 @@ impl->module = module; impl->context = context; + impl->main_loop = pw_context_get_main_loop(context); data_loop = pw_context_get_data_loop(context); impl->data_loop = pw_data_loop_get_loop(data_loop); @@ -848,22 +887,28 @@ if (spa_streq(str, "capture")) { impl->mode = MODE_CAPTURE; impl->direction = PW_DIRECTION_INPUT; + impl->may_pause = true; } else if (spa_streq(str, "playback")) { impl->mode = MODE_PLAYBACK; impl->direction = PW_DIRECTION_OUTPUT; + impl->may_pause = true; }else if (spa_streq(str, "sink")) { impl->mode = MODE_SINK; impl->direction = PW_DIRECTION_INPUT; + impl->may_pause = false; media_class = "Audio/Sink"; } else if (spa_streq(str, "source")) { impl->mode = MODE_SOURCE; impl->direction = PW_DIRECTION_OUTPUT; + impl->may_pause = false; media_class = "Audio/Source"; } else { pw_log_error("invalid tunnel.mode '%s'", str); res = -EINVAL; goto error; } + if ((str = pw_properties_get(props, "tunnel.may-pause")) != NULL) + impl->may_pause = spa_atob(str); if (pw_properties_get(props, PW_KEY_NODE_VIRTUAL) == NULL) pw_properties_set(props, PW_KEY_NODE_VIRTUAL, "true");
View file
pipewire-0.3.84.tar.gz/src/modules/module-protocol-native.c -> pipewire-0.3.85.tar.gz/src/modules/module-protocol-native.c
Changed
@@ -1489,6 +1489,7 @@ { struct pw_core *core = proxy->core; struct client *impl = SPA_CONTAINER_OF(core->conn, struct client, this); + ensure_loop(impl->context->main_loop); assert_single_pod(builder); marshal_core_footers(&impl->footer_state, core, builder); return core->send_seq = pw_protocol_native_connection_end(impl->connection, builder); @@ -1518,6 +1519,7 @@ { struct client_data *data = resource->client->user_data; struct pw_impl_client *client = resource->client; + ensure_loop(client->context->main_loop); assert_single_pod(builder); marshal_client_footers(&data->footer_state, client, builder); return client->send_seq = pw_protocol_native_connection_end(data->connection, builder);
View file
pipewire-0.3.84.tar.gz/src/modules/module-raop-sink.c -> pipewire-0.3.85.tar.gz/src/modules/module-raop-sink.c
Changed
@@ -1854,6 +1854,8 @@ if (pw_properties_get(props, PW_KEY_NODE_NAME) == NULL) pw_properties_setf(props, PW_KEY_NODE_NAME, "raop_sink.%s.%s.%s", hostname, ip, port); + if (pw_properties_get(props, PW_KEY_MEDIA_NAME) == NULL) + pw_properties_setf(props, PW_KEY_MEDIA_NAME, "RAOP to %s", name); if (pw_properties_get(props, PW_KEY_NODE_DESCRIPTION) == NULL) pw_properties_setf(props, PW_KEY_NODE_DESCRIPTION, "%s", name); if (pw_properties_get(props, PW_KEY_NODE_LATENCY) == NULL) @@ -1891,6 +1893,7 @@ copy_props(impl, props, PW_KEY_NODE_VIRTUAL); copy_props(impl, props, PW_KEY_MEDIA_CLASS); copy_props(impl, props, PW_KEY_MEDIA_FORMAT); + copy_props(impl, props, PW_KEY_MEDIA_NAME); copy_props(impl, props, "net.mtu"); copy_props(impl, props, "rtp.sender-ts-offset"); copy_props(impl, props, "sess.media");
View file
pipewire-0.3.84.tar.gz/src/modules/module-rt.c -> pipewire-0.3.85.tar.gz/src/modules/module-rt.c
Changed
@@ -82,6 +82,8 @@ * - `rlimits.enabled`: enable the use of rtlimits, default true. * - `rtportal.enabled`: enable the use of realtime portal, default true * - `rtkit.enabled`: enable the use of rtkit, default true + * - `uclamp.min`: the minimum utilisation value the scheduler should consider + * - `uclamp.max`: the maximum utilisation value the scheduler should consider * The nice level is by default set to an invalid value so that clients don't * automatically have the nice level raised. @@ -101,6 +103,8 @@ * #rlimits.enabled = true * #rtportal.enabled = true * #rtkit.enabled = true + * #uclamp.min = 0 + * #uclamp.max = 1024 * } * flags = ifexists nofail * } @@ -131,13 +135,18 @@ #define DEFAULT_RT_TIME_SOFT -1 #define DEFAULT_RT_TIME_HARD -1 +#define DEFAULT_UCLAMP_MIN 0 +#define DEFAULT_UCLAMP_MAX 1024 + #define MODULE_USAGE "( nice.level=<priority: default "SPA_STRINGIFY(DEFAULT_NICE_LEVEL)"(don't change)> ) " \ "( rt.prio=<priority: default "SPA_STRINGIFY(DEFAULT_RT_PRIO)"> ) " \ "( rt.time.soft=<in usec: default "SPA_STRINGIFY(DEFAULT_RT_TIME_SOFT)"> ) " \ "( rt.time.hard=<in usec: default "SPA_STRINGIFY(DEFAULT_RT_TIME_HARD)"> ) " \ "( rlimits.enabled=<default true> ) " \ "( rtportal.enabled=<default true> ) " \ - "( rtkit.enabled=<default true> ) " + "( rtkit.enabled=<default true> ) " \ + "( uclamp.min=<default "SPA_STRINGIFY(DEFAULT_UCLAMP_MIN)"> ) " \ + "( uclamp.max=<default "SPA_STRINGIFY(DEFAULT_UCLAMP_MAX)"> )" static const struct spa_dict_item module_props = { { PW_KEY_MODULE_AUTHOR, "Wim Taymans <wim.taymans@gmail.com>" }, @@ -183,6 +192,9 @@ rlim_t rt_time_soft; rlim_t rt_time_hard; + int uclamp_min; + int uclamp_max; + struct spa_hook module_listener; unsigned rlimits_enabled:1; @@ -537,6 +549,8 @@ int err, old_policy, new_policy, min, max; struct sched_param old_sched_params; struct sched_param new_sched_params; + struct rlimit old_rlim; + struct rlimit no_rlim = { -1, -1 }; int try = 0; if (!impl->rlimits_enabled) @@ -584,11 +598,21 @@ if ((old_policy & PW_SCHED_RESET_ON_FORK) != 0) new_policy |= PW_SCHED_RESET_ON_FORK; + /* Disable RLIMIT_RTTIME while trying new_policy. */ + if ((err = getrlimit(RLIMIT_RTTIME, &old_rlim)) < 0) + pw_log_debug("getrlimit() failed: %s", spa_strerror(err)); + if ((err = setrlimit(RLIMIT_RTTIME, &no_rlim)) < 0) + pw_log_debug("setrlimit() failed: %s", spa_strerror(err)); + if (pthread_setschedparam(pthread_self(), new_policy, &new_sched_params) == 0) { impl->rt_prio = new_sched_params.sched_priority; pthread_setschedparam(pthread_self(), old_policy, &old_sched_params); + if ((err = setrlimit(RLIMIT_RTTIME, &old_rlim)) < 0) + pw_log_debug("setrlimit() failed: %s", spa_strerror(err)); return true; } + if ((err = setrlimit(RLIMIT_RTTIME, &old_rlim)) < 0) + pw_log_debug("setrlimit() failed: %s", spa_strerror(err)); } pw_log_info("Can't set rt prio to %d: %m (try increasing rlimits)", (int)priority); return false; @@ -636,18 +660,18 @@ return res; } -static int set_rlimit(struct impl *impl) +static int set_rlimit(struct rlimit *rlim) { int res = 0; - if (setrlimit(RLIMIT_RTTIME, &impl->rl) < 0) + if (setrlimit(RLIMIT_RTTIME, rlim) < 0) res = -errno; if (res < 0) pw_log_debug("setrlimit() failed: %s", spa_strerror(res)); else pw_log_debug("rt.time.soft:%"PRIi64" rt.time.hard:%"PRIi64, - (int64_t)impl->rl.rlim_cur, (int64_t)impl->rl.rlim_max); + (int64_t)rlim->rlim_cur, (int64_t)rlim->rlim_max); return res; } @@ -1011,12 +1035,56 @@ impl->rl.rlim_cur = SPA_MIN(impl->rl.rlim_cur, impl->rttime_max); impl->rl.rlim_max = SPA_MIN(impl->rl.rlim_max, impl->rttime_max); - set_rlimit(impl); + set_rlimit(&impl->rl); return 0; } #endif /* HAVE_DBUS */ +int set_uclamp(int uclamp_min, int uclamp_max, pid_t pid) { +#ifdef __linux__ + int ret; + struct sched_attr { + uint32_t size; + uint32_t sched_policy; + uint64_t sched_flags; + int32_t sched_nice; + uint32_t sched_priority; + uint64_t sched_runtime; + uint64_t sched_deadline; + uint64_t sched_period; + uint32_t sched_util_min; + uint32_t sched_util_max; + } attr; + + ret = syscall(SYS_sched_getattr, pid, &attr, sizeof(struct sched_attr), 0); + if (ret) { + pw_log_warn("Could not retrieve scheduler attributes: %d", -errno); + return -errno; + } + + /* SCHED_FLAG_KEEP_POLICY | + * SCHED_FLAG_KEEP_PARAMS | + * SCHED_FLAG_UTIL_CLAMP_MIN | + * SCHED_FLAG_UTIL_CLAMP_MAX */ + attr.sched_flags = 0x8 | 0x10 | 0x20 | 0x40; + attr.sched_util_min = uclamp_min; + attr.sched_util_max = uclamp_max; + + ret = syscall(SYS_sched_setattr, pid, &attr, 0); + + if (ret) { + pw_log_warn("Could not set scheduler attributes: %d", -errno); + return -errno; + } + return 0; +#else + pw_log_warn("Setting UCLAMP values is only supported on Linux"); + return -EOPNOTSUPP; +#endif /* __linux__ */ +} + + SPA_EXPORT int pipewire__module_init(struct pw_impl_module *module, const char *args) { @@ -1047,6 +1115,8 @@ impl->rlimits_enabled = pw_properties_get_bool(props, "rlimits.enabled", true); impl->rtportal_enabled = pw_properties_get_bool(props, "rtportal.enabled", true); impl->rtkit_enabled = pw_properties_get_bool(props, "rtkit.enabled", true); + impl->uclamp_min = pw_properties_get_int32(props, "uclamp.min", DEFAULT_UCLAMP_MIN); + impl->uclamp_max = pw_properties_get_int32(props, "uclamp.max", DEFAULT_UCLAMP_MAX); impl->rl.rlim_cur = impl->rt_time_soft; impl->rl.rlim_max = impl->rt_time_hard; @@ -1086,7 +1156,15 @@ use_rtkit = can_use_rtkit; } if (!use_rtkit) - set_rlimit(impl); + set_rlimit(&impl->rl); + + if (impl->uclamp_max > 1024) { + pw_log_warn("uclamp.max out of bounds. Got %d, clamping to 1024.", impl->uclamp_max); + impl->uclamp_max = 1024; + } + + if (impl->uclamp_min || impl->uclamp_max < 1024) + set_uclamp(impl->uclamp_min, impl->uclamp_max, impl->main_pid); #ifdef HAVE_DBUS impl->use_rtkit = use_rtkit;
View file
pipewire-0.3.84.tar.gz/src/pipewire/context.c -> pipewire-0.3.85.tar.gz/src/pipewire/context.c
Changed
@@ -32,6 +32,8 @@ PW_LOG_TOPIC_EXTERN(log_context); #define PW_LOG_TOPIC_DEFAULT log_context +#define MAX_HOPS 64 + /** \cond */ struct impl { struct pw_context this; @@ -791,12 +793,17 @@ * and groups to active nodes and make them recursively runnable as well. */ static inline int run_nodes(struct pw_context *context, struct pw_impl_node *node, - struct spa_list *nodes, enum pw_direction direction) + struct spa_list *nodes, enum pw_direction direction, int hop) { struct pw_impl_node *t; struct pw_impl_port *p; struct pw_impl_link *l; + if (hop == MAX_HOPS) { + pw_log_warn("exceeded hops (%d)", hop); + return -EIO; + } + pw_log_debug("node %p: '%s' direction:%s", node, node->name, pw_direction_as_string(direction)); @@ -810,10 +817,12 @@ if (!t->active || !l->prepared || (!t->driving && SPA_FLAG_IS_SET(t->checked, 1u<<direction))) continue; + if (t->driving && p->node == t) + continue; pw_log_debug(" peer %p: '%s'", t, t->name); t->runnable = true; - run_nodes(context, t, nodes, direction); + run_nodes(context, t, nodes, direction, hop + 1); } } } else { @@ -824,10 +833,12 @@ if (!t->active || !l->prepared || (!t->driving && SPA_FLAG_IS_SET(t->checked, 1u<<direction))) continue; + if (t->driving && p->node == t) + continue; pw_log_debug(" peer %p: '%s'", t, t->name); t->runnable = true; - run_nodes(context, t, nodes, direction); + run_nodes(context, t, nodes, direction, hop + 1); } } } @@ -847,7 +858,7 @@ pw_log_debug(" group %p: '%s'", t, t->name); t->runnable = true; if (!t->driving) - run_nodes(context, t, nodes, direction); + run_nodes(context, t, nodes, direction, hop + 1); } } return 0; @@ -950,8 +961,8 @@ } spa_list_for_each(n, collect, sort_link) if (!n->driving && n->runnable) { - run_nodes(context, n, collect, PW_DIRECTION_OUTPUT); - run_nodes(context, n, collect, PW_DIRECTION_INPUT); + run_nodes(context, n, collect, PW_DIRECTION_OUTPUT, 0); + run_nodes(context, n, collect, PW_DIRECTION_INPUT, 0); } return 0;
View file
pipewire-0.3.84.tar.gz/src/pipewire/impl-client.h -> pipewire-0.3.85.tar.gz/src/pipewire/impl-client.h
Changed
@@ -13,6 +13,8 @@ /** \page page_client_impl Client Implementation * + * \see \ref pw_impl_client + * * \section sec_page_client_impl_overview Overview * * The \ref pw_impl_client object is created by a protocol implementation when @@ -51,7 +53,7 @@ * Each client has its own list of resources it is bound to along with * a mapping between the client types and server types. * - * See: \ref page_client_impl + * \see \ref page_client_impl */ /**
View file
pipewire-0.3.84.tar.gz/src/pipewire/impl-link.c -> pipewire-0.3.85.tar.gz/src/pipewire/impl-link.c
Changed
@@ -884,9 +884,11 @@ impl->activated = false; pw_log_info("(%s) deactivated", this->name); - link_update_state(this, this->destroyed ? - PW_LINK_STATE_INIT : PW_LINK_STATE_PAUSED, - 0, NULL); + + if (this->info.state < PW_LINK_STATE_PAUSED || this->destroyed) + link_update_state(this, PW_LINK_STATE_INIT, 0, NULL); + else + link_update_state(this, PW_LINK_STATE_PAUSED, 0, NULL); return 0; }
View file
pipewire-0.3.84.tar.gz/src/pipewire/proxy.h -> pipewire-0.3.85.tar.gz/src/pipewire/proxy.h
Changed
@@ -13,6 +13,8 @@ /** \page page_proxy Proxy * + * \see \ref pw_proxy + * * \section sec_page_proxy_overview Overview * * The proxy object is a client side representation of a resource @@ -76,7 +78,7 @@ * invoked by the client to PipeWire messages. Events will call the handlers * set in listener. * - * See \ref page_proxy + * \see \ref page_proxy */ /**
View file
pipewire-0.3.84.tar.gz/src/pipewire/stream.h -> pipewire-0.3.85.tar.gz/src/pipewire/stream.h
Changed
@@ -11,6 +11,8 @@ /** \page page_streams Streams * + * \see \ref pw_stream + * * \section sec_overview Overview * * \ref pw_stream "Streams" are used to exchange data with the @@ -162,7 +164,7 @@ * The stream object provides a convenient way to send and * receive data streams from/to PipeWire. * - * See also \ref page_streams and \ref api_pw_core + * \see \ref page_streams, \ref api_pw_core */ /**
View file
pipewire-0.3.84.tar.gz/src/pipewire/thread-loop.h -> pipewire-0.3.85.tar.gz/src/pipewire/thread-loop.h
Changed
@@ -13,6 +13,8 @@ /** \page page_thread_loop Thread Loop * + * \see \ref pw_thread_loop + * * \section sec_thread_loop_overview Overview * * The threaded loop implementation is a special wrapper around the @@ -68,7 +70,7 @@ * All of the loop callbacks will be executed with the loop * lock held. * - * See also \ref page_thread_loop + * \see \ref page_thread_loop */ /**
View file
pipewire-0.3.84.tar.gz/src/pipewire/utils.c -> pipewire-0.3.85.tar.gz/src/pipewire/utils.c
Changed
@@ -162,7 +162,7 @@ * \since 0.3.84 */ SPA_EXPORT -int pw_strv_find(char **a, char *b) +int pw_strv_find(char **a, const char *b) { int i; if (a == NULL || b == NULL)
View file
pipewire-0.3.84.tar.gz/src/pipewire/utils.h -> pipewire-0.3.85.tar.gz/src/pipewire/utils.h
Changed
@@ -48,7 +48,7 @@ char **pw_strv_parse(const char *val, size_t len, int max_tokens, int *n_tokens); -int pw_strv_find(char **a, char *b); +int pw_strv_find(char **a, const char *b); int pw_strv_find_common(char **a, char **b);
View file
pipewire-0.3.84.tar.gz/src/tools/pw-top.c -> pipewire-0.3.85.tar.gz/src/tools/pw-top.c
Changed
@@ -282,7 +282,7 @@ } static const struct pw_node_events node_events = { - PW_VERSION_NODE, + PW_VERSION_NODE_EVENTS, .info = node_info, .param = node_param, };
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
.