Projects
Essentials
pipewire-aptx
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 14
View file
pipewire-aptx.changes
Changed
@@ -1,4 +1,9 @@ ------------------------------------------------------------------- +Wed Sep 7 13:36:51 UTC 2022 - Bjørn Lie <zaitor@opensuse.org> + +- Update to version 0.3.57 + +------------------------------------------------------------------- Thu Jul 21 12:08:38 UTC 2022 - Bjørn Lie <zaitor@opensuse.org> - Update to version 0.3.56
View file
pipewire-aptx.spec
Changed
@@ -7,7 +7,7 @@ %define soversion 0_2 Name: pipewire-aptx -Version: 0.3.56 +Version: 0.3.57 Release: 0 Summary: PipeWire Bluetooth aptX codec plugin License: MIT @@ -20,6 +20,7 @@ BuildRequires: pkgconfig BuildRequires: pkgconfig(bluez) BuildRequires: pkgconfig(dbus-1) +BuildRequires: pkgconfig(glib-2.0) BuildRequires: pkgconfig(libfreeaptx) BuildRequires: pkgconfig(sbc)
View file
pipewire-0.3.56.tar.gz/.cirrus.yml -> pipewire-0.3.57.tar.gz/.cirrus.yml
Changed
@@ -1,7 +1,7 @@ task: freebsd_instance: matrix: - - image_family: freebsd-13-0-snap + - image_family: freebsd-13-1-snap env: # /usr/ports/Mk/Uses/localbase.mk localbase:ldflags LOCALBASE: /usr/local
View file
pipewire-0.3.56.tar.gz/NEWS -> pipewire-0.3.57.tar.gz/NEWS
Changed
@@ -1,3 +1,93 @@ +# PipeWire 0.3.57 (2022-09-02) + +This is a bugfix release that is API and ABI compatible with previous +0.3.x releases. + +## Highlights + +## PipeWire + - Support masking of conf.d/ files. (#2629) + - Add some more debug info to memfd. + - Improve data-loop invoke method. Also flush pending items. (#2631) + - Add a filter-chain systemd service file than can be used to start + custom filters placed in ~/.conf/pipewire/filter-chain.d/ (#2553) + - Improve triggered timestamps for remote nodes. + - Fix some potential cross compilation problems due to wrong + host_machine. + - Check return values of pw_getrandom(). + + +## Tools + - Updates to pw-cli manpages. (#2552) + - Remove the pw-cli dump command. It is mostly implemented as part of + wpctl status, pw-dump, pw-link, pw-top and others. + - Clean up resource in pw-cat correctly on errors. (#2651) + +## Modules + - Fix compilation of AVB on big-endian. Enable AVB only on Linux. + - Use org.freedesktop.portal.Realtime when available. This does the + correct PID/TID mappings to make realtime also work from flatpaks. + - Fix compilation of ROC module when headers are missing. (#2513) + - Improve some error cleanup paths in protocol-native. Improve connect + and disconnect. + - Fix a potential crash in FFT unload in filter-chain. + - Implement PIPEWIRE_NOTIFICATION_FD for notification when the socket + is ready. + - Try to use rtkit if set_nice() fails. + - Fix rate adjustement logic in pulse-tunnel. This would cause + increasing delays and hickups when using tunnels. (#2548) + - Handle disconnect in pulse-tunnel. + +## Bluetooth + - Add OPUS as a new vendor codec. Add OPUS-A2DP spec. PipeWire can now + send and reveive OPUS data over bluetooth. + - An AAC decoder was added so that PipeWire can now also function as + an A2DP AAC receiver. + +## SPA + - Tweak the resampler window function some more. (#2574) + - Improve format convert performance in some fallback cases. + - Fix rounding in format conversion on ARM NEON. + - Fix libcamera build error. (#2575) + - Fix some issues where the wrong samplerate was used. (#2614) + - Don't wait for more samples that can fit in the ringbuffer in ALSA. + - Improve buffer size handling in audioconvert, scale the buffers based + on the rate conversion and make things work with really large rate + conversions as well. + - Add more and better debug for ALSA devices. + - Improve channel mix: Filter FC and LFE when copying from a different + layout. Implement STEREO from FC. Avoid generating REAR from FC in PSD + mode. + - Fix rate match for sources. This fixes an error where follower sources + would generate many resync warnings. + - Improve ALSA format negotiation. If the ALSA node is not running and + there was a previously configured format, close and reopen the device + to enumerate and accept all possible formats again. (#2625). + +## ALSA + - The alsa plugin will now also save the volumes set with the control + API. This saves the volumes set with alsa-mixer, for example. + +## Pulse-server + - Flatpak apps with devices=all (Zoom) will now be granted Manager + permissions. + - Small tweaks to the amount of data sent to clients to work around an + issue in freerdp. + +## JACK + - Clean up the transport correctly when closing a client. (#2569) + - Match context properties in addition to node properties for the jack + client rules. (#2580) + - Make sure to return an error when disconnected from the server. (#2606) + - Fix thread cast problem in jack_client_thread_id(). + - Increase jack_client_name_size() length and make sure we have space for + the \0 byte. + - JACK clients from the same application will be added to the same group + so that they share the quantum and rate. + + +Older versions: + # PipeWire 0.3.56 (2022-07-19) This is a quick bugfix release that is API and ABI compatible with previous @@ -52,8 +142,6 @@ - Add the resampler delay to delay reporting as well. -Older versions: - # PipeWire 0.3.55 (2022-07-12) This is a quick bugfix release that is API and ABI compatible with previous
View file
pipewire-0.3.56.tar.gz/doc/tutorial3.c -> pipewire-0.3.57.tar.gz/doc/tutorial3.c
Changed
@@ -7,32 +7,36 @@ #include <pipewire/pipewire.h> /* roundtrip */ -static int roundtrip(struct pw_core *core, struct pw_main_loop *loop) +struct roundtrip_data { + int pending; + struct pw_main_loop *loop; +}; + +static void on_core_done(void *data, uint32_t id, int seq) +{ + struct roundtrip_data *d = data; + + if (id == PW_ID_CORE && seq == d->pending) + pw_main_loop_quit(d->loop); +} + +static void roundtrip(struct pw_core *core, struct pw_main_loop *loop) { - struct spa_hook core_listener; - int pending, done = 0; - void core_event_done(void *object, uint32_t id, int seq) { - if (id == PW_ID_CORE && seq == pending) { - done = 1; - pw_main_loop_quit(loop); - } - } - const struct pw_core_events core_events = { - PW_VERSION_CORE_EVENTS, - .done = core_event_done, - }; - - spa_zero(core_listener); - pw_core_add_listener(core, &core_listener, - &core_events, NULL); - - pending = pw_core_sync(core, PW_ID_CORE, 0); - - while (!done) { - pw_main_loop_run(loop); - } - spa_hook_remove(&core_listener); - return 0; + static const struct pw_core_events core_events = { + PW_VERSION_CORE_EVENTS, + .done = on_core_done, + }; + + struct roundtrip_data d = { .loop = loop }; + struct spa_hook core_listener; + + pw_core_add_listener(core, &core_listener, &core_events, &d); + + d.pending = pw_core_sync(core, PW_ID_CORE, 0); + + pw_main_loop_run(loop); + + spa_hook_remove(&core_listener); } /* roundtrip */ @@ -50,37 +54,36 @@ int main(int argc, char *argv) { - struct pw_main_loop *loop; - struct pw_context *context; - struct pw_core *core; - struct pw_registry *registry; - struct spa_hook registry_listener; + struct pw_main_loop *loop; + struct pw_context *context; + struct pw_core *core; + struct pw_registry *registry; + struct spa_hook registry_listener; - pw_init(&argc, &argv); + pw_init(&argc, &argv); - loop = pw_main_loop_new(NULL /* properties */); - context = pw_context_new(pw_main_loop_get_loop(loop), - NULL /* properties */, - 0 /* user_data size */); + loop = pw_main_loop_new(NULL /* properties */); + context = pw_context_new(pw_main_loop_get_loop(loop), + NULL /* properties */, + 0 /* user_data size */); - core = pw_context_connect(context, - NULL /* properties */, - 0 /* user_data size */); + core = pw_context_connect(context, + NULL /* properties */, + 0 /* user_data size */); - registry = pw_core_get_registry(core, PW_VERSION_REGISTRY, - 0 /* user_data size */); + registry = pw_core_get_registry(core, PW_VERSION_REGISTRY, + 0 /* user_data size */); - spa_zero(registry_listener); - pw_registry_add_listener(registry, ®istry_listener, - ®istry_events, NULL); + pw_registry_add_listener(registry, ®istry_listener, + ®istry_events, NULL); - roundtrip(core, loop); + roundtrip(core, loop); - pw_proxy_destroy((struct pw_proxy*)registry); - pw_core_disconnect(core); - pw_context_destroy(context); - pw_main_loop_destroy(loop); + pw_proxy_destroy((struct pw_proxy*)registry); + pw_core_disconnect(core); + pw_context_destroy(context); + pw_main_loop_destroy(loop); - return 0; + return 0; } /* code */
View file
pipewire-0.3.56.tar.gz/doc/tutorial3.dox -> pipewire-0.3.57.tar.gz/doc/tutorial3.dox
Changed
@@ -15,10 +15,9 @@ Let's take a look at what this method does. \code{.c} - struct spa_hook core_listener; - spa_zero(core_listener); - pw_core_add_listener(core, &core_listener, - &core_events, NULL); + struct spa_hook core_listener; + + pw_core_add_listener(core, &core_listener, &core_events, &d); \endcode First of all we add a listener for the events of the core @@ -26,37 +25,31 @@ tutorial. This is the event handler: \code{.c} - int pending, done = 0; - - void core_event_done(void *data, uint32_t id, int seq) { - if (id == PW_ID_CORE && seq == pending) { - done = 1; - pw_main_loop_quit(loop); - } - } - const struct pw_core_events core_events = { - PW_VERSION_CORE_EVENTS, - .done = core_event_done, - }; +static void on_core_done(void *data, uint32_t id, int seq) +{ + struct roundtrip_data *d = data; + + if (id == PW_ID_CORE && seq == d->pending) + pw_main_loop_quit(d->loop); +} \endcode -When the done event is received for an object with id `PW_ID_CORE` -and a certain sequence number `seq`, this function will set the done -variable to 1 and call `pw_main_loop_quit()`. +When the done event is received for an object with id `PW_ID_CORE` and +a certain sequence number `seq`, this function will call `pw_main_loop_quit()`. Next we do: \code{.c} - pending = pw_core_sync(core, PW_ID_CORE, 0); + d.pending = pw_core_sync(core, PW_ID_CORE, 0); \endcode This triggers the `sync` method on the core object with id `PW_ID_CORE` and sequence number 0. Because this is a method on a proxy object, it will be executed -asynchronously and the returns value will reflect this. PipeWire +asynchronously and the return value will reflect this. PipeWire uses the return values of the underlying SPA (Simple Plugin API) -helper objects (See also error codes(spa-design.md#error-codes)). +helper objects (See also \ref page_spa_design ). Because all messages on the PipeWire server are handled sequentially, the sync method will be executed after all previous methods are @@ -68,9 +61,7 @@ receive the events: \code{.c} - while (!done) { - pw_main_loop_run(loop); - } + pw_main_loop_run(loop); \endcode When we get the done event, we can compare it to the sync method @@ -79,7 +70,7 @@ remove the listener: \code{.c} - spa_hook_remove(&core_listener); + spa_hook_remove(&core_listener); \endcode If we add this roundtrip method to our code and call it instead of the @@ -100,7 +91,7 @@ created them: \code{.c} - pw_proxy_destroy((struct pw_proxy*)registry); + pw_proxy_destroy((struct pw_proxy*)registry); \endcode The registry is a proxy and can be destroyed with the generic proxy destroy @@ -110,7 +101,7 @@ We can disconnect from the server with: \code{.c} - pw_core_disconnect(core); + pw_core_disconnect(core); \endcode This will also destroy the core proxy object and will remove the proxies @@ -119,8 +110,8 @@ We can finally destroy our context and mainloop to conclude this tutorial: \code{.c} - pw_context_destroy(context); - pw_main_loop_destroy(loop); + pw_context_destroy(context); + pw_main_loop_destroy(loop); \endcode \ref page_tutorial2 | \ref page_tutorial "Index" | \ref page_tutorial4
View file
pipewire-0.3.56.tar.gz/man/pw-cli.1.rst.in -> pipewire-0.3.57.tar.gz/man/pw-cli.1.rst.in
Changed
@@ -34,17 +34,20 @@ GENERAL COMMANDS ================ -help - Show a quick help on the commands available. +help | h + Show a quick help on the commands available. It also lists the aliases + for many commands. -quit +quit | q Exit from **pw-cli** MODULE MANAGEMENT ================= -| Modules are loaded and unloaded in the local instance and can add -| functionality or objects to the local instance. +| Modules are loaded and unloaded in the local instance, thus the pw-cli +| binary itself and can add functionality or objects to the local +| instance. It is not possible in PipeWire to load modules in another +| instance. load-module *name* *arguments...* Load a module specified by its name and arguments. For most @@ -105,14 +108,22 @@ This command returns a *node variable*. -destroy-node *node-var* - Destroy a node. - export-node *node-id* *remote-var* Export a node from the local instance to the specified instance. When no instance is specified, the node will be exported to the current instance. +DEVICE MANAGEMENT +================= + +create-device *factory-name* *properties...* + Create a device from a factory in the current instance. + + Properties are key=value pairs separated by whitespace. + + This command returns a *device variable*. + + LINK MANAGEMENT =============== @@ -125,8 +136,44 @@ This command returns a *link variable*. -destroy-link *link-var* - Destroy a link. +GLOBALS MANAGEMENT +================== + +destroy *object-id* + Destroy a global object. + + +PARAMETER MANAGEMENT +==================== + +enum-params *object-id* *param-id* + Enumerate params of an object. + + *param-id* can also be given as the param short name. + +set-param *object-id* *param-id* *param-json* + Set param of an object. + + *param-id* can also be given as the param short name. + +PERMISSION MANAGEMENT +===================== + +permissions *client-id* *object-id* *permission* + Set permissions for a client. + + *object-id* can be *-1* to set the default permissions. + +get-permissions *client-id* + Get permissions of a client. + + +COMMAND MANAGEMENT +================== + +send-command *object-id* + Send a command to an object. + EXAMPLES ========
View file
pipewire-0.3.56.tar.gz/meson.build -> pipewire-0.3.57.tar.gz/meson.build
Changed
@@ -1,5 +1,5 @@ project('pipewire', 'c' , - version : '0.3.56', + version : '0.3.57', license : 'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' , meson_version : '>= 0.59.0', default_options : 'warning_level=3', @@ -295,6 +295,11 @@ cap_lib = dependency('libcap', required : false) cdata.set('HAVE_LIBCAP', cap_lib.found()) +glib2_dep = dependency('glib-2.0', required : get_option('flatpak')) +summary({'GLib-2.0 (Flatpak support)': glib2_dep.found()}, bool_yn: true, section: 'Misc dependencies') +flatpak_support = glib2_dep.found() +cdata.set('HAVE_GLIB2', flatpak_support) + gst_option = get_option('gstreamer') gst_deps_def = { 'glib-2.0': {'version': '>=2.32.0'}, @@ -337,11 +342,11 @@ cdata.set('HAVE_WEBRTC', webrtc_dep.found()) # On FreeBSD and MidnightBSD, epoll-shim library is required for eventfd() and timerfd() -epoll_shim_dep = (build_machine.system() == 'freebsd' or build_machine.system() == 'midnightbsd' +epoll_shim_dep = (host_machine.system() == 'freebsd' or host_machine.system() == 'midnightbsd' ? dependency('epoll-shim', required: true) : dependency('', required: false)) -libinotify_dep = (build_machine.system() == 'freebsd' or build_machine.system() == 'midnightbsd' +libinotify_dep = (host_machine.system() == 'freebsd' or host_machine.system() == 'midnightbsd' ? dependency('libinotify', required: true) : dependency('', required: false)) @@ -356,7 +361,7 @@ alsa_dep = dependency('alsa', version : '>=1.1.7', required: need_alsa) summary({'pipewire-alsa': alsa_dep.found()}, bool_yn: true) -if build_machine.system() == 'freebsd' or build_machine.system() == 'midnightbsd' +if host_machine.system() == 'freebsd' or host_machine.system() == 'midnightbsd' # On FreeBSD and MidnightBSD the OpenSSL library may come from base or a package. # Check for a package first and fallback to the base library if we can't find it via pkgconfig openssl_lib = dependency('openssl', required: false)
View file
pipewire-0.3.56.tar.gz/meson_options.txt -> pipewire-0.3.57.tar.gz/meson_options.txt
Changed
@@ -116,6 +116,10 @@ description: 'Enable LC3plus open source codec implementation', type: 'feature', value: 'auto') +option('bluez5-codec-opus', + description: 'Enable Opus open source codec implementation', + type: 'feature', + value: 'auto') option('control', description: 'Enable control spa plugin integration', type: 'feature', @@ -249,3 +253,7 @@ description: 'Enable AVB code', type: 'feature', value: 'auto') +option('flatpak', + description: 'Enable Flatpak support', + type: 'feature', + value: 'enabled')
View file
pipewire-0.3.56.tar.gz/pipewire-alsa/alsa-plugins/ctl_pipewire.c -> pipewire-0.3.57.tar.gz/pipewire-alsa/alsa-plugins/ctl_pipewire.c
Changed
@@ -532,6 +532,7 @@ spa_pod_builder_add(&b, SPA_PARAM_ROUTE_index, SPA_POD_Int(id), SPA_PARAM_ROUTE_device, SPA_POD_Int(device_id), + SPA_PARAM_ROUTE_save, SPA_POD_Bool(true), 0); spa_pod_builder_prop(&b, SPA_PARAM_ROUTE_props, 0);
View file
pipewire-0.3.56.tar.gz/pipewire-jack/src/pipewire-jack.c -> pipewire-0.3.57.tar.gz/pipewire-jack/src/pipewire-jack.c
Changed
@@ -62,7 +62,7 @@ #define DEFAULT_RT_MAX 88 -#define JACK_CLIENT_NAME_SIZE 128 +#define JACK_CLIENT_NAME_SIZE 256 #define JACK_PORT_NAME_SIZE 256 #define JACK_PORT_TYPE_SIZE 32 #define MONITOR_EXT " Monitor" @@ -800,7 +800,7 @@ } else { \ if (c->active) \ (expr); \ - pw_log_debug("skip " #callback \ + pw_log_debug("skip " #callback \ " cb:%p active:%d", c->callback, \ c->active); \ } \ @@ -817,6 +817,9 @@ res = c->callback(__VA_ARGS__); \ c->rt_locked = false; \ pthread_mutex_unlock(&c->rt_lock); \ + } else { \ + pw_log_debug("skip " #callback \ + " cb:%p", c->callback); \ } \ } \ res; \ @@ -871,6 +874,8 @@ pw_log_warn("sync requested from callback"); return 0; } + if (client->last_res == -EPIPE) + return -EPIPE; client->last_res = 0; client->pending_sync = pw_proxy_sync((struct pw_proxy*)client->core, client->pending_sync); @@ -3279,7 +3284,7 @@ "jack.properties", client->props); pw_context_conf_section_match_rules(client->context.context, "jack.rules", - &client->props->dict, execute_match, client); + &client->context.context->properties->dict, execute_match, client); support = pw_context_get_support(client->context.context, &n_support); @@ -3356,6 +3361,8 @@ } if (pw_properties_get(client->props, PW_KEY_NODE_NAME) == NULL) pw_properties_set(client->props, PW_KEY_NODE_NAME, client_name); + if (pw_properties_get(client->props, PW_KEY_NODE_GROUP) == NULL) + pw_properties_setf(client->props, PW_KEY_NODE_GROUP, "jack-%d", getpid()); if (pw_properties_get(client->props, PW_KEY_NODE_DESCRIPTION) == NULL) pw_properties_set(client->props, PW_KEY_NODE_DESCRIPTION, client_name); if (pw_properties_get(client->props, PW_KEY_MEDIA_TYPE) == NULL) @@ -3492,6 +3499,8 @@ res = jack_deactivate(client); + clean_transport(c); + if (c->context.loop) pw_thread_loop_stop(c->context.loop); @@ -3577,8 +3586,9 @@ SPA_EXPORT int jack_client_name_size (void) { - pw_log_trace("%d", JACK_CLIENT_NAME_SIZE); - return JACK_CLIENT_NAME_SIZE; + /* The JACK API specifies that this value includes the final NULL character. */ + pw_log_trace("%d", JACK_CLIENT_NAME_SIZE+1); + return JACK_CLIENT_NAME_SIZE+1; } SPA_EXPORT @@ -3765,12 +3775,12 @@ struct client *c = (struct client *) client; void *thr; - spa_return_val_if_fail(c != NULL, -EINVAL); + spa_return_val_if_fail(c != NULL, (pthread_t){0}); thr = pw_data_loop_get_thread(c->loop); if (thr == NULL) return pthread_self(); - return *(pthread_t*)thr; + return (pthread_t) thr; } SPA_EXPORT
View file
pipewire-0.3.56.tar.gz/po/LINGUAS -> pipewire-0.3.57.tar.gz/po/LINGUAS
Changed
@@ -21,6 +21,7 @@ id it ja +ka kk kn ko
View file
pipewire-0.3.56.tar.gz/po/ca.po -> pipewire-0.3.57.tar.gz/po/ca.po
Changed
@@ -5,6 +5,7 @@ # Xavier Conde Rueda <xavi.conde@gmail.com>, 2008. # Agustí Grau <fletxa@gmail.com>, 2009. # Judith Pintó Subirada <judithp@gmail.com> +# Jordi Mas i Herǹandez, <jmas@softcatala.org>, 2022 # # This file is translated according to the glossary and style guide of # Softcatalà. If you plan to modify this file, please read first the page @@ -26,11 +27,10 @@ msgid "" msgstr "" "Project-Id-Version: pipewire\n" -"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/" -"issues/new\n" +"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/issues/new\n" "POT-Creation-Date: 2021-04-18 16:54+0800\n" -"PO-Revision-Date: 2012-01-30 09:52+0000\n" -"Last-Translator: Josep Torné Llavall <josep.torne@gmail.com>\n" +"PO-Revision-Date: 2022-09-01 19:24+0000\n" +"Last-Translator: Jordi Mas i Herǹandez, <jmas@softcatala.org>,\n" "Language-Team: Catalan <fedora@softcatala.net>\n" "Language: ca\n" "MIME-Version: 1.0\n" @@ -45,14 +45,18 @@ " --version Show version\n" " -c, --config Load config (Default %s)\n" msgstr "" +"%s opcions\n" +" -h, --help Mostra aquesta ajuda\n" +" --version Mostra la versió\n" +" -c, --config Carrega la configuració (predeterminada %s)\n" #: src/daemon/pipewire.desktop.in:4 msgid "PipeWire Media System" -msgstr "" +msgstr "Sistema multimèdia PipeWire" #: src/daemon/pipewire.desktop.in:5 msgid "Start the PipeWire Media System" -msgstr "" +msgstr "Inicia el sistema multimèdia PipeWire" #: src/examples/media-session/alsa-monitor.c:526 #: spa/plugins/alsa/acp/compat.c:187 @@ -66,7 +70,7 @@ #: src/examples/media-session/alsa-monitor.c:539 msgid "Unknown device" -msgstr "" +msgstr "Dispositiu desconegut" #: src/tools/pw-cat.c:991 #, c-format @@ -77,9 +81,13 @@ " -v, --verbose Enable verbose operations\n" "\n" msgstr "" +"%s opcions <fitxer>\n" +" -h, --help Mostra aquesta ajuda\n" +" --version Mostra la versió\n" +" -v, --verbose Habilita les operacions detallades\n" #: src/tools/pw-cat.c:998 -#, c-format +#, c-format, fuzzy msgid "" " -R, --remote Remote daemon name\n" " --media-type Set media type (default %s)\n" @@ -90,42 +98,58 @@ " --latency Set node latency (default %s)\n" " Xunit (unit = s, ms, us, ns)\n" " or direct samples (256)\n" -" the rate is the one of the source " -"file\n" +" the rate is the one of the source file\n" " --list-targets List available targets for --target\n" "\n" msgstr "" +"-R, --remote Nom del dimoni remot\n" +" --media-type Estableix el tipus de mitjà (per defecte %s)\n" +" --media-category Estableix la categoria dels mitjans (per defecte %s)\n" +" --media-role Estableix el rol del mitjà (per defecte %s)\n" +" --target Estableix l'objectiu del node (per defecte %s)\n" +" 0 vol dir que no enllaça\n" +" --latency Estableix latència del node (per defecte %s)\n" +" Xunit (unitat = s, ms, us, ns)\n" +" o mostres directes (256)\n" +" la taxa és la del fitxer d'origen\n" +" --list-targets Llista d'objectius disponibles per a --target" #: src/tools/pw-cat.c:1016 -#, c-format +#, c-format, fuzzy msgid "" -" --rate Sample rate (req. for rec) (default " -"%u)\n" -" --channels Number of channels (req. for rec) " -"(default %u)\n" +" --rate Sample rate (req. for rec) (default %u)\n" +" --channels Number of channels (req. for rec) (default %u)\n" " --channel-map Channel map\n" -" one of: \"stereo\", " -"\"surround-51\",... or\n" -" comma separated list of channel " -"names: eg. \"FL,FR\"\n" -" --format Sample format %s (req. for rec) " -"(default %s)\n" +" one of: \"stereo\", \"surround-51\",... or\n" +" comma separated list of channel names: eg. \"FL,FR\"\n" +" --format Sample format %s (req. for rec) (default %s)\n" " --volume Stream volume 0-1.0 (default %.3f)\n" -" -q --quality Resampler quality (0 - 15) (default " -"%d)\n" +" -q --quality Resampler quality (0 - 15) (default %d)\n" "\n" msgstr "" +"--rate Freqüència de mostreig (req. per rec) (predeterminat %u)\n" +" --channels Nombre de canals (req. per rec) (predeterminat %u)\n" +" --channel-map Mapa de canals\n" +" un dels següents: \"estèreo\", \"surround-51\",... o\n" +" Llista separada per comes dels noms dels canals: per exemple. \"FL,FR\"\n" +" --format Format de mostra %s (req. per a rec) (predeterminat %s)\n" +" --volume Volum de flux 0-1.0 (predeterminat %.3f)\n" +" -q --qualitat Remostrador de qualitat (0 - 15) (per defecte %d)" #: src/tools/pw-cat.c:1033 +#, fuzzy msgid "" " -p, --playback Playback mode\n" " -r, --record Recording mode\n" " -m, --midi Midi mode\n" "\n" msgstr "" +"-p, --playback Mode de reproducció\n" +" -r, --record mode d'enregistrament\n" +" -m, --midi Mode MIDI" #: src/tools/pw-cli.c:2932 -#, c-format +#, c-format, fuzzy msgid "" "%s options command\n" " -h, --help Show this help\n" @@ -134,10 +158,15 @@ " -r, --remote Remote daemon name\n" "\n" msgstr "" +"%s opcions ordre\n" +" -h, --help Mostra aquesta ajuda\n" +" --version Mostra la versió\n" +" -d, --daemon Inicia com a dimoni (fals predeterminat)\n" +" -r, --remote Nom del dimoni remot" #: spa/plugins/alsa/acp/acp.c:290 msgid "Pro Audio" -msgstr "" +msgstr "Pro Audio" #: spa/plugins/alsa/acp/acp.c:411 spa/plugins/alsa/acp/alsa-mixer.c:4704 #: spa/plugins/bluez5/bluez5-device.c:1000 @@ -252,25 +281,23 @@ #: spa/plugins/alsa/acp/alsa-mixer.c:2801 msgid "Dock Microphone" -msgstr "" +msgstr "Micròfon de l'acoblador" #: spa/plugins/alsa/acp/alsa-mixer.c:2803 msgid "Headset Microphone" -msgstr "" +msgstr "Micròfon d'auriculars" #: spa/plugins/alsa/acp/alsa-mixer.c:2807 msgid "Analog Output" msgstr "Sortida analògica" #: spa/plugins/alsa/acp/alsa-mixer.c:2809 -#, fuzzy msgid "Headphones 2" -msgstr "Auriculars" +msgstr "Auriculars 2" #: spa/plugins/alsa/acp/alsa-mixer.c:2810 -#, fuzzy msgid "Headphones Mono Output" -msgstr "Sortida mono analògica" +msgstr "Sortida mono dels auriculars" #: spa/plugins/alsa/acp/alsa-mixer.c:2811 msgid "Line Out" @@ -297,49 +324,41 @@ msgstr "Entrada digital (S/PDIF)" #: spa/plugins/alsa/acp/alsa-mixer.c:2817 -#, fuzzy msgid "Multichannel Input" -msgstr "Multicanal" +msgstr "Entrada multicanal" #: spa/plugins/alsa/acp/alsa-mixer.c:2818 -#, fuzzy msgid "Multichannel Output" -msgstr "Multicanal" +msgstr "Sortida multicanal" #: spa/plugins/alsa/acp/alsa-mixer.c:2819 -#, fuzzy msgid "Game Output" -msgstr "Sortida %s" +msgstr "Sortida del joc" #: spa/plugins/alsa/acp/alsa-mixer.c:2820 #: spa/plugins/alsa/acp/alsa-mixer.c:2821 -#, fuzzy msgid "Chat Output" -msgstr "Sortida %s" +msgstr "Sortida del xat" #: spa/plugins/alsa/acp/alsa-mixer.c:2822 -#, fuzzy msgid "Chat Input" -msgstr "Entrada %s" +msgstr "Entrada del xat" #: spa/plugins/alsa/acp/alsa-mixer.c:2823 -#, fuzzy msgid "Virtual Surround 7.1" -msgstr "Envoltant analògic 7.1" +msgstr "Envoltant virtual 7.1" #: spa/plugins/alsa/acp/alsa-mixer.c:4527 msgid "Analog Mono" msgstr "Mono analògic" #: spa/plugins/alsa/acp/alsa-mixer.c:4528 -#, fuzzy msgid "Analog Mono (Left)" -msgstr "Mono analògic" +msgstr "Mono analògic (esquerra)" #: spa/plugins/alsa/acp/alsa-mixer.c:4529 -#, fuzzy msgid "Analog Mono (Right)" -msgstr "Mono analògic" +msgstr "Mono analògic (dreta)" #. Note: Not translated to "Analog Stereo Input", because the source #. * name gets "Input" appended to it automatically, so adding "Input" @@ -364,13 +383,12 @@ #: spa/plugins/alsa/acp/alsa-mixer.c:4698 #: spa/plugins/bluez5/bluez5-device.c:1135 msgid "Headset" -msgstr "Auricular" +msgstr "Auriculars" #: spa/plugins/alsa/acp/alsa-mixer.c:4541 #: spa/plugins/alsa/acp/alsa-mixer.c:4699 -#, fuzzy msgid "Speakerphone" -msgstr "Altaveu" +msgstr "Altaveu del telèfon" #: spa/plugins/alsa/acp/alsa-mixer.c:4542 #: spa/plugins/alsa/acp/alsa-mixer.c:4543 @@ -379,23 +397,23 @@ #: spa/plugins/alsa/acp/alsa-mixer.c:4544 msgid "Analog Surround 2.1" -msgstr "So envoltant analògic 2.1" +msgstr "Envoltant analògic 2.1" #: spa/plugins/alsa/acp/alsa-mixer.c:4545 msgid "Analog Surround 3.0" -msgstr "So envoltant analògic 3.0" +msgstr "Envoltant analògic 3.0" #: spa/plugins/alsa/acp/alsa-mixer.c:4546 msgid "Analog Surround 3.1" -msgstr "So envoltant analògic 4.1" +msgstr "Envoltant analògic 3.1" #: spa/plugins/alsa/acp/alsa-mixer.c:4547 msgid "Analog Surround 4.0" -msgstr "Envoltant analògic 4.0 " +msgstr "Envoltant analògic 4.0" #: spa/plugins/alsa/acp/alsa-mixer.c:4548 msgid "Analog Surround 4.1" -msgstr "Envoltant analògic 4.1 " +msgstr "Envoltant analògic 4.1" #: spa/plugins/alsa/acp/alsa-mixer.c:4549 msgid "Analog Surround 5.0" @@ -407,15 +425,15 @@ #: spa/plugins/alsa/acp/alsa-mixer.c:4551 msgid "Analog Surround 6.0" -msgstr "So envoltant analògic 6.0" +msgstr "Envoltant analògic 6.0" #: spa/plugins/alsa/acp/alsa-mixer.c:4552 msgid "Analog Surround 6.1" -msgstr "So envoltant analògic 6.1" +msgstr "Envoltant analògic 6.1" #: spa/plugins/alsa/acp/alsa-mixer.c:4553 msgid "Analog Surround 7.0" -msgstr "So envoltant analògic 7.0" +msgstr "Envoltant analògic 7.0" #: spa/plugins/alsa/acp/alsa-mixer.c:4554 msgid "Analog Surround 7.1" @@ -431,11 +449,11 @@ #: spa/plugins/alsa/acp/alsa-mixer.c:4557 msgid "Digital Surround 5.1 (IEC958/AC3)" -msgstr "Envolvent digital 5.1 (IEC958/AC3)" +msgstr "Envoltant digital 5.1 (IEC958/AC3)" #: spa/plugins/alsa/acp/alsa-mixer.c:4558 msgid "Digital Surround 5.1 (IEC958/DTS)" -msgstr "So envoltant digital 5.1 (IEC958/DTS)" +msgstr "Envoltant digital 5.1 (IEC958/DTS)" #: spa/plugins/alsa/acp/alsa-mixer.c:4559 msgid "Digital Stereo (HDMI)" @@ -443,15 +461,15 @@ #: spa/plugins/alsa/acp/alsa-mixer.c:4560 msgid "Digital Surround 5.1 (HDMI)" -msgstr "So envoltant digital 5.1 (HDMI)" +msgstr "Envoltant digital 5.1 (HDMI)" #: spa/plugins/alsa/acp/alsa-mixer.c:4561 msgid "Chat" -msgstr "" +msgstr "Xat" #: spa/plugins/alsa/acp/alsa-mixer.c:4562 msgid "Game" -msgstr "" +msgstr "Joc" #: spa/plugins/alsa/acp/alsa-mixer.c:4696 msgid "Analog Mono Duplex" @@ -466,18 +484,16 @@ msgstr "Dúplex estèreo digital (IEC958)" #: spa/plugins/alsa/acp/alsa-mixer.c:4701 -#, fuzzy msgid "Multichannel Duplex" -msgstr "Multicanal" +msgstr "Dúplex Multicanal" #: spa/plugins/alsa/acp/alsa-mixer.c:4702 -#, fuzzy msgid "Stereo Duplex" -msgstr "Dúplex estèreo analògic" +msgstr "Dúplex estèreo" #: spa/plugins/alsa/acp/alsa-mixer.c:4703 msgid "Mono Chat + 7.1 Surround" -msgstr "" +msgstr "Xat mono + 7.1 envoltant" #: spa/plugins/alsa/acp/alsa-mixer.c:4806 #, c-format @@ -492,115 +508,87 @@ #: spa/plugins/alsa/acp/alsa-util.c:1175 spa/plugins/alsa/acp/alsa-util.c:1269 #, fuzzy, c-format msgid "" -"snd_pcm_avail() returned a value that is exceptionally large: %lu byte (%lu " -"ms).\n" -"Most likely this is a bug in the ALSA driver '%s'. Please report this issue " -"to the ALSA developers." +"snd_pcm_avail() returned a value that is exceptionally large: %lu byte (%lu ms).\n" +"Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers." msgid_plural "" -"snd_pcm_avail() returned a value that is exceptionally large: %lu bytes (%lu " -"ms).\n" -"Most likely this is a bug in the ALSA driver '%s'. Please report this issue " -"to the ALSA developers." +"snd_pcm_avail() returned a value that is exceptionally large: %lu bytes (%lu ms).\n" +"Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers." msgstr0 "" -"snd_pcm_avail() ha retornat un valor excepcionalment gran: %lu bytes (%lu " -"ms).\n" -"Probablement es tracta d'un error del controlador de l'ALSA '%s'. Informeu " -"d'aquest incident als desenvolupadors de l'ALSA." +"snd_pcm_avail() ha retornat un valor excepcionalment gran: %lu bytes (%lu ms).\n" +"Probablement es tracta d'un error del controlador de l'ALSA '%s'. Informeu d'aquest incident als desenvolupadors de l'ALSA." msgstr1 "" -"snd_pcm_avail() ha retornat un valor excepcionalment gran: %lu bytes (%lu " -"ms).\n" -"Probablement es tracta d'un error del controlador de l'ALSA '%s'. Informeu " -"d'aquest incident als desenvolupadors de l'ALSA." +"snd_pcm_avail() ha retornat un valor excepcionalment gran: %lu bytes (%lu ms).\n" +"Probablement es tracta d'un error del controlador de l'ALSA '%s'. Informeu d'aquest incident als desenvolupadors de l'ALSA." #: spa/plugins/alsa/acp/alsa-util.c:1241 #, fuzzy, c-format msgid "" -"snd_pcm_delay() returned a value that is exceptionally large: %li byte (%s" -"%lu ms).\n" -"Most likely this is a bug in the ALSA driver '%s'. Please report this issue " -"to the ALSA developers." +"snd_pcm_delay() returned a value that is exceptionally large: %li byte (%s%lu ms).\n" +"Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers." msgid_plural "" -"snd_pcm_delay() returned a value that is exceptionally large: %li bytes (%s" -"%lu ms).\n" -"Most likely this is a bug in the ALSA driver '%s'. Please report this issue " -"to the ALSA developers." +"snd_pcm_delay() returned a value that is exceptionally large: %li bytes (%s%lu ms).\n" +"Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers." msgstr0 "" -"snd_pcm_delay() ha retornat un valor excepcionalment gran: %li bytes (%s%lu " -"ms).\n" -"Probablement es tracta d'un error del controlador de l'ALSA '%s'. Informeu " -"d'aquest incident als desenvolupadors de l'ALSA." +"snd_pcm_delay() ha retornat un valor excepcionalment gran: %li bytes (%s%lu ms).\n" +"Probablement es tracta d'un error del controlador de l'ALSA '%s'. Informeu d'aquest incident als desenvolupadors de l'ALSA." msgstr1 "" -"snd_pcm_delay() ha retornat un valor excepcionalment gran: %li bytes (%s%lu " -"ms).\n" -"Probablement es tracta d'un error del controlador de l'ALSA '%s'. Informeu " -"d'aquest incident als desenvolupadors de l'ALSA." +"snd_pcm_delay() ha retornat un valor excepcionalment gran: %li bytes (%s%lu ms).\n" +"Probablement es tracta d'un error del controlador de l'ALSA '%s'. Informeu d'aquest incident als desenvolupadors de l'ALSA." #: spa/plugins/alsa/acp/alsa-util.c:1288 #, c-format msgid "" -"snd_pcm_avail_delay() returned strange values: delay %lu is less than avail " -"%lu.\n" -"Most likely this is a bug in the ALSA driver '%s'. Please report this issue " -"to the ALSA developers." +"snd_pcm_avail_delay() returned strange values: delay %lu is less than avail %lu.\n" +"Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers." msgstr "" -"snd_pcm_avail() ha retornat un valor excepcionalment gran: %lu bytes (%lu " -"ms).\n" -"Probablement es tracta d'un error del controlador d'ALSA «%s». Informeu " -"d'aquest problema als desenvolupadors d'ALSA." +"snd_pcm_avail() ha retornat un valor excepcionalment gran: %lu bytes (%lu ms).\n" +"Probablement es tracta d'un error del controlador d'ALSA «%s». Informeu d'aquest problema als desenvolupadors d'ALSA." #: spa/plugins/alsa/acp/alsa-util.c:1331 #, fuzzy, c-format msgid "" -"snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu byte " -"(%lu ms).\n" -"Most likely this is a bug in the ALSA driver '%s'. Please report this issue " -"to the ALSA developers." +"snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu byte (%lu ms).\n" +"Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers." msgid_plural "" -"snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu bytes " -"(%lu ms).\n" -"Most likely this is a bug in the ALSA driver '%s'. Please report this issue " -"to the ALSA developers." +"snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu bytes (%lu ms).\n" +"Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers." msgstr0 "" -"snd_pcm_mmap_begin() ha retornat un valor excepcionalment gran: %lu bytes " -"(%lu ms).\n" -"Probablement es tracta d'un error del controlador de l'ALSA '%s'. Informeu " -"d'aquest incident als desenvolupadors de l'ALSA." +"snd_pcm_mmap_begin() ha retornat un valor excepcionalment gran: %lu bytes (%lu ms).\n" +"Probablement es tracta d'un error del controlador de l'ALSA '%s'. Informeu d'aquest incident als desenvolupadors de l'ALSA." msgstr1 "" -"snd_pcm_mmap_begin() ha retornat un valor excepcionalment gran: %lu bytes " -"(%lu ms).\n" -"Probablement es tracta d'un error del controlador de l'ALSA '%s'. Informeu " -"d'aquest incident als desenvolupadors de l'ALSA." +"snd_pcm_mmap_begin() ha retornat un valor excepcionalment gran: %lu bytes (%lu ms).\n" +"Probablement es tracta d'un error del controlador de l'ALSA '%s'. Informeu d'aquest incident als desenvolupadors de l'ALSA." #: spa/plugins/bluez5/bluez5-device.c:1010 msgid "Audio Gateway (A2DP Source & HSP/HFP AG)" -msgstr "" +msgstr "Passarel·la d'àudio (A2DP Source & HSP/HFP AG)" #: spa/plugins/bluez5/bluez5-device.c:1033 #, c-format msgid "High Fidelity Playback (A2DP Sink, codec %s)" -msgstr "" +msgstr "Reproducció d'alta fidelitat (Sink A2DP, còdec %s)" #: spa/plugins/bluez5/bluez5-device.c:1035 #, c-format msgid "High Fidelity Duplex (A2DP Source/Sink, codec %s)" -msgstr "" +msgstr "Dúplex d'alta fidelitat (A2DP Source/Sink, còdec %s)" #: spa/plugins/bluez5/bluez5-device.c:1041 msgid "High Fidelity Playback (A2DP Sink)" -msgstr "" +msgstr "Reproducció d'alta fidelitat (A2DP Sink)" #: spa/plugins/bluez5/bluez5-device.c:1043 msgid "High Fidelity Duplex (A2DP Source/Sink)" -msgstr "" +msgstr "Dúplex d'alta fidelitat (A2DP Source/Sink)" #: spa/plugins/bluez5/bluez5-device.c:1070 #, c-format msgid "Headset Head Unit (HSP/HFP, codec %s)" -msgstr "" +msgstr "Unitat d'ariculars pel cap (HSP/HFP, còdec %s)" #: spa/plugins/bluez5/bluez5-device.c:1074 msgid "Headset Head Unit (HSP/HFP)" -msgstr "" +msgstr "Unitat d'ariculars pel cap (HSP/HFP)" #: spa/plugins/bluez5/bluez5-device.c:1140 msgid "Handsfree" @@ -612,7 +600,7 @@ #: spa/plugins/bluez5/bluez5-device.c:1160 msgid "Portable" -msgstr "" +msgstr "Portable" #: spa/plugins/bluez5/bluez5-device.c:1165 msgid "Car" @@ -620,13 +608,12 @@ #: spa/plugins/bluez5/bluez5-device.c:1170 msgid "HiFi" -msgstr "" +msgstr "HiFi" #: spa/plugins/bluez5/bluez5-device.c:1175 msgid "Phone" msgstr "Telèfon" #: spa/plugins/bluez5/bluez5-device.c:1181 -#, fuzzy msgid "Bluetooth" -msgstr "Entrada bluetooth" +msgstr "Bluetooth"
View file
pipewire-0.3.56.tar.gz/po/gl.po -> pipewire-0.3.57.tar.gz/po/gl.po
Changed
@@ -4,25 +4,31 @@ # Translators: # bassball93 <bassball93@gmail.com>, 2011. # mbouzada <mbouzada@gmail.com>, 2011. -# Fran Dieguez <frandieguez@gnome.org>, 2012, 2019. # Marcos Lans <marcoslansgarza@gmail.com>, 2018. +# Fran Dieguez <frandieguez@gnome.org>, 2012-2022. +# msgid "" msgstr "" "Project-Id-Version: PipeWire\n" -"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/" -"issues/new\n" -"POT-Creation-Date: 2021-04-18 16:54+0800\n" -"PO-Revision-Date: 2019-02-20 01:36+0200\n" +"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/-/" +"issues\n" +"POT-Creation-Date: 2022-07-10 03:27+0000\n" +"PO-Revision-Date: 2022-08-23 09:47+0200\n" "Last-Translator: Fran Dieguez <frandieguez@gnome.org>\n" -"Language-Team: Galician\n" +"Language-Team: Galician <Proxecto Trasno <proxecto@trasno.gal>>\n" "Language: gl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Virtaal 0.7.1\n" - -#: src/daemon/pipewire.c:43 +"Plural-Forms: nplurals=2; plural=(n != 1)\n" +"X-Generator: Gtranslator 40.0\n" +"X-DL-Team: gl\n" +"X-DL-Module: PipeWire\n" +"X-DL-Branch: master\n" +"X-DL-Domain: po\n" +"X-DL-State: Translating\n" + +#: src/daemon/pipewire.c:46 #, c-format msgid "" "%s options\n" @@ -30,6 +36,11 @@ " --version Show version\n" " -c, --config Load config (Default %s)\n" msgstr "" +"%s opcións\n" +" -h, --help Mostra esta axuda\n" +" --version Mostrar versión\n" +" -c, --config Cargar configuración (Predeterminado " +"%s)\n" #: src/daemon/pipewire.desktop.in:4 msgid "PipeWire Media System" @@ -39,31 +50,52 @@ msgid "Start the PipeWire Media System" msgstr "Iniciar o Sistema multimedia PipeWire" -#: src/examples/media-session/alsa-monitor.c:526 -#: spa/plugins/alsa/acp/compat.c:187 -msgid "Built-in Audio" -msgstr "Audio interno" +#: src/modules/module-protocol-pulse/modules/module-tunnel-sink.c:180 +#: src/modules/module-protocol-pulse/modules/module-tunnel-source.c:180 +#, c-format +msgid "Tunnel to %s/%s" +msgstr "Túnel a %s/%s" -#: src/examples/media-session/alsa-monitor.c:530 -#: spa/plugins/alsa/acp/compat.c:192 -msgid "Modem" -msgstr "Módem" +#: src/modules/module-fallback-sink.c:51 +#| msgid "Game Output" +msgid "Dummy Output" +msgstr "Saída de proba" -#: src/examples/media-session/alsa-monitor.c:539 +#: src/modules/module-pulse-tunnel.c:648 +#, c-format +msgid "Tunnel for %s@%s" +msgstr "Túnel para %s@%s" + +#: src/modules/module-zeroconf-discover.c:332 msgid "Unknown device" -msgstr "" +msgstr "Dispositivo descoñecido" + +#: src/modules/module-zeroconf-discover.c:344 +#, c-format +msgid "%s on %s@%s" +msgstr "%s en %s@%s" + +#: src/modules/module-zeroconf-discover.c:348 +#, c-format +msgid "%s on %s" +msgstr "%s en %s" -#: src/tools/pw-cat.c:991 +#: src/tools/pw-cat.c:784 #, c-format msgid "" -"%s options <file>\n" +"%s options <file>|-\n" " -h, --help Show this help\n" " --version Show version\n" " -v, --verbose Enable verbose operations\n" "\n" msgstr "" +"%s opcións <ficheiro>|-\n" +" -h, --help Mostrar esta axuda\n" +" --version Mostrar versión\n" +" -v, --verbose Activar operacións verbosas\n" +"\n" -#: src/tools/pw-cat.c:998 +#: src/tools/pw-cat.c:791 #, c-format msgid "" " -R, --remote Remote daemon name\n" @@ -77,11 +109,29 @@ " or direct samples (256)\n" " the rate is the one of the source " "file\n" -" --list-targets List available targets for --target\n" +" -P --properties Set node properties\n" "\n" msgstr "" +" -R, --remote Nome do daemon remoto\n" +" --media-type Estabelecer o tipo de medio (por " +"omisión %s)\n" +" --media-category Estabelecer a categoría multimedia " +"(por omisión %s)\n" +" --media-role Estabelecer o rol multimedia (por " +"omisión %s)\n" +" --target Estabelecer o nodo obxectivo (por " +"omisión %s)\n" +" 0 significa non ligar\n" +" --latency Estabelecer a latencia do nodo (por " +"omisión %s)\n" +" Xunit (unidade = s, ms, us, ns)\n" +" ou mostras directas samples (256)\n" +" a taxa é un dos ficheiros de " +"orixe\n" +" -P --properties Estabelecer as propiedades do nodo\n" +"\n" -#: src/tools/pw-cat.c:1016 +#: src/tools/pw-cat.c:809 #, c-format msgid "" " --rate Sample rate (req. for rec) (default " @@ -100,16 +150,38 @@ "%d)\n" "\n" msgstr "" +" --rate Taxa de mostreo (solicitudes por " +"segundo) (por omisión %u)\n" +" --channels Número de canles (solicitudes por " +"segundo) (por omisión %u)\n" +" --channel-map Mapa de canles\n" +" un de: \"stereo\", " +"\"surround-51\",... or\n" +" lista separada por comas dos " +"nomes das canles: p.ex. \"FL,FR\"\n" +" --format Formato de mostras %s (solicitudes " +"por segundo) (por omisión %s)\n" +" --volume Volume do fluxo 0-1.0 (por omisión " +"%.3f)\n" +" -q --quality Calidade do remostreador (0 - 15) " +"(por omisión %d)\n" +"\n" -#: src/tools/pw-cat.c:1033 +#: src/tools/pw-cat.c:826 msgid "" " -p, --playback Playback mode\n" " -r, --record Recording mode\n" " -m, --midi Midi mode\n" +" -d, --dsd DSD mode\n" "\n" msgstr "" +" -p, --playback Modo de reprodución\n" +" -r, --record Modo de grabación\n" +" -m, --midi Modo MIDI\n" +" -d, --dsd Modo DSD\n" +"\n" -#: src/tools/pw-cli.c:2932 +#: src/tools/pw-cli.c:3165 #, c-format msgid "" "%s options command\n" @@ -119,355 +191,352 @@ " -r, --remote Remote daemon name\n" "\n" msgstr "" +"%s opcións orde\n" +" -h, --help Mostrar esta axuda\n" +" --version Mostrar versión\n" +" -d, --daemon Iniciar como demonio (Por omisión " +"falso)\n" +" -r, --remote Modo de demonio remoto\n" +"\n" -#: spa/plugins/alsa/acp/acp.c:290 +#: spa/plugins/alsa/acp/acp.c:321 msgid "Pro Audio" -msgstr "" +msgstr "Pro Audio" -#: spa/plugins/alsa/acp/acp.c:411 spa/plugins/alsa/acp/alsa-mixer.c:4704 -#: spa/plugins/bluez5/bluez5-device.c:1000 +#: spa/plugins/alsa/acp/acp.c:446 spa/plugins/alsa/acp/alsa-mixer.c:4648 +#: spa/plugins/bluez5/bluez5-device.c:1185 msgid "Off" msgstr "Apagado" -#: spa/plugins/alsa/acp/channelmap.h:466 -msgid "(invalid)" -msgstr "(incorrecto)" - -#: spa/plugins/alsa/acp/alsa-mixer.c:2709 +#: spa/plugins/alsa/acp/alsa-mixer.c:2652 msgid "Input" msgstr "Entrada" -#: spa/plugins/alsa/acp/alsa-mixer.c:2710 +#: spa/plugins/alsa/acp/alsa-mixer.c:2653 msgid "Docking Station Input" msgstr "Entrada de estación acoplada (Docking Station)" -#: spa/plugins/alsa/acp/alsa-mixer.c:2711 +#: spa/plugins/alsa/acp/alsa-mixer.c:2654 msgid "Docking Station Microphone" msgstr "Micrófono da estación acoplada (Docking Station)" -#: spa/plugins/alsa/acp/alsa-mixer.c:2712 +#: spa/plugins/alsa/acp/alsa-mixer.c:2655 msgid "Docking Station Line In" msgstr "Entrada de estación acoplada (Docking Station)" -#: spa/plugins/alsa/acp/alsa-mixer.c:2713 -#: spa/plugins/alsa/acp/alsa-mixer.c:2804 +#: spa/plugins/alsa/acp/alsa-mixer.c:2656 +#: spa/plugins/alsa/acp/alsa-mixer.c:2747 msgid "Line In" msgstr "Liña de entrada" -#: spa/plugins/alsa/acp/alsa-mixer.c:2714 -#: spa/plugins/alsa/acp/alsa-mixer.c:2798 -#: spa/plugins/bluez5/bluez5-device.c:1145 +#: spa/plugins/alsa/acp/alsa-mixer.c:2657 +#: spa/plugins/alsa/acp/alsa-mixer.c:2741 +#: spa/plugins/bluez5/bluez5-device.c:1357 msgid "Microphone" msgstr "Micrófono" -#: spa/plugins/alsa/acp/alsa-mixer.c:2715 -#: spa/plugins/alsa/acp/alsa-mixer.c:2799 +#: spa/plugins/alsa/acp/alsa-mixer.c:2658 +#: spa/plugins/alsa/acp/alsa-mixer.c:2742 msgid "Front Microphone" msgstr "Micrófono frontal" -#: spa/plugins/alsa/acp/alsa-mixer.c:2716 -#: spa/plugins/alsa/acp/alsa-mixer.c:2800 +#: spa/plugins/alsa/acp/alsa-mixer.c:2659 +#: spa/plugins/alsa/acp/alsa-mixer.c:2743 msgid "Rear Microphone" msgstr "Micrófono traseiro" -#: spa/plugins/alsa/acp/alsa-mixer.c:2717 +#: spa/plugins/alsa/acp/alsa-mixer.c:2660 msgid "External Microphone" msgstr "Micrófono externo" -#: spa/plugins/alsa/acp/alsa-mixer.c:2718 -#: spa/plugins/alsa/acp/alsa-mixer.c:2802 +#: spa/plugins/alsa/acp/alsa-mixer.c:2661 +#: spa/plugins/alsa/acp/alsa-mixer.c:2745 msgid "Internal Microphone" msgstr "Micrófono interno" -#: spa/plugins/alsa/acp/alsa-mixer.c:2719 -#: spa/plugins/alsa/acp/alsa-mixer.c:2805 +#: spa/plugins/alsa/acp/alsa-mixer.c:2662 +#: spa/plugins/alsa/acp/alsa-mixer.c:2748 msgid "Radio" msgstr "Radio" -#: spa/plugins/alsa/acp/alsa-mixer.c:2720 -#: spa/plugins/alsa/acp/alsa-mixer.c:2806 +#: spa/plugins/alsa/acp/alsa-mixer.c:2663 +#: spa/plugins/alsa/acp/alsa-mixer.c:2749 msgid "Video" msgstr "Vídeo" -#: spa/plugins/alsa/acp/alsa-mixer.c:2721 +#: spa/plugins/alsa/acp/alsa-mixer.c:2664 msgid "Automatic Gain Control" msgstr "Control automático de ganancia" -#: spa/plugins/alsa/acp/alsa-mixer.c:2722 +#: spa/plugins/alsa/acp/alsa-mixer.c:2665 msgid "No Automatic Gain Control" msgstr "Sen control automático de ganancia" -#: spa/plugins/alsa/acp/alsa-mixer.c:2723 +#: spa/plugins/alsa/acp/alsa-mixer.c:2666 msgid "Boost" msgstr "Enfatizador" -#: spa/plugins/alsa/acp/alsa-mixer.c:2724 +#: spa/plugins/alsa/acp/alsa-mixer.c:2667 msgid "No Boost" msgstr "Sen enfatizador" -#: spa/plugins/alsa/acp/alsa-mixer.c:2725 +#: spa/plugins/alsa/acp/alsa-mixer.c:2668 msgid "Amplifier" msgstr "Amplificador" -#: spa/plugins/alsa/acp/alsa-mixer.c:2726 +#: spa/plugins/alsa/acp/alsa-mixer.c:2669 msgid "No Amplifier" msgstr "Sen amplificador" -#: spa/plugins/alsa/acp/alsa-mixer.c:2727 +#: spa/plugins/alsa/acp/alsa-mixer.c:2670 msgid "Bass Boost" msgstr "Enfatizador baixo" -#: spa/plugins/alsa/acp/alsa-mixer.c:2728 +#: spa/plugins/alsa/acp/alsa-mixer.c:2671 msgid "No Bass Boost" msgstr "Sen enfatizador baixo" -#: spa/plugins/alsa/acp/alsa-mixer.c:2729 -#: spa/plugins/bluez5/bluez5-device.c:1150 +#: spa/plugins/alsa/acp/alsa-mixer.c:2672 +#: spa/plugins/bluez5/bluez5-device.c:1363 msgid "Speaker" msgstr "Altofalante" -#: spa/plugins/alsa/acp/alsa-mixer.c:2730 -#: spa/plugins/alsa/acp/alsa-mixer.c:2808 +#: spa/plugins/alsa/acp/alsa-mixer.c:2673 +#: spa/plugins/alsa/acp/alsa-mixer.c:2751 msgid "Headphones" msgstr "Auriculares" -#: spa/plugins/alsa/acp/alsa-mixer.c:2797 +#: spa/plugins/alsa/acp/alsa-mixer.c:2740 msgid "Analog Input" msgstr "Entrada analóxica" -#: spa/plugins/alsa/acp/alsa-mixer.c:2801 +#: spa/plugins/alsa/acp/alsa-mixer.c:2744 msgid "Dock Microphone" msgstr "Micrófono do acople" -#: spa/plugins/alsa/acp/alsa-mixer.c:2803 +#: spa/plugins/alsa/acp/alsa-mixer.c:2746 msgid "Headset Microphone" msgstr "Micrófono con auricular" -#: spa/plugins/alsa/acp/alsa-mixer.c:2807 +#: spa/plugins/alsa/acp/alsa-mixer.c:2750 msgid "Analog Output" msgstr "Saída analóxica" -#: spa/plugins/alsa/acp/alsa-mixer.c:2809 -#, fuzzy +#: spa/plugins/alsa/acp/alsa-mixer.c:2752 msgid "Headphones 2" -msgstr "Auriculares" +msgstr "Auriculares 2" -#: spa/plugins/alsa/acp/alsa-mixer.c:2810 +#: spa/plugins/alsa/acp/alsa-mixer.c:2753 msgid "Headphones Mono Output" msgstr "Saída monoaural para auriculares" -#: spa/plugins/alsa/acp/alsa-mixer.c:2811 +#: spa/plugins/alsa/acp/alsa-mixer.c:2754 msgid "Line Out" msgstr "Liña de saída" -#: spa/plugins/alsa/acp/alsa-mixer.c:2812 +#: spa/plugins/alsa/acp/alsa-mixer.c:2755 msgid "Analog Mono Output" msgstr "Saída monoaural analóxica" -#: spa/plugins/alsa/acp/alsa-mixer.c:2813 +#: spa/plugins/alsa/acp/alsa-mixer.c:2756 msgid "Speakers" msgstr "Altofalantes" -#: spa/plugins/alsa/acp/alsa-mixer.c:2814 +#: spa/plugins/alsa/acp/alsa-mixer.c:2757 msgid "HDMI / DisplayPort" msgstr "HDMI / DisplayPort" -#: spa/plugins/alsa/acp/alsa-mixer.c:2815 +#: spa/plugins/alsa/acp/alsa-mixer.c:2758 msgid "Digital Output (S/PDIF)" msgstr "Saída dixital (S/PDIF)" -#: spa/plugins/alsa/acp/alsa-mixer.c:2816 +#: spa/plugins/alsa/acp/alsa-mixer.c:2759 msgid "Digital Input (S/PDIF)" msgstr "Entrada dixital (S/PDIF)" -#: spa/plugins/alsa/acp/alsa-mixer.c:2817 +#: spa/plugins/alsa/acp/alsa-mixer.c:2760 msgid "Multichannel Input" msgstr "Entrada multicanle" -#: spa/plugins/alsa/acp/alsa-mixer.c:2818 +#: spa/plugins/alsa/acp/alsa-mixer.c:2761 msgid "Multichannel Output" msgstr "Saída multicanle" -#: spa/plugins/alsa/acp/alsa-mixer.c:2819 +#: spa/plugins/alsa/acp/alsa-mixer.c:2762 msgid "Game Output" msgstr "Saída do xogo" -#: spa/plugins/alsa/acp/alsa-mixer.c:2820 -#: spa/plugins/alsa/acp/alsa-mixer.c:2821 +#: spa/plugins/alsa/acp/alsa-mixer.c:2763 +#: spa/plugins/alsa/acp/alsa-mixer.c:2764 msgid "Chat Output" msgstr "Saída do chat" -#: spa/plugins/alsa/acp/alsa-mixer.c:2822 -#, fuzzy +#: spa/plugins/alsa/acp/alsa-mixer.c:2765 msgid "Chat Input" -msgstr "Saída do chat" +msgstr "Entrada de chat" -#: spa/plugins/alsa/acp/alsa-mixer.c:2823 -#, fuzzy +#: spa/plugins/alsa/acp/alsa-mixer.c:2766 msgid "Virtual Surround 7.1" -msgstr "Sumideiro envolvente virtual" +msgstr "Envolvente virtual 7.1" -#: spa/plugins/alsa/acp/alsa-mixer.c:4527 +#: spa/plugins/alsa/acp/alsa-mixer.c:4471 msgid "Analog Mono" msgstr "Monoaural analóxico" -#: spa/plugins/alsa/acp/alsa-mixer.c:4528 -#, fuzzy +#: spa/plugins/alsa/acp/alsa-mixer.c:4472 msgid "Analog Mono (Left)" -msgstr "Monoaural analóxico" +msgstr "Monoaural analóxico (Esquerda)" -#: spa/plugins/alsa/acp/alsa-mixer.c:4529 -#, fuzzy +#: spa/plugins/alsa/acp/alsa-mixer.c:4473 msgid "Analog Mono (Right)" -msgstr "Monoaural analóxico" +msgstr "Monoaural analóxico (Dereita)" #. Note: Not translated to "Analog Stereo Input", because the source #. * name gets "Input" appended to it automatically, so adding "Input" #. * here would lead to the source name to become "Analog Stereo Input #. * Input". The same logic applies to analog-stereo-output, #. * multichannel-input and multichannel-output. -#: spa/plugins/alsa/acp/alsa-mixer.c:4530 -#: spa/plugins/alsa/acp/alsa-mixer.c:4538 -#: spa/plugins/alsa/acp/alsa-mixer.c:4539 +#: spa/plugins/alsa/acp/alsa-mixer.c:4474 +#: spa/plugins/alsa/acp/alsa-mixer.c:4482 +#: spa/plugins/alsa/acp/alsa-mixer.c:4483 msgid "Analog Stereo" msgstr "Estéreo analóxico" -#: spa/plugins/alsa/acp/alsa-mixer.c:4531 +#: spa/plugins/alsa/acp/alsa-mixer.c:4475 msgid "Mono" msgstr "Mono" -#: spa/plugins/alsa/acp/alsa-mixer.c:4532 +#: spa/plugins/alsa/acp/alsa-mixer.c:4476 msgid "Stereo" msgstr "Estéreo" -#: spa/plugins/alsa/acp/alsa-mixer.c:4540 -#: spa/plugins/alsa/acp/alsa-mixer.c:4698 -#: spa/plugins/bluez5/bluez5-device.c:1135 +#: spa/plugins/alsa/acp/alsa-mixer.c:4484 +#: spa/plugins/alsa/acp/alsa-mixer.c:4642 +#: spa/plugins/bluez5/bluez5-device.c:1345 msgid "Headset" msgstr "Auriculares con micro" -#: spa/plugins/alsa/acp/alsa-mixer.c:4541 -#: spa/plugins/alsa/acp/alsa-mixer.c:4699 -#, fuzzy +#: spa/plugins/alsa/acp/alsa-mixer.c:4485 +#: spa/plugins/alsa/acp/alsa-mixer.c:4643 msgid "Speakerphone" msgstr "Altofalante" -#: spa/plugins/alsa/acp/alsa-mixer.c:4542 -#: spa/plugins/alsa/acp/alsa-mixer.c:4543 +#: spa/plugins/alsa/acp/alsa-mixer.c:4486 +#: spa/plugins/alsa/acp/alsa-mixer.c:4487 msgid "Multichannel" msgstr "Multicanle" -#: spa/plugins/alsa/acp/alsa-mixer.c:4544 +#: spa/plugins/alsa/acp/alsa-mixer.c:4488 msgid "Analog Surround 2.1" msgstr "Envolvente analóxico 2.1" -#: spa/plugins/alsa/acp/alsa-mixer.c:4545 +#: spa/plugins/alsa/acp/alsa-mixer.c:4489 msgid "Analog Surround 3.0" msgstr "Envolvente analóxico 3.0" -#: spa/plugins/alsa/acp/alsa-mixer.c:4546 +#: spa/plugins/alsa/acp/alsa-mixer.c:4490 msgid "Analog Surround 3.1" msgstr "Envolvente analóxico 3.1" -#: spa/plugins/alsa/acp/alsa-mixer.c:4547 +#: spa/plugins/alsa/acp/alsa-mixer.c:4491 msgid "Analog Surround 4.0" msgstr "Envolvente analóxico 4.0" -#: spa/plugins/alsa/acp/alsa-mixer.c:4548 +#: spa/plugins/alsa/acp/alsa-mixer.c:4492 msgid "Analog Surround 4.1" msgstr "Envolvente analóxico 4.1" -#: spa/plugins/alsa/acp/alsa-mixer.c:4549 +#: spa/plugins/alsa/acp/alsa-mixer.c:4493 msgid "Analog Surround 5.0" msgstr "Envolvente analóxico 5.0" -#: spa/plugins/alsa/acp/alsa-mixer.c:4550 +#: spa/plugins/alsa/acp/alsa-mixer.c:4494 msgid "Analog Surround 5.1" msgstr "Envolvente analóxico 5.1" -#: spa/plugins/alsa/acp/alsa-mixer.c:4551 +#: spa/plugins/alsa/acp/alsa-mixer.c:4495 msgid "Analog Surround 6.0" msgstr "Envolvente analóxico 6.0" -#: spa/plugins/alsa/acp/alsa-mixer.c:4552 +#: spa/plugins/alsa/acp/alsa-mixer.c:4496 msgid "Analog Surround 6.1" msgstr "Envolvente analóxico 6.1" -#: spa/plugins/alsa/acp/alsa-mixer.c:4553 +#: spa/plugins/alsa/acp/alsa-mixer.c:4497 msgid "Analog Surround 7.0" msgstr "Envolvente analóxico 7.0" -#: spa/plugins/alsa/acp/alsa-mixer.c:4554 +#: spa/plugins/alsa/acp/alsa-mixer.c:4498 msgid "Analog Surround 7.1" msgstr "Envolvente analóxico 7.1" -#: spa/plugins/alsa/acp/alsa-mixer.c:4555 +#: spa/plugins/alsa/acp/alsa-mixer.c:4499 msgid "Digital Stereo (IEC958)" msgstr "Estéreo dixital (IEC958)" -#: spa/plugins/alsa/acp/alsa-mixer.c:4556 +#: spa/plugins/alsa/acp/alsa-mixer.c:4500 msgid "Digital Surround 4.0 (IEC958/AC3)" msgstr "Envolvente dixital 4.0 (IEC958/AC3)" -#: spa/plugins/alsa/acp/alsa-mixer.c:4557 +#: spa/plugins/alsa/acp/alsa-mixer.c:4501 msgid "Digital Surround 5.1 (IEC958/AC3)" msgstr "Envolvente dixital 5.1 (IEC958/AC3)" -#: spa/plugins/alsa/acp/alsa-mixer.c:4558 +#: spa/plugins/alsa/acp/alsa-mixer.c:4502 msgid "Digital Surround 5.1 (IEC958/DTS)" msgstr "Envolvente dixital 5.1 (IEC958/ACDTS)" -#: spa/plugins/alsa/acp/alsa-mixer.c:4559 +#: spa/plugins/alsa/acp/alsa-mixer.c:4503 msgid "Digital Stereo (HDMI)" msgstr "Estéreo dixital (HDMI)" -#: spa/plugins/alsa/acp/alsa-mixer.c:4560 +#: spa/plugins/alsa/acp/alsa-mixer.c:4504 msgid "Digital Surround 5.1 (HDMI)" msgstr "Envolvente dixital 5.1 (HDMI)" -#: spa/plugins/alsa/acp/alsa-mixer.c:4561 +#: spa/plugins/alsa/acp/alsa-mixer.c:4505 msgid "Chat" -msgstr "" +msgstr "Chat" -#: spa/plugins/alsa/acp/alsa-mixer.c:4562 +#: spa/plugins/alsa/acp/alsa-mixer.c:4506 msgid "Game" -msgstr "" +msgstr "Xogo" -#: spa/plugins/alsa/acp/alsa-mixer.c:4696 +#: spa/plugins/alsa/acp/alsa-mixer.c:4640 msgid "Analog Mono Duplex" msgstr "Monoaural analóxico dúplex" -#: spa/plugins/alsa/acp/alsa-mixer.c:4697 +#: spa/plugins/alsa/acp/alsa-mixer.c:4641 msgid "Analog Stereo Duplex" msgstr "Estéreo analóxico dúplex" -#: spa/plugins/alsa/acp/alsa-mixer.c:4700 +#: spa/plugins/alsa/acp/alsa-mixer.c:4644 msgid "Digital Stereo Duplex (IEC958)" msgstr "Estéreo dixital dúplex (IEC958)" -#: spa/plugins/alsa/acp/alsa-mixer.c:4701 +#: spa/plugins/alsa/acp/alsa-mixer.c:4645 msgid "Multichannel Duplex" msgstr "Dúplex multicanle" -#: spa/plugins/alsa/acp/alsa-mixer.c:4702 +#: spa/plugins/alsa/acp/alsa-mixer.c:4646 msgid "Stereo Duplex" msgstr "Dúplex estéreo" -#: spa/plugins/alsa/acp/alsa-mixer.c:4703 +#: spa/plugins/alsa/acp/alsa-mixer.c:4647 msgid "Mono Chat + 7.1 Surround" -msgstr "" +msgstr "Chat mono + envolvente 7.1" -#: spa/plugins/alsa/acp/alsa-mixer.c:4806 +#: spa/plugins/alsa/acp/alsa-mixer.c:4754 #, c-format msgid "%s Output" msgstr "Saída %s" -#: spa/plugins/alsa/acp/alsa-mixer.c:4813 +#: spa/plugins/alsa/acp/alsa-mixer.c:4761 #, c-format msgid "%s Input" msgstr "Entrada %s" -#: spa/plugins/alsa/acp/alsa-util.c:1175 spa/plugins/alsa/acp/alsa-util.c:1269 +#: spa/plugins/alsa/acp/alsa-util.c:1173 spa/plugins/alsa/acp/alsa-util.c:1267 #, c-format msgid "" "snd_pcm_avail() returned a value that is exceptionally large: %lu byte (%lu " @@ -490,16 +559,16 @@ "O máis probábel é que sexa un erro do controlador ALSA «%s». Informe disto " "aos desenvolvedores de ALSA." -#: spa/plugins/alsa/acp/alsa-util.c:1241 +#: spa/plugins/alsa/acp/alsa-util.c:1239 #, c-format msgid "" -"snd_pcm_delay() returned a value that is exceptionally large: %li byte (%s" -"%lu ms).\n" +"snd_pcm_delay() returned a value that is exceptionally large: %li byte " +"(%s%lu ms).\n" "Most likely this is a bug in the ALSA driver '%s'. Please report this issue " "to the ALSA developers." msgid_plural "" -"snd_pcm_delay() returned a value that is exceptionally large: %li bytes (%s" -"%lu ms).\n" +"snd_pcm_delay() returned a value that is exceptionally large: %li bytes " +"(%s%lu ms).\n" "Most likely this is a bug in the ALSA driver '%s'. Please report this issue " "to the ALSA developers." msgstr0 "" @@ -513,7 +582,7 @@ "O máis probábel é que sexa un erro do controlador ALSA «%s». Informe disto " "aos desenvolvedores de ALSA." -#: spa/plugins/alsa/acp/alsa-util.c:1288 +#: spa/plugins/alsa/acp/alsa-util.c:1286 #, c-format msgid "" "snd_pcm_avail_delay() returned strange values: delay %lu is less than avail " @@ -526,7 +595,7 @@ "O máis probábel é que sexa un erro do controlador ALSA «%s». Informe disto " "aos desenvolvedores de ALSA." -#: spa/plugins/alsa/acp/alsa-util.c:1331 +#: spa/plugins/alsa/acp/alsa-util.c:1329 #, c-format msgid "" "snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu byte " @@ -549,62 +618,90 @@ "O máis probábel é que sexa un erro do controlador ALSA «%s». Informe disto " "aos desenvolvedores de ALSA." -#: spa/plugins/bluez5/bluez5-device.c:1010 +#: spa/plugins/alsa/acp/channelmap.h:457 +msgid "(invalid)" +msgstr "(incorrecto)" + +#: spa/plugins/alsa/acp/compat.c:189 +msgid "Built-in Audio" +msgstr "Audio interno" + +#: spa/plugins/alsa/acp/compat.c:194 +msgid "Modem" +msgstr "Módem" + +#: spa/plugins/bluez5/bluez5-device.c:1196 msgid "Audio Gateway (A2DP Source & HSP/HFP AG)" -msgstr "" +msgstr "Porta de enlace de son (Orixe A2DP e HSP/HFP AG)" -#: spa/plugins/bluez5/bluez5-device.c:1033 +#: spa/plugins/bluez5/bluez5-device.c:1221 #, c-format msgid "High Fidelity Playback (A2DP Sink, codec %s)" -msgstr "" +msgstr "Reprodución de alta fidelidade (Sumideiro A2DP, códec %s)" -#: spa/plugins/bluez5/bluez5-device.c:1035 +#: spa/plugins/bluez5/bluez5-device.c:1224 #, c-format msgid "High Fidelity Duplex (A2DP Source/Sink, codec %s)" -msgstr "" +msgstr "Dúplex de alta fidelidade (Orixe/sumideiro A2DP, códec %s)" -#: spa/plugins/bluez5/bluez5-device.c:1041 +#: spa/plugins/bluez5/bluez5-device.c:1232 msgid "High Fidelity Playback (A2DP Sink)" -msgstr "" +msgstr "Reprodución de alta fidelidade (Sumideiro A2DP)" -#: spa/plugins/bluez5/bluez5-device.c:1043 +#: spa/plugins/bluez5/bluez5-device.c:1234 msgid "High Fidelity Duplex (A2DP Source/Sink)" -msgstr "" +msgstr "Dúplex de alta fidelidade (Orixe/sumideiro A2DP)" -#: spa/plugins/bluez5/bluez5-device.c:1070 +#: spa/plugins/bluez5/bluez5-device.c:1262 #, c-format msgid "Headset Head Unit (HSP/HFP, codec %s)" -msgstr "" +msgstr "Unidade de auriculares de cabeza (HSP/HFP, códec %s)" -#: spa/plugins/bluez5/bluez5-device.c:1074 +#: spa/plugins/bluez5/bluez5-device.c:1267 msgid "Headset Head Unit (HSP/HFP)" -msgstr "" - -#: spa/plugins/bluez5/bluez5-device.c:1140 +msgstr "Unidade de auriculares de cabeza (HSP/HFP)" + +#: spa/plugins/bluez5/bluez5-device.c:1346 +#: spa/plugins/bluez5/bluez5-device.c:1351 +#: spa/plugins/bluez5/bluez5-device.c:1358 +#: spa/plugins/bluez5/bluez5-device.c:1364 +#: spa/plugins/bluez5/bluez5-device.c:1370 +#: spa/plugins/bluez5/bluez5-device.c:1376 +#: spa/plugins/bluez5/bluez5-device.c:1382 +#: spa/plugins/bluez5/bluez5-device.c:1388 +#: spa/plugins/bluez5/bluez5-device.c:1394 msgid "Handsfree" msgstr "Sen mans" -#: spa/plugins/bluez5/bluez5-device.c:1155 +#: spa/plugins/bluez5/bluez5-device.c:1352 +#| msgid "Handsfree" +msgid "Handsfree (HFP)" +msgstr "Sen mans (HFP)" + +#: spa/plugins/bluez5/bluez5-device.c:1369 msgid "Headphone" msgstr "Auriculares" -#: spa/plugins/bluez5/bluez5-device.c:1160 +#: spa/plugins/bluez5/bluez5-device.c:1375 msgid "Portable" msgstr "Portátil" -#: spa/plugins/bluez5/bluez5-device.c:1165 +#: spa/plugins/bluez5/bluez5-device.c:1381 msgid "Car" msgstr "Automóbil" -#: spa/plugins/bluez5/bluez5-device.c:1170 +#: spa/plugins/bluez5/bluez5-device.c:1387 msgid "HiFi" -msgstr "Hifi" +msgstr "HiFi" -#: spa/plugins/bluez5/bluez5-device.c:1175 +#: spa/plugins/bluez5/bluez5-device.c:1393 msgid "Phone" msgstr "Teléfono" -#: spa/plugins/bluez5/bluez5-device.c:1181 -#, fuzzy +#: spa/plugins/bluez5/bluez5-device.c:1400 msgid "Bluetooth" -msgstr "Entrada de Bluetooth" +msgstr "Bluetooth" + +#: spa/plugins/bluez5/bluez5-device.c:1401 +msgid "Bluetooth (HFP)" +msgstr "Bluetooth (HFP)"
View file
pipewire-0.3.57.tar.gz/po/ka.po
Added
@@ -0,0 +1,661 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the pipewire package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: pipewire\n" +"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/" +"issues/new\n" +"POT-Creation-Date: 2022-06-30 12:50+0200\n" +"PO-Revision-Date: 2022-07-25 13:11+0200\n" +"Last-Translator: Temuri Doghonadze <temuri.doghonadze@gmail.com>\n" +"Language-Team: Georgian <(nothing)>\n" +"Language: ka\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 3.1.1\n" + +#: src/daemon/pipewire.c:46 +#, c-format +msgid "" +"%s options\n" +" -h, --help Show this help\n" +" --version Show version\n" +" -c, --config Load config (Default %s)\n" +msgstr "" +"%s პარამეტრები\n" +" -h, --help ამ დახმარების ჩვენება\n" +" --version ვერსიის ჩვენება\n" +" -c, --config ჩატვირთვის კონფიგურაცია (ნაგულისხმები %s)\n" + +#: src/modules/module-protocol-pulse/modules/module-tunnel-sink.c:180 +#: src/modules/module-protocol-pulse/modules/module-tunnel-source.c:180 +#, c-format +msgid "Tunnel to %s/%s" +msgstr "გვირაბი %s/%s -მდე" + +#: src/modules/module-fallback-sink.c:51 +msgid "Dummy Output" +msgstr "ნულოვანი გამოყვანა" + +#: src/modules/module-pulse-tunnel.c:648 +#, c-format +msgid "Tunnel for %s@%s" +msgstr "გვირაბი %s@%s-სთვის" + +#: src/modules/module-zeroconf-discover.c:332 +msgid "Unknown device" +msgstr "უცნობი მოწყობილობა" + +#: src/modules/module-zeroconf-discover.c:344 +#, c-format +msgid "%s on %s@%s" +msgstr "%s %s@%s -ზე" + +#: src/modules/module-zeroconf-discover.c:348 +#, c-format +msgid "%s on %s" +msgstr "%s %s-ზე" + +#: src/tools/pw-cat.c:784 +#, c-format +msgid "" +"%s options <file>|-\n" +" -h, --help Show this help\n" +" --version Show version\n" +" -v, --verbose Enable verbose operations\n" +"\n" +msgstr "" +"%s პარამეტრები <ფაილი>|-\n" +" -h, --help ამ დახმარების ჩვენება\n" +" --version ვერსიის ჩვენება\n" +" -v, --verbose დამატებითი შეტყობინებების გამოტანა\n" +"\n" + +#: src/tools/pw-cat.c:791 +#, c-format +msgid "" +" -R, --remote Remote daemon name\n" +" --media-type Set media type (default %s)\n" +" --media-category Set media category (default %s)\n" +" --media-role Set media role (default %s)\n" +" --target Set node target (default %s)\n" +" 0 means don't link\n" +" --latency Set node latency (default %s)\n" +" Xunit (unit = s, ms, us, ns)\n" +" or direct samples (256)\n" +" the rate is the one of the source " +"file\n" +" -P --properties Set node properties\n" +"\n" +msgstr "" +" -R, --remote დაშორებული დემონის სახელი\n" +" --media-type მედიის ტიპის დაყენება (ნაგულისხმები %s)\n" +" --media-category მედია კატეგორიის დაყენება (ნაგულისხმები %s)\n" +" --media-role მედიის როლის დაყენება (ნაგულისხმები %s)\n" +" --target კვანძის სამიზნის დაყენება (ნაგულისხმები %s)\n" +" 0 ნიშნავს არ მიბმა\n" +" --latency კვანძის შეყოვნების დაყენება (ნაგულისხმები %s)\n" +" Xunit (ერთეული = s, ms, us, ns)\n" +" ან პირდაპირი ნიმუშები (256)\n" +" მაჩვენებელი არის ერთ-ერთი წყაროს " +"ფაილი\n" +" -P --properties კვანძის თვისებების დაყენება\n" + +#: src/tools/pw-cat.c:809 +#, c-format +msgid "" +" --rate Sample rate (req. for rec) (default " +"%u)\n" +" --channels Number of channels (req. for rec) " +"(default %u)\n" +" --channel-map Channel map\n" +" one of: \"stereo\", " +"\"surround-51\",... or\n" +" comma separated list of channel " +"names: eg. \"FL,FR\"\n" +" --format Sample format %s (req. for rec) " +"(default %s)\n" +" --volume Stream volume 0-1.0 (default %.3f)\n" +" -q --quality Resampler quality (0 - 15) (default " +"%d)\n" +"\n" +msgstr "" +" --rate სემპლის_სიჩქარე (მოთხოვნილება rec.) (ნაგულისხმები %u)\n" +" --channels არხების რაოდენობა (მოთხოვნილი ჩანაწერისთვის) (ნაგულისხმები " +"%u)\n" +" --channel-map არხის რუკა\n" +" ერთ-ერთი: \"stereo\", " +"\"surround-51\",... ან\n" +" მძიმით გამოყოფილი არხის " +"სახელების სია: მაგ. \"FL, FR\"\n" +" --format ნიმუშის ფორმატი %s (მოთხოვნილება rec.) " +"(ნაგულისხმები %s)\n" +" --volume ნაკადის მოცულობა 0-1.0 (ნაგულისხმები %.3f)\n" +" -q --quality Resampler ხარისხი (0 - 15) " +"(ნაგულისხმები %d)\n" + +#: src/tools/pw-cat.c:826 +msgid "" +" -p, --playback Playback mode\n" +" -r, --record Recording mode\n" +" -m, --midi Midi mode\n" +" -d, --dsd DSD mode\n" +"\n" +msgstr "" +" -p, --playback დაკვრის რეჟიმი\n" +" -r, -- record ჩაწერის რეჟიმი\n" +" -m, --midi Midi რეჟიმი\n" +" -d, --dsd DSD რეჟიმი\n" +"\n" + +#: src/tools/pw-cli.c:3165 +#, c-format +msgid "" +"%s options command\n" +" -h, --help Show this help\n" +" --version Show version\n" +" -d, --daemon Start as daemon (Default false)\n" +" -r, --remote Remote daemon name\n" +"\n" +msgstr "" +"%s პარამეტრები ბრძანება\n" +" -h, --help ამ დახმარების ჩვენება\n" +" --version ვერსიის ჩვენება\n" +" -d, --daemon დაწყება როგორც დემონი (ნაგულისხმები " +"false)\n" +" -r, --remote დაშორებული დემონის სახელი\n" + +#: spa/plugins/alsa/acp/acp.c:321 +msgid "Pro Audio" +msgstr "Pro Audio" + +#: spa/plugins/alsa/acp/acp.c:446 spa/plugins/alsa/acp/alsa-mixer.c:4648 +#: spa/plugins/bluez5/bluez5-device.c:1161 +msgid "Off" +msgstr "გამორთული" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2652 +msgid "Input" +msgstr "შეყვანა" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2653 +msgid "Docking Station Input" +msgstr "Docking Station-ის შეყვანა" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2654 +msgid "Docking Station Microphone" +msgstr "Docking Station-ის მიკროფონი" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2655 +msgid "Docking Station Line In" +msgstr "Docking Station Line In" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2656 +#: spa/plugins/alsa/acp/alsa-mixer.c:2747 +msgid "Line In" +msgstr "Line In" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2657 +#: spa/plugins/alsa/acp/alsa-mixer.c:2741 +#: spa/plugins/bluez5/bluez5-device.c:1330 +msgid "Microphone" +msgstr "მიკროფონი" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2658 +#: spa/plugins/alsa/acp/alsa-mixer.c:2742 +msgid "Front Microphone" +msgstr "წინა მიკროფონი" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2659 +#: spa/plugins/alsa/acp/alsa-mixer.c:2743 +msgid "Rear Microphone" +msgstr "უკანა მიკფოფონი" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2660 +msgid "External Microphone" +msgstr "გარე მიკროფონი" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2661 +#: spa/plugins/alsa/acp/alsa-mixer.c:2745 +msgid "Internal Microphone" +msgstr "შიდა მიკროფონი" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2662 +#: spa/plugins/alsa/acp/alsa-mixer.c:2748 +msgid "Radio" +msgstr "რადიო" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2663 +#: spa/plugins/alsa/acp/alsa-mixer.c:2749 +msgid "Video" +msgstr "ვიდეო" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2664 +msgid "Automatic Gain Control" +msgstr "ხმის მომატების ავტომატური კონტროლი" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2665 +msgid "No Automatic Gain Control" +msgstr "ხმის მომატების ავტომატური კონტროლის გამორთვა" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2666 +msgid "Boost" +msgstr "გაძლიერება" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2667 +msgid "No Boost" +msgstr "გაძლიერების გარეშე" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2668 +msgid "Amplifier" +msgstr "გამაძლიერებელი" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2669 +msgid "No Amplifier" +msgstr "გამაძლიერებლის გარეშე" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2670 +msgid "Bass Boost" +msgstr "Bass-ის გაძლიერება" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2671 +msgid "No Bass Boost" +msgstr "Bass-ის გაძლიერების გარეშე" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2672 +#: spa/plugins/bluez5/bluez5-device.c:1335 +msgid "Speaker" +msgstr "დინამიკი" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2673 +#: spa/plugins/alsa/acp/alsa-mixer.c:2751 +msgid "Headphones" +msgstr "ყურსაცვამები" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2740 +msgid "Analog Input" +msgstr "ანალოგური შეყვანა" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2744 +msgid "Dock Microphone" +msgstr "მისამაგრებელი მიკროფონი" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2746 +msgid "Headset Microphone" +msgstr "ყურსაცვამის მიროფონი" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2750 +msgid "Analog Output" +msgstr "ანალოგური გამოტანა" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2752 +msgid "Headphones 2" +msgstr "ყურსაცვამები 2" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2753 +msgid "Headphones Mono Output" +msgstr "ყურსაცვამები მონო" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2754 +msgid "Line Out" +msgstr "ხაზოვანი გამოყვანა" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2755 +msgid "Analog Mono Output" +msgstr "ანალოგური მონო გამოყვანა" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2756 +msgid "Speakers" +msgstr "დინამიკები" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2757 +msgid "HDMI / DisplayPort" +msgstr "HDMI / DisplayPort" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2758 +msgid "Digital Output (S/PDIF)" +msgstr "ციფრული გამოყვანა (S/PDIF)" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2759 +msgid "Digital Input (S/PDIF)" +msgstr "ციფრული შეტანა (S/PDIF)" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2760 +msgid "Multichannel Input" +msgstr "მრავალარხიანი შეყვანა" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2761 +msgid "Multichannel Output" +msgstr "მრავალარხიანი გამოყვანა" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2762 +msgid "Game Output" +msgstr "თამაშის გამოყვანა" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2763 +#: spa/plugins/alsa/acp/alsa-mixer.c:2764 +msgid "Chat Output" +msgstr "ჩატის გამოყვანა" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2765 +msgid "Chat Input" +msgstr "ჩატის შეყვანა" + +#: spa/plugins/alsa/acp/alsa-mixer.c:2766 +msgid "Virtual Surround 7.1" +msgstr "ვირტუალური სივრცითი ხმა 7.1" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4471 +msgid "Analog Mono" +msgstr "ანალოგური მონო" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4472 +msgid "Analog Mono (Left)" +msgstr "ანალოგური მონო (მარცხენა)" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4473 +msgid "Analog Mono (Right)" +msgstr "ანალოგური მონო (მარჯვენა)" + +#. Note: Not translated to "Analog Stereo Input", because the source +#. * name gets "Input" appended to it automatically, so adding "Input" +#. * here would lead to the source name to become "Analog Stereo Input +#. * Input". The same logic applies to analog-stereo-output, +#. * multichannel-input and multichannel-output. +#: spa/plugins/alsa/acp/alsa-mixer.c:4474 +#: spa/plugins/alsa/acp/alsa-mixer.c:4482 +#: spa/plugins/alsa/acp/alsa-mixer.c:4483 +msgid "Analog Stereo" +msgstr "ანალოგური სტერეო" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4475 +msgid "Mono" +msgstr "მონო" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4476 +msgid "Stereo" +msgstr "სტერეო" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4484 +#: spa/plugins/alsa/acp/alsa-mixer.c:4642 +#: spa/plugins/bluez5/bluez5-device.c:1320 +msgid "Headset" +msgstr "ყურსაცვამები & მიკროფონი" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4485 +#: spa/plugins/alsa/acp/alsa-mixer.c:4643 +msgid "Speakerphone" +msgstr "სამაგიდო დინამიკი" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4486 +#: spa/plugins/alsa/acp/alsa-mixer.c:4487 +msgid "Multichannel" +msgstr "მრავალარხიანი" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4488 +msgid "Analog Surround 2.1" +msgstr "ანალოგური სივრცითი 2.1" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4489 +msgid "Analog Surround 3.0" +msgstr "ანალოგური სივრცითი 3.0" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4490 +msgid "Analog Surround 3.1" +msgstr "ანალოგური სივრცითი 3.1" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4491 +msgid "Analog Surround 4.0" +msgstr "ანალოგური სივრცითი 4.0" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4492 +msgid "Analog Surround 4.1" +msgstr "ანალოგური სივრცითი 4.1" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4493 +msgid "Analog Surround 5.0" +msgstr "ანალოგური სივრცითი 5.0" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4494 +msgid "Analog Surround 5.1" +msgstr "ანალოგური სივრცითი 5.1" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4495 +msgid "Analog Surround 6.0" +msgstr "ანალოგური სივრცითი 6.0" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4496 +msgid "Analog Surround 6.1" +msgstr "ანალოგური სივრცითი 6.1" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4497 +msgid "Analog Surround 7.0" +msgstr "ანალოგური სივრცითი 7.0" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4498 +msgid "Analog Surround 7.1" +msgstr "ანალოგური სივრცითი 7.1" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4499 +msgid "Digital Stereo (IEC958)" +msgstr "ციფრული სტერეო (IEC958)" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4500 +msgid "Digital Surround 4.0 (IEC958/AC3)" +msgstr "ციფრული სივრცითი 4.0 (IEC958/AC3)" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4501 +msgid "Digital Surround 5.1 (IEC958/AC3)" +msgstr "ციფრული სივრცითი 5.1 (IEC958/AC3)" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4502 +msgid "Digital Surround 5.1 (IEC958/DTS)" +msgstr "ციფრული სივრცითი 5.1 (IEC958/DTS)" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4503 +msgid "Digital Stereo (HDMI)" +msgstr "ციფრული სტერეო (HDMI)" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4504 +msgid "Digital Surround 5.1 (HDMI)" +msgstr "ციფრული სივრცითი 5.1 (HDMI)" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4505 +msgid "Chat" +msgstr "ჩატი" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4506 +msgid "Game" +msgstr "თამაში" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4640 +msgid "Analog Mono Duplex" +msgstr "ანალოგური მონო დუპლექსი" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4641 +msgid "Analog Stereo Duplex" +msgstr "ანალოგური სტერეო დუპლექსი" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4644 +msgid "Digital Stereo Duplex (IEC958)" +msgstr "ციფრული სტერეო დუპლექსი (IEC958)" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4645 +msgid "Multichannel Duplex" +msgstr "მრავალარხიანი დუპლექსი" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4646 +msgid "Stereo Duplex" +msgstr "სტერეო დუპლექსი" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4647 +msgid "Mono Chat + 7.1 Surround" +msgstr "მონო ჩატი + 7.1 სივრცითი" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4754 +#, c-format +msgid "%s Output" +msgstr "%s გამოყვანა" + +#: spa/plugins/alsa/acp/alsa-mixer.c:4761 +#, c-format +msgid "%s Input" +msgstr "%s შეყვანა" + +#: spa/plugins/alsa/acp/alsa-util.c:1173 spa/plugins/alsa/acp/alsa-util.c:1267 +#, c-format +msgid "" +"snd_pcm_avail() returned a value that is exceptionally large: %lu byte (%lu " +"ms).\n" +"Most likely this is a bug in the ALSA driver '%s'. Please report this issue " +"to the ALSA developers." +msgid_plural "" +"snd_pcm_avail() returned a value that is exceptionally large: %lu bytes (%lu " +"ms).\n" +"Most likely this is a bug in the ALSA driver '%s'. Please report this issue " +"to the ALSA developers." +msgstr0 "" +"snd_pcm_avail()-ის მიერ დაბრუნებული მნიშვნელობა არაჩვეულებრივად დიდია: %lu " +"ბაიტი (%lu მწმ).\n" +"ყველაზე ხშირად ეს ALSA-ს დრაივერის (%s) შეცდომის გამო ხდება. დაუკავშირდით " +"ALSA-ის პროგრამისტებს." +msgstr1 "" +"snd_pcm_avail()-ის მიერ დაბრუნებული მნიშვნელობა არაჩვეულებრივად დიდია: %lu " +"ბაიტი (%lu მწმ).\n" +"ყველაზე ხშირად ეს ALSA-ს დრაივერის (%s) შეცდომის გამო ხდება. დაუკავშირდით " +"ALSA-ის პროგრამისტებს." + +#: spa/plugins/alsa/acp/alsa-util.c:1239 +#, c-format +msgid "" +"snd_pcm_delay() returned a value that is exceptionally large: %li byte (%s" +"%lu ms).\n" +"Most likely this is a bug in the ALSA driver '%s'. Please report this issue " +"to the ALSA developers." +msgid_plural "" +"snd_pcm_delay() returned a value that is exceptionally large: %li bytes (%s" +"%lu ms).\n" +"Most likely this is a bug in the ALSA driver '%s'. Please report this issue " +"to the ALSA developers." +msgstr0 "" +"snd_pcm_delay()-ის მიერ დაბრუნებული მნიშვნელობა არაჩვეულებრივად დიდია: %li " +"ბაიტი (%s%lu მწმ).\n" +"ყველაზე ხშირად ეს ALSA-ს დრაივერის (%s) შეცდომის გამო ხდება. დაუკავშირდით " +"ALSA-ის პროგრამისტებს." +msgstr1 "" +"snd_pcm_delay()-ის მიერ დაბრუნებული მნიშვნელობა არაჩვეულებრივად დიდია: %li " +"ბაიტი (%s%lu მწმ).\n" +"ყველაზე ხშირად ეს ALSA-ს დრაივერის (%s) შეცდომის გამო ხდება. დაუკავშირდით " +"ALSA-ის პროგრამისტებს." + +#: spa/plugins/alsa/acp/alsa-util.c:1286 +#, c-format +msgid "" +"snd_pcm_avail_delay() returned strange values: delay %lu is less than avail " +"%lu.\n" +"Most likely this is a bug in the ALSA driver '%s'. Please report this issue " +"to the ALSA developers." +msgstr "" +"snd_pcm_avail_delay()-ის მიერ დაბრუნებული მნიშვნელობები უცნაურია: დაყოვნება " +"%lu უფრო მცირეა, ვიდრე ხელმისაწვდომი დრო %lu.\n" +"ყველაზე ხშირად ეს ALSA-ს დრაივერის (%s) შეცდომის გამო ხდება. დაუკავშირდით " +"ALSA-ის პროგრამისტებს." + +#: spa/plugins/alsa/acp/alsa-util.c:1329 +#, c-format +msgid "" +"snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu byte " +"(%lu ms).\n" +"Most likely this is a bug in the ALSA driver '%s'. Please report this issue " +"to the ALSA developers." +msgid_plural "" +"snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu bytes " +"(%lu ms).\n" +"Most likely this is a bug in the ALSA driver '%s'. Please report this issue " +"to the ALSA developers." +msgstr0 "" +"snd_pcm_mmap_begin()-ის მიერ დაბრუნებული მნიშვნელობა არაჩვეულებრივად დიდია: " +"%lu ბაიტი (%lu მწმ).\n" +"ყველაზე ხშირად ეს ALSA-ს დრაივერის (%s) შეცდომის გამო ხდება. დაუკავშირდით " +"ALSA-ის პროგრამისტებს." +msgstr1 "" +"snd_pcm_mmap_begin()-ის მიერ დაბრუნებული მნიშვნელობა არაჩვეულებრივად დიდია: " +"%lu ბაიტი (%lu მწმ).\n" +"ყველაზე ხშირად ეს ALSA-ს დრაივერის (%s) შეცდომის გამო ხდება. დაუკავშირდით " +"ALSA-ის პროგრამისტებს." + +#: spa/plugins/alsa/acp/channelmap.h:457 +msgid "(invalid)" +msgstr "(არასწორი)" + +#: spa/plugins/alsa/acp/compat.c:189 +msgid "Built-in Audio" +msgstr "ჩაშენებული აუდიო" + +#: spa/plugins/alsa/acp/compat.c:194 +msgid "Modem" +msgstr "მოდემი" + +#: spa/plugins/bluez5/bluez5-device.c:1172 +msgid "Audio Gateway (A2DP Source & HSP/HFP AG)" +msgstr "Audio Gateway (A2DP წყარო & HSP/HFP AG)" + +#: spa/plugins/bluez5/bluez5-device.c:1197 +#, c-format +msgid "High Fidelity Playback (A2DP Sink, codec %s)" +msgstr "მაღალი ხარისხის ხმა (A2DP Sink, კოდეკი %s)" + +#: spa/plugins/bluez5/bluez5-device.c:1200 +#, c-format +msgid "High Fidelity Duplex (A2DP Source/Sink, codec %s)" +msgstr "მაღალი ხარისხის დუპლექსი (A2DP წყარო/Sink, კოდეკი %s)" + +#: spa/plugins/bluez5/bluez5-device.c:1208 +msgid "High Fidelity Playback (A2DP Sink)" +msgstr "მაღალი ხარისხის ხმა (A2DP Sink)" + +#: spa/plugins/bluez5/bluez5-device.c:1210 +msgid "High Fidelity Duplex (A2DP Source/Sink)" +msgstr "მაღალი ხარისხის დუპლექსი(A2DP წყარო/Sink)" + +#: spa/plugins/bluez5/bluez5-device.c:1238 +#, c-format +msgid "Headset Head Unit (HSP/HFP, codec %s)" +msgstr "Headset Head Unit (HSP/HFP, კოდეკი %s)" + +#: spa/plugins/bluez5/bluez5-device.c:1243 +msgid "Headset Head Unit (HSP/HFP)" +msgstr "Headset Head Unit (HSP/HFP)" + +#: spa/plugins/bluez5/bluez5-device.c:1325 +msgid "Handsfree" +msgstr "ხელის გარეშე სამართავი" + +#: spa/plugins/bluez5/bluez5-device.c:1340 +msgid "Headphone" +msgstr "ყურსაცვამი" + +#: spa/plugins/bluez5/bluez5-device.c:1345 +msgid "Portable" +msgstr "გადატანადი" + +#: spa/plugins/bluez5/bluez5-device.c:1350 +msgid "Car" +msgstr "მანქანა" + +#: spa/plugins/bluez5/bluez5-device.c:1355 +msgid "HiFi" +msgstr "HiFi" + +#: spa/plugins/bluez5/bluez5-device.c:1360 +msgid "Phone" +msgstr "ტელეფონი" + +#: spa/plugins/bluez5/bluez5-device.c:1366 +msgid "Bluetooth" +msgstr "Bluetooth"
View file
pipewire-0.3.56.tar.gz/po/pl.po -> pipewire-0.3.57.tar.gz/po/pl.po
Changed
@@ -8,8 +8,8 @@ "Project-Id-Version: pipewire\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/-/" "issues\n" -"POT-Creation-Date: 2022-05-20 15:26+0000\n" -"PO-Revision-Date: 2022-05-21 12:49+0200\n" +"POT-Creation-Date: 2022-08-27 13:57+0000\n" +"PO-Revision-Date: 2022-08-27 16:00+0200\n" "Last-Translator: Piotr Drąg <piotrdrag@gmail.com>\n" "Language-Team: Polish <community-poland@mozilla.org>\n" "Language: pl\n" @@ -41,8 +41,8 @@ msgid "Start the PipeWire Media System" msgstr "Uruchomienie systemu multimediów PipeWire" -#: src/modules/module-protocol-pulse/modules/module-tunnel-sink.c:183 -#: src/modules/module-protocol-pulse/modules/module-tunnel-source.c:183 +#: src/modules/module-protocol-pulse/modules/module-tunnel-sink.c:180 +#: src/modules/module-protocol-pulse/modules/module-tunnel-source.c:180 #, c-format msgid "Tunnel to %s/%s" msgstr "Tunel do %s/%s" @@ -51,7 +51,7 @@ msgid "Dummy Output" msgstr "Głuche wyjście" -#: src/modules/module-pulse-tunnel.c:639 +#: src/modules/module-pulse-tunnel.c:648 #, c-format msgid "Tunnel for %s@%s" msgstr "Tunel dla %s@%s" @@ -70,7 +70,7 @@ msgid "%s on %s" msgstr "%s na %s" -#: src/tools/pw-cat.c:872 +#: src/tools/pw-cat.c:784 #, c-format msgid "" "%s options <file>|-\n" @@ -85,7 +85,7 @@ " -v, --verbose Wyświetla więcej komunikatów\n" "\n" -#: src/tools/pw-cat.c:879 +#: src/tools/pw-cat.c:791 #, c-format msgid "" " -R, --remote Remote daemon name\n" @@ -122,7 +122,7 @@ " -P --properties Ustawia właściwości węzła\n" "\n" -#: src/tools/pw-cat.c:897 +#: src/tools/pw-cat.c:809 #, c-format msgid "" " --rate Sample rate (req. for rec) (default " @@ -158,7 +158,7 @@ "(domyślnie %d)\n" "\n" -#: src/tools/pw-cat.c:914 +#: src/tools/pw-cat.c:826 msgid "" " -p, --playback Playback mode\n" " -r, --record Recording mode\n" @@ -172,7 +172,7 @@ " -d, --dsd Tryb DSD\n" "\n" -#: src/tools/pw-cli.c:3139 +#: src/tools/pw-cli.c:2255 #, c-format msgid "" "%s options command\n" @@ -195,7 +195,7 @@ msgstr "Dźwięk w zastosowaniach profesjonalnych" #: spa/plugins/alsa/acp/acp.c:444 spa/plugins/alsa/acp/alsa-mixer.c:4648 -#: spa/plugins/bluez5/bluez5-device.c:1161 +#: spa/plugins/bluez5/bluez5-device.c:1188 msgid "Off" msgstr "Wyłączone" @@ -222,7 +222,7 @@ #: spa/plugins/alsa/acp/alsa-mixer.c:2657 #: spa/plugins/alsa/acp/alsa-mixer.c:2741 -#: spa/plugins/bluez5/bluez5-device.c:1330 +#: spa/plugins/bluez5/bluez5-device.c:1360 msgid "Microphone" msgstr "Mikrofon" @@ -288,7 +288,7 @@ msgstr "Brak podbicia basów" #: spa/plugins/alsa/acp/alsa-mixer.c:2672 -#: spa/plugins/bluez5/bluez5-device.c:1335 +#: spa/plugins/bluez5/bluez5-device.c:1366 msgid "Speaker" msgstr "Głośnik" @@ -403,7 +403,7 @@ #: spa/plugins/alsa/acp/alsa-mixer.c:4484 #: spa/plugins/alsa/acp/alsa-mixer.c:4642 -#: spa/plugins/bluez5/bluez5-device.c:1320 +#: spa/plugins/bluez5/bluez5-device.c:1348 msgid "Headset" msgstr "Słuchawki z mikrofonem" @@ -527,7 +527,7 @@ msgid "%s Input" msgstr "Wejście %s" -#: spa/plugins/alsa/acp/alsa-util.c:1173 spa/plugins/alsa/acp/alsa-util.c:1267 +#: spa/plugins/alsa/acp/alsa-util.c:1187 spa/plugins/alsa/acp/alsa-util.c:1281 #, c-format msgid "" "snd_pcm_avail() returned a value that is exceptionally large: %lu byte (%lu " @@ -552,7 +552,7 @@ "Prawdopodobnie jest to błąd sterownika ALSA „%s”. Proszę zgłosić ten problem " "programistom usługi ALSA." -#: spa/plugins/alsa/acp/alsa-util.c:1239 +#: spa/plugins/alsa/acp/alsa-util.c:1253 #, c-format msgid "" "snd_pcm_delay() returned a value that is exceptionally large: %li byte (%s" @@ -577,7 +577,7 @@ "Prawdopodobnie jest to błąd sterownika ALSA „%s”. Proszę zgłosić ten problem " "programistom usługi ALSA." -#: spa/plugins/alsa/acp/alsa-util.c:1286 +#: spa/plugins/alsa/acp/alsa-util.c:1300 #, c-format msgid "" "snd_pcm_avail_delay() returned strange values: delay %lu is less than avail " @@ -590,7 +590,7 @@ "Prawdopodobnie jest to błąd sterownika ALSA „%s”. Proszę zgłosić ten problem " "programistom usługi ALSA." -#: spa/plugins/alsa/acp/alsa-util.c:1329 +#: spa/plugins/alsa/acp/alsa-util.c:1343 #, c-format msgid "" "snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu byte " @@ -615,7 +615,7 @@ "Prawdopodobnie jest to błąd sterownika ALSA „%s”. Proszę zgłosić ten problem " "programistom usługi ALSA." -#: spa/plugins/alsa/acp/channelmap.h:464 +#: spa/plugins/alsa/acp/channelmap.h:457 msgid "(invalid)" msgstr "(nieprawidłowe)" @@ -627,61 +627,77 @@ msgid "Modem" msgstr "Modem" -#: spa/plugins/bluez5/bluez5-device.c:1172 +#: spa/plugins/bluez5/bluez5-device.c:1199 msgid "Audio Gateway (A2DP Source & HSP/HFP AG)" msgstr "Bramka dźwięku (źródło A2DP i AG HSP/HFP)" -#: spa/plugins/bluez5/bluez5-device.c:1197 +#: spa/plugins/bluez5/bluez5-device.c:1224 #, c-format msgid "High Fidelity Playback (A2DP Sink, codec %s)" msgstr "Odtwarzanie o wysokiej dokładności (odpływ A2DP, kodek %s)" -#: spa/plugins/bluez5/bluez5-device.c:1200 +#: spa/plugins/bluez5/bluez5-device.c:1227 #, c-format msgid "High Fidelity Duplex (A2DP Source/Sink, codec %s)" msgstr "Dupleks o wysokiej dokładności (źródło/odpływ A2DP, kodek %s)" -#: spa/plugins/bluez5/bluez5-device.c:1208 +#: spa/plugins/bluez5/bluez5-device.c:1235 msgid "High Fidelity Playback (A2DP Sink)" msgstr "Odtwarzanie o wysokiej dokładności (odpływ A2DP)" -#: spa/plugins/bluez5/bluez5-device.c:1210 +#: spa/plugins/bluez5/bluez5-device.c:1237 msgid "High Fidelity Duplex (A2DP Source/Sink)" msgstr "Dupleks o wysokiej dokładności (źródło/odpływ A2DP)" -#: spa/plugins/bluez5/bluez5-device.c:1238 +#: spa/plugins/bluez5/bluez5-device.c:1265 #, c-format msgid "Headset Head Unit (HSP/HFP, codec %s)" msgstr "Jednostka główna słuchawek z mikrofonem (HSP/HFP, kodek %s)" -#: spa/plugins/bluez5/bluez5-device.c:1243 +#: spa/plugins/bluez5/bluez5-device.c:1270 msgid "Headset Head Unit (HSP/HFP)" msgstr "Jednostka główna słuchawek z mikrofonem (HSP/HFP)" -#: spa/plugins/bluez5/bluez5-device.c:1325 +#: spa/plugins/bluez5/bluez5-device.c:1349 +#: spa/plugins/bluez5/bluez5-device.c:1354 +#: spa/plugins/bluez5/bluez5-device.c:1361 +#: spa/plugins/bluez5/bluez5-device.c:1367 +#: spa/plugins/bluez5/bluez5-device.c:1373 +#: spa/plugins/bluez5/bluez5-device.c:1379 +#: spa/plugins/bluez5/bluez5-device.c:1385 +#: spa/plugins/bluez5/bluez5-device.c:1391 +#: spa/plugins/bluez5/bluez5-device.c:1397 msgid "Handsfree" msgstr "Zestaw głośnomówiący" -#: spa/plugins/bluez5/bluez5-device.c:1340 +#: spa/plugins/bluez5/bluez5-device.c:1355 +msgid "Handsfree (HFP)" +msgstr "Zestaw głośnomówiący (HFP)" + +#: spa/plugins/bluez5/bluez5-device.c:1372 msgid "Headphone" msgstr "Słuchawki" -#: spa/plugins/bluez5/bluez5-device.c:1345 +#: spa/plugins/bluez5/bluez5-device.c:1378 msgid "Portable" msgstr "Przenośne" -#: spa/plugins/bluez5/bluez5-device.c:1350 +#: spa/plugins/bluez5/bluez5-device.c:1384 msgid "Car" msgstr "Samochód" -#: spa/plugins/bluez5/bluez5-device.c:1355 +#: spa/plugins/bluez5/bluez5-device.c:1390 msgid "HiFi" msgstr "HiFi" -#: spa/plugins/bluez5/bluez5-device.c:1360 +#: spa/plugins/bluez5/bluez5-device.c:1396 msgid "Phone" msgstr "Telefon" -#: spa/plugins/bluez5/bluez5-device.c:1366 +#: spa/plugins/bluez5/bluez5-device.c:1403 msgid "Bluetooth" msgstr "Bluetooth" + +#: spa/plugins/bluez5/bluez5-device.c:1404 +msgid "Bluetooth (HFP)" +msgstr "Bluetooth (HFP)"
View file
pipewire-0.3.56.tar.gz/po/sv.po -> pipewire-0.3.57.tar.gz/po/sv.po
Changed
@@ -19,8 +19,8 @@ "Project-Id-Version: pipewire\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/-/" "issues\n" -"POT-Creation-Date: 2022-05-20 15:26+0000\n" -"PO-Revision-Date: 2022-05-23 11:01+0200\n" +"POT-Creation-Date: 2022-07-19 15:27+0000\n" +"PO-Revision-Date: 2022-07-10 10:22+0200\n" "Last-Translator: Anders Jonsson <anders.jonsson@norsjovallen.se>\n" "Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n" "Language: sv\n" @@ -28,7 +28,7 @@ "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Poedit 3.0.1\n" +"X-Generator: Poedit 3.1\n" #: src/daemon/pipewire.c:46 #, c-format @@ -51,8 +51,8 @@ msgid "Start the PipeWire Media System" msgstr "Starta mediasystemet PipeWire" -#: src/modules/module-protocol-pulse/modules/module-tunnel-sink.c:183 -#: src/modules/module-protocol-pulse/modules/module-tunnel-source.c:183 +#: src/modules/module-protocol-pulse/modules/module-tunnel-sink.c:180 +#: src/modules/module-protocol-pulse/modules/module-tunnel-source.c:180 #, c-format msgid "Tunnel to %s/%s" msgstr "Tunnel till %s/%s" @@ -61,7 +61,7 @@ msgid "Dummy Output" msgstr "Attrapputgång" -#: src/modules/module-pulse-tunnel.c:639 +#: src/modules/module-pulse-tunnel.c:648 #, c-format msgid "Tunnel for %s@%s" msgstr "Tunnel för %s@%s" @@ -80,7 +80,7 @@ msgid "%s on %s" msgstr "%s på %s" -#: src/tools/pw-cat.c:872 +#: src/tools/pw-cat.c:784 #, c-format msgid "" "%s options <file>|-\n" @@ -95,7 +95,7 @@ " -v, --verbose Aktivera utförliga operationer\n" "\n" -#: src/tools/pw-cat.c:879 +#: src/tools/pw-cat.c:791 #, c-format msgid "" " -R, --remote Remote daemon name\n" @@ -125,7 +125,7 @@ " -P --properties Sätt nodegenskaper\n" "\n" -#: src/tools/pw-cat.c:897 +#: src/tools/pw-cat.c:809 #, c-format msgid "" " --rate Sample rate (req. for rec) (default " @@ -160,7 +160,7 @@ "%d)\n" "\n" -#: src/tools/pw-cat.c:914 +#: src/tools/pw-cat.c:826 msgid "" " -p, --playback Playback mode\n" " -r, --record Recording mode\n" @@ -174,7 +174,7 @@ " -d, --dsd DSD-läge\n" "\n" -#: src/tools/pw-cli.c:3139 +#: src/tools/pw-cli.c:3165 #, c-format msgid "" "%s options command\n" @@ -195,8 +195,8 @@ msgid "Pro Audio" msgstr "Professionellt ljud" -#: spa/plugins/alsa/acp/acp.c:444 spa/plugins/alsa/acp/alsa-mixer.c:4648 -#: spa/plugins/bluez5/bluez5-device.c:1161 +#: spa/plugins/alsa/acp/acp.c:446 spa/plugins/alsa/acp/alsa-mixer.c:4648 +#: spa/plugins/bluez5/bluez5-device.c:1188 msgid "Off" msgstr "Av" @@ -223,7 +223,7 @@ #: spa/plugins/alsa/acp/alsa-mixer.c:2657 #: spa/plugins/alsa/acp/alsa-mixer.c:2741 -#: spa/plugins/bluez5/bluez5-device.c:1330 +#: spa/plugins/bluez5/bluez5-device.c:1360 msgid "Microphone" msgstr "Mikrofon" @@ -289,7 +289,7 @@ msgstr "Ingen basökning" #: spa/plugins/alsa/acp/alsa-mixer.c:2672 -#: spa/plugins/bluez5/bluez5-device.c:1335 +#: spa/plugins/bluez5/bluez5-device.c:1366 msgid "Speaker" msgstr "Högtalare" @@ -404,7 +404,7 @@ #: spa/plugins/alsa/acp/alsa-mixer.c:4484 #: spa/plugins/alsa/acp/alsa-mixer.c:4642 -#: spa/plugins/bluez5/bluez5-device.c:1320 +#: spa/plugins/bluez5/bluez5-device.c:1348 msgid "Headset" msgstr "Headset" @@ -554,13 +554,13 @@ #: spa/plugins/alsa/acp/alsa-util.c:1239 #, c-format msgid "" -"snd_pcm_delay() returned a value that is exceptionally large: %li byte " -"(%s%lu ms).\n" +"snd_pcm_delay() returned a value that is exceptionally large: %li byte (%s" +"%lu ms).\n" "Most likely this is a bug in the ALSA driver '%s'. Please report this issue " "to the ALSA developers." msgid_plural "" -"snd_pcm_delay() returned a value that is exceptionally large: %li bytes " -"(%s%lu ms).\n" +"snd_pcm_delay() returned a value that is exceptionally large: %li bytes (%s" +"%lu ms).\n" "Most likely this is a bug in the ALSA driver '%s'. Please report this issue " "to the ALSA developers." msgstr0 "" @@ -610,7 +610,7 @@ "Förmodligen är detta ett fel i ALSA-drivrutinen ”%s”. Vänligen rapportera " "problemet till ALSA-utvecklarna." -#: spa/plugins/alsa/acp/channelmap.h:464 +#: spa/plugins/alsa/acp/channelmap.h:457 msgid "(invalid)" msgstr "(ogiltig)" @@ -622,61 +622,77 @@ msgid "Modem" msgstr "Modem" -#: spa/plugins/bluez5/bluez5-device.c:1172 +#: spa/plugins/bluez5/bluez5-device.c:1199 msgid "Audio Gateway (A2DP Source & HSP/HFP AG)" msgstr "Audio gateway (A2DP-källa & HSP/HFP AG)" -#: spa/plugins/bluez5/bluez5-device.c:1197 +#: spa/plugins/bluez5/bluez5-device.c:1224 #, c-format msgid "High Fidelity Playback (A2DP Sink, codec %s)" msgstr "High fidelity-uppspelning (A2DP-utgång, kodek %s)" -#: spa/plugins/bluez5/bluez5-device.c:1200 +#: spa/plugins/bluez5/bluez5-device.c:1227 #, c-format msgid "High Fidelity Duplex (A2DP Source/Sink, codec %s)" msgstr "High fidelity duplex (A2DP-källa/utgång, kodek %s)" -#: spa/plugins/bluez5/bluez5-device.c:1208 +#: spa/plugins/bluez5/bluez5-device.c:1235 msgid "High Fidelity Playback (A2DP Sink)" msgstr "High fidelity-uppspelning (A2DP-utgång)" -#: spa/plugins/bluez5/bluez5-device.c:1210 +#: spa/plugins/bluez5/bluez5-device.c:1237 msgid "High Fidelity Duplex (A2DP Source/Sink)" msgstr "High fidelity duplex (A2DP-källa/utgång)" -#: spa/plugins/bluez5/bluez5-device.c:1238 +#: spa/plugins/bluez5/bluez5-device.c:1265 #, c-format msgid "Headset Head Unit (HSP/HFP, codec %s)" msgstr "Headset-huvudenhet (HSP/HFP, kodek %s)" -#: spa/plugins/bluez5/bluez5-device.c:1243 +#: spa/plugins/bluez5/bluez5-device.c:1270 msgid "Headset Head Unit (HSP/HFP)" msgstr "Headset-huvudenhet (HSP/HFP)" -#: spa/plugins/bluez5/bluez5-device.c:1325 +#: spa/plugins/bluez5/bluez5-device.c:1349 +#: spa/plugins/bluez5/bluez5-device.c:1354 +#: spa/plugins/bluez5/bluez5-device.c:1361 +#: spa/plugins/bluez5/bluez5-device.c:1367 +#: spa/plugins/bluez5/bluez5-device.c:1373 +#: spa/plugins/bluez5/bluez5-device.c:1379 +#: spa/plugins/bluez5/bluez5-device.c:1385 +#: spa/plugins/bluez5/bluez5-device.c:1391 +#: spa/plugins/bluez5/bluez5-device.c:1397 msgid "Handsfree" msgstr "Handsfree" -#: spa/plugins/bluez5/bluez5-device.c:1340 +#: spa/plugins/bluez5/bluez5-device.c:1355 +msgid "Handsfree (HFP)" +msgstr "Handsfree (HFP)" + +#: spa/plugins/bluez5/bluez5-device.c:1372 msgid "Headphone" msgstr "Hörlurar" -#: spa/plugins/bluez5/bluez5-device.c:1345 +#: spa/plugins/bluez5/bluez5-device.c:1378 msgid "Portable" msgstr "Bärbar" -#: spa/plugins/bluez5/bluez5-device.c:1350 +#: spa/plugins/bluez5/bluez5-device.c:1384 msgid "Car" msgstr "Bil" -#: spa/plugins/bluez5/bluez5-device.c:1355 +#: spa/plugins/bluez5/bluez5-device.c:1390 msgid "HiFi" msgstr "HiFi" -#: spa/plugins/bluez5/bluez5-device.c:1360 +#: spa/plugins/bluez5/bluez5-device.c:1396 msgid "Phone" msgstr "Telefon" -#: spa/plugins/bluez5/bluez5-device.c:1366 +#: spa/plugins/bluez5/bluez5-device.c:1403 msgid "Bluetooth" msgstr "Bluetooth" + +#: spa/plugins/bluez5/bluez5-device.c:1404 +msgid "Bluetooth (HFP)" +msgstr "Bluetooth (HFP)"
View file
pipewire-0.3.56.tar.gz/spa/include/spa/interfaces/audio/aec.h -> pipewire-0.3.57.tar.gz/spa/include/spa/interfaces/audio/aec.h
Changed
@@ -68,9 +68,9 @@ const struct spa_audio_aec_events *events, void *data); - int (*init) (void *data, const struct spa_dict *args, const struct spa_audio_info_raw *info); - int (*run) (void *data, const float *rec, const float *play, float *out, uint32_t n_samples); - int (*set_props) (void *data, const struct spa_dict *args); + int (*init) (void *object, const struct spa_dict *args, const struct spa_audio_info_raw *info); + int (*run) (void *object, const float *rec, const float *play, float *out, uint32_t n_samples); + int (*set_props) (void *object, const struct spa_dict *args); }; #define spa_audio_aec_method(o,method,version,...) \
View file
pipewire-0.3.56.tar.gz/spa/include/spa/param/bluetooth/audio.h -> pipewire-0.3.57.tar.gz/spa/include/spa/param/bluetooth/audio.h
Changed
@@ -49,6 +49,11 @@ SPA_BLUETOOTH_AUDIO_CODEC_FASTSTREAM, SPA_BLUETOOTH_AUDIO_CODEC_FASTSTREAM_DUPLEX, SPA_BLUETOOTH_AUDIO_CODEC_LC3PLUS_HR, + SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05, + SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_51, + SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_71, + SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_DUPLEX, + SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_PRO, /* HFP */ SPA_BLUETOOTH_AUDIO_CODEC_CVSD = 0x100,
View file
pipewire-0.3.56.tar.gz/spa/include/spa/param/bluetooth/type-info.h -> pipewire-0.3.57.tar.gz/spa/include/spa/param/bluetooth/type-info.h
Changed
@@ -53,6 +53,11 @@ { SPA_BLUETOOTH_AUDIO_CODEC_FASTSTREAM, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "faststream", NULL }, { SPA_BLUETOOTH_AUDIO_CODEC_FASTSTREAM_DUPLEX, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "faststream_duplex", NULL }, { SPA_BLUETOOTH_AUDIO_CODEC_LC3PLUS_HR, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "lc3plus_hr", NULL }, + { SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "opus_05", NULL }, + { SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_51, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "opus_05_51", NULL }, + { SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_71, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "opus_05_71", NULL }, + { SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_DUPLEX, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "opus_05_duplex", NULL }, + { SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_PRO, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "opus_05_pro", NULL }, { SPA_BLUETOOTH_AUDIO_CODEC_CVSD, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "cvsd", NULL }, { SPA_BLUETOOTH_AUDIO_CODEC_MSBC, SPA_TYPE_Int, SPA_TYPE_INFO_BLUETOOTH_AUDIO_CODEC_BASE "msbc", NULL },
View file
pipewire-0.3.56.tar.gz/spa/include/spa/utils/defs.h -> pipewire-0.3.57.tar.gz/spa/include/spa/utils/defs.h
Changed
@@ -147,6 +147,12 @@ SPA_MIN(SPA_MAX(_v, _low), _high); \ }) +#define SPA_CLAMPF(v,low,high) \ +({ \ + fminf(fmaxf(v, low), high); \ +}) + + #define SPA_SWAP(a,b) \ ({ \ __typeof__(a) _t = (a); \ @@ -209,6 +215,7 @@ #define SPA_SENTINEL __attribute__((__sentinel__)) #define SPA_UNUSED __attribute__ ((unused)) #define SPA_NORETURN __attribute__ ((noreturn)) +#define SPA_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result)) #else #define SPA_PRINTF_FUNC(fmt, arg1) #define SPA_FORMAT_ARG_FUNC(arg1) @@ -218,6 +225,7 @@ #define SPA_SENTINEL #define SPA_UNUSED #define SPA_NORETURN +#define SPA_WARN_UNUSED_RESULT #endif #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
View file
pipewire-0.3.56.tar.gz/spa/include/spa/utils/hook.h -> pipewire-0.3.57.tar.gz/spa/include/spa/utils/hook.h
Changed
@@ -382,7 +382,8 @@ /** Remove a hook */ static inline void spa_hook_remove(struct spa_hook *hook) { - spa_list_remove(&hook->link); + if (spa_list_is_initialized(&hook->link)) + spa_list_remove(&hook->link); if (hook->removed) hook->removed(hook); }
View file
pipewire-0.3.56.tar.gz/spa/include/spa/utils/list.h -> pipewire-0.3.57.tar.gz/spa/include/spa/utils/list.h
Changed
@@ -51,6 +51,11 @@ *list = SPA_LIST_INIT(list); } +static inline int spa_list_is_initialized(struct spa_list *list) +{ + return !!list->prev; +} + #define spa_list_is_empty(l) ((l)->next == (l)) static inline void spa_list_insert(struct spa_list *list, struct spa_list *elem)
View file
pipewire-0.3.56.tar.gz/spa/meson.build -> pipewire-0.3.57.tar.gz/spa/meson.build
Changed
@@ -62,6 +62,8 @@ endif endif summary({'LC3plus': lc3plus_dep.found()}, bool_yn: true, section: 'Bluetooth audio codecs') + opus_dep = dependency('opus', required : get_option('bluez5-codec-opus')) + summary({'Opus': opus_dep.found()}, bool_yn: true, section: 'Bluetooth audio codecs') endif avcodec_dep = dependency('libavcodec', required: get_option('ffmpeg')) jack_dep = dependency('jack', version : '>= 1.9.10', required: get_option('jack'))
View file
pipewire-0.3.56.tar.gz/spa/plugins/aec/aec-null.c -> pipewire-0.3.57.tar.gz/spa/plugins/aec/aec-null.c
Changed
@@ -58,19 +58,18 @@ return 0; } -static struct spa_audio_aec_methods impl_aec = { +static const struct spa_audio_aec_methods impl_aec = { + SPA_VERSION_AUDIO_AEC, .init = null_init, .run = null_run, }; static int impl_get_interface(struct spa_handle *handle, const char *type, void **interface) { - struct impl *impl; - spa_return_val_if_fail(handle != NULL, -EINVAL); spa_return_val_if_fail(interface != NULL, -EINVAL); - impl = (struct impl *) handle; + struct impl *impl = (struct impl *) handle; if (spa_streq(type, SPA_TYPE_INTERFACE_AUDIO_AEC)) *interface = &impl->aec; @@ -101,15 +100,13 @@ const struct spa_support *support, uint32_t n_support) { - struct impl *impl; - spa_return_val_if_fail(factory != NULL, -EINVAL); spa_return_val_if_fail(handle != NULL, -EINVAL); handle->get_interface = impl_get_interface; handle->clear = impl_clear; - impl = (struct impl *) handle; + struct impl *impl = (struct impl *) handle; impl->aec.iface = SPA_INTERFACE_INIT( SPA_TYPE_INTERFACE_AUDIO_AEC, @@ -119,7 +116,7 @@ impl->aec.info = NULL; impl->aec.latency = NULL; - impl->log = (struct spa_log*)spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log); + impl->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log); spa_log_topic_init(impl->log, &log_topic); spa_hook_list_init(&impl->hooks_list); @@ -151,7 +148,7 @@ return 1; } -const struct spa_handle_factory spa_aec_null_factory = { +static const struct spa_handle_factory spa_aec_null_factory = { SPA_VERSION_HANDLE_FACTORY, SPA_NAME_AEC, NULL, @@ -160,7 +157,6 @@ impl_enum_interface_info, }; - SPA_EXPORT int spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t *index) {
View file
pipewire-0.3.56.tar.gz/spa/plugins/aec/aec-webrtc.cpp -> pipewire-0.3.57.tar.gz/spa/plugins/aec/aec-webrtc.cpp
Changed
@@ -50,19 +50,17 @@ #undef SPA_LOG_TOPIC_DEFAULT #define SPA_LOG_TOPIC_DEFAULT &log_topic -static bool webrtc_get_spa_bool(const struct spa_dict *args, const char *key, bool default_value) { - const char *str_val; - bool value = default_value; - str_val = spa_dict_lookup(args, key); - if (str_val != NULL) - value =spa_atob(str_val); - - return value; +static bool webrtc_get_spa_bool(const struct spa_dict *args, const char *key, bool default_value) +{ + if (auto str = spa_dict_lookup(args, key)) + return spa_atob(str); + + return default_value; } -static int webrtc_init(void *data, const struct spa_dict *args, const struct spa_audio_info_raw *info) +static int webrtc_init(void *object, const struct spa_dict *args, const struct spa_audio_info_raw *info) { - auto impl = reinterpret_cast<struct impl_data*>(data); + auto impl = static_cast<struct impl_data*>(object); bool extended_filter = webrtc_get_spa_bool(args, "webrtc.extended_filter", true); bool delay_agnostic = webrtc_get_spa_bool(args, "webrtc.delay_agnostic", true); @@ -122,9 +120,9 @@ return 0; } -static int webrtc_run(void *data, const float *rec, const float *play, float *out, uint32_t n_samples) +static int webrtc_run(void *object, const float *rec, const float *play, float *out, uint32_t n_samples) { - auto impl = reinterpret_cast<struct impl_data*>(data); + auto impl = static_cast<struct impl_data*>(object); webrtc::StreamConfig config = webrtc::StreamConfig(impl->info.rate, impl->info.channels, false); unsigned int num_blocks = n_samples * 1000 / impl->info.rate / 10; @@ -160,7 +158,7 @@ return 0; } -static struct spa_audio_aec_methods impl_aec = { +static const struct spa_audio_aec_methods impl_aec = { SPA_VERSION_AUDIO_AEC_METHODS, .add_listener = NULL, .init = webrtc_init, @@ -220,7 +218,7 @@ impl->aec.info = NULL; impl->aec.latency = "480/48000", - impl->log = (struct spa_log*)spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log); + impl->log = static_cast<struct spa_log *>(spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log)); spa_log_topic_init(impl->log, &log_topic); return 0; @@ -250,7 +248,7 @@ return 1; } -const struct spa_handle_factory spa_aec_webrtc_factory = { +static const struct spa_handle_factory spa_aec_webrtc_factory = { SPA_VERSION_HANDLE_FACTORY, SPA_NAME_AEC, NULL, @@ -259,7 +257,6 @@ impl_enum_interface_info, }; - SPA_EXPORT int spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t *index) {
View file
pipewire-0.3.56.tar.gz/spa/plugins/alsa/acp/acp.c -> pipewire-0.3.57.tar.gz/spa/plugins/alsa/acp/acp.c
Changed
@@ -382,8 +382,7 @@ 0, NULL, NULL, false))) { pa_alsa_init_proplist_pcm(NULL, m->output_proplist, m->output_pcm); pa_proplist_setf(m->output_proplist, "clock.name", "api.alsa.%u", index); - snd_pcm_close(m->output_pcm); - m->output_pcm = NULL; + pa_alsa_close(&m->output_pcm); m->supported = true; pa_channel_map_init_auto(&m->channel_map, m->sample_spec.channels, PA_CHANNEL_MAP_AUX); } @@ -413,8 +412,7 @@ 0, NULL, NULL, false))) { pa_alsa_init_proplist_pcm(NULL, m->input_proplist, m->input_pcm); pa_proplist_setf(m->input_proplist, "clock.name", "api.alsa.%u", index); - snd_pcm_close(m->input_pcm); - m->input_pcm = NULL; + pa_alsa_close(&m->input_pcm); m->supported = true; pa_channel_map_init_auto(&m->channel_map, m->sample_spec.channels, PA_CHANNEL_MAP_AUX); } @@ -1058,6 +1056,9 @@ uint32_t i; int res; + if (!dev->mixer_handle) + return 0; + if ((res = pa_alsa_path_get_volume(dev->mixer_path, dev->mixer_handle, &dev->mapping->channel_map, &r)) < 0) return res; @@ -1089,6 +1090,9 @@ dev->real_volume = *v; + if (!dev->mixer_handle) + return; + /* Shift up by the base volume */ pa_sw_cvolume_divide_scalar(&r, &dev->real_volume, dev->base_volume); @@ -1139,6 +1143,9 @@ bool mute; int res; + if (!dev->mixer_handle) + return 0; + if ((res = pa_alsa_path_get_mute(dev->mixer_path, dev->mixer_handle, &mute)) < 0) return res; @@ -1157,6 +1164,10 @@ static void set_mute(pa_alsa_device *dev, bool mute) { dev->muted = mute; + + if (!dev->mixer_handle) + return; + pa_alsa_path_set_mute(dev->mixer_path, dev->mixer_handle, mute); } @@ -1735,7 +1746,8 @@ setting = data->setting; } - pa_alsa_path_select(d->mixer_path, setting, d->mixer_handle, d->muted); + if (d->mixer_handle) + pa_alsa_path_select(d->mixer_path, setting, d->mixer_handle, d->muted); if (d->set_mute) d->set_mute(d, d->muted);
View file
pipewire-0.3.56.tar.gz/spa/plugins/alsa/acp/alsa-mixer.c -> pipewire-0.3.57.tar.gz/spa/plugins/alsa/acp/alsa-mixer.c
Changed
@@ -4966,8 +4966,7 @@ continue; pa_alsa_init_proplist_pcm(NULL, m->output_proplist, m->output_pcm); - snd_pcm_close(m->output_pcm); - m->output_pcm = NULL; + pa_alsa_close(&m->output_pcm); } if (to_be_finalized->input_mappings) @@ -4986,8 +4985,7 @@ continue; pa_alsa_init_proplist_pcm(NULL, m->input_proplist, m->input_pcm); - snd_pcm_close(m->input_pcm); - m->input_pcm = NULL; + pa_alsa_close(&m->input_pcm); } }
View file
pipewire-0.3.56.tar.gz/spa/plugins/alsa/acp/alsa-ucm.c -> pipewire-0.3.57.tar.gz/spa/plugins/alsa/acp/alsa-ucm.c
Changed
@@ -1941,8 +1941,7 @@ continue; pa_alsa_init_proplist_pcm(NULL, m->output_proplist, m->output_pcm); - snd_pcm_close(m->output_pcm); - m->output_pcm = NULL; + pa_alsa_close(&m->output_pcm); } PA_IDXSET_FOREACH(m, p->input_mappings, idx) { @@ -1953,8 +1952,7 @@ continue; pa_alsa_init_proplist_pcm(NULL, m->input_proplist, m->input_pcm); - snd_pcm_close(m->input_pcm); - m->input_pcm = NULL; + pa_alsa_close(&m->input_pcm); } }
View file
pipewire-0.3.56.tar.gz/spa/plugins/alsa/acp/alsa-util.c -> pipewire-0.3.57.tar.gz/spa/plugins/alsa/acp/alsa-util.c
Changed
@@ -656,6 +656,20 @@ return pcm_handle; } +int pa_alsa_close(snd_pcm_t **pcm) +{ + int err; + pa_assert(pcm); + pa_log_info("ALSA device close %p", *pcm); + if (*pcm == NULL) + return 0; + if ((err = snd_pcm_close(*pcm)) < 0) { + pa_log_warn("ALSA close failed: %s", snd_strerror(err)); + } + *pcm = NULL; + return err; +} + snd_pcm_t *pa_alsa_open_by_device_string( const char *device, char **dev, @@ -691,8 +705,8 @@ pa_log_info("Error opening PCM device %s: %s", d, pa_alsa_strerror(err)); goto fail; } - - pa_log_debug("Managed to open %s", d); + pa_log_info("ALSA device open '%s' %s: %p", d, + mode == SND_PCM_STREAM_CAPTURE ? "capture" : "playback", pcm_handle); if ((err = pa_alsa_set_hw_params( pcm_handle, @@ -707,7 +721,7 @@ if (!reformat) { reformat = true; - snd_pcm_close(pcm_handle); + pa_alsa_close(&pcm_handle); continue; } @@ -721,12 +735,12 @@ reformat = false; - snd_pcm_close(pcm_handle); + pa_alsa_close(&pcm_handle); continue; } pa_log_info("Failed to set hardware parameters on %s: %s", d, pa_alsa_strerror(err)); - snd_pcm_close(pcm_handle); + pa_alsa_close(&pcm_handle); goto fail; } @@ -734,7 +748,7 @@ if (ss->channels > PA_CHANNELS_MAX) { pa_log("Device %s has %u channels, but PulseAudio supports only %u channels. Unable to use the device.", d, ss->channels, PA_CHANNELS_MAX); - snd_pcm_close(pcm_handle); + pa_alsa_close(&pcm_handle); goto fail; }
View file
pipewire-0.3.56.tar.gz/spa/plugins/alsa/acp/alsa-util.h -> pipewire-0.3.57.tar.gz/spa/plugins/alsa/acp/alsa-util.h
Changed
@@ -115,6 +115,7 @@ void pa_alsa_dump(pa_log_level_t level, snd_pcm_t *pcm); void pa_alsa_dump_status(snd_pcm_t *pcm); #endif +int pa_alsa_close(snd_pcm_t **pcm); void pa_alsa_refcnt_inc(void); void pa_alsa_refcnt_dec(void);
View file
pipewire-0.3.56.tar.gz/spa/plugins/alsa/alsa-pcm-sink.c -> pipewire-0.3.57.tar.gz/spa/plugins/alsa/alsa-pcm-sink.c
Changed
@@ -798,38 +798,38 @@ static int impl_node_process(void *object) { struct state *this = object; - struct spa_io_buffers *input; + struct spa_io_buffers *io; spa_return_val_if_fail(this != NULL, -EINVAL); - input = this->io; - spa_return_val_if_fail(input != NULL, -EIO); + if ((io = this->io) == NULL) + return -EIO; - spa_log_trace_fp(this->log, "%p: process %d %d/%d", this, input->status, - input->buffer_id, this->n_buffers); + spa_log_trace_fp(this->log, "%p: process %d %d/%d", this, io->status, + io->buffer_id, this->n_buffers); if (this->position && this->position->clock.flags & SPA_IO_CLOCK_FLAG_FREEWHEEL) { - input->status = SPA_STATUS_NEED_DATA; + io->status = SPA_STATUS_NEED_DATA; return SPA_STATUS_HAVE_DATA; } - if (input->status == SPA_STATUS_HAVE_DATA && - input->buffer_id < this->n_buffers) { - struct buffer *b = &this->buffersinput->buffer_id; + if (io->status == SPA_STATUS_HAVE_DATA && + io->buffer_id < this->n_buffers) { + struct buffer *b = &this->buffersio->buffer_id; if (!SPA_FLAG_IS_SET(b->flags, BUFFER_FLAG_OUT)) { spa_log_warn(this->log, "%p: buffer %u in use", - this, input->buffer_id); - input->status = -EINVAL; + this, io->buffer_id); + io->status = -EINVAL; return -EINVAL; } - spa_log_trace_fp(this->log, "%p: queue buffer %u", this, input->buffer_id); + spa_log_trace_fp(this->log, "%p: queue buffer %u", this, io->buffer_id); spa_list_append(&this->ready, &b->link); SPA_FLAG_CLEAR(b->flags, BUFFER_FLAG_OUT); - input->buffer_id = SPA_ID_INVALID; + io->buffer_id = SPA_ID_INVALID; spa_alsa_write(this); - input->status = SPA_STATUS_OK; + io->status = SPA_STATUS_OK; } return SPA_STATUS_HAVE_DATA; }
View file
pipewire-0.3.56.tar.gz/spa/plugins/alsa/alsa-pcm-source.c -> pipewire-0.3.57.tar.gz/spa/plugins/alsa/alsa-pcm-source.c
Changed
@@ -753,8 +753,8 @@ spa_return_val_if_fail(this != NULL, -EINVAL); - io = this->io; - spa_return_val_if_fail(io != NULL, -EIO); + if ((io = this->io) == NULL) + return -EIO; spa_log_trace_fp(this->log, "%p; status %d", this, io->status);
View file
pipewire-0.3.56.tar.gz/spa/plugins/alsa/alsa-pcm.c -> pipewire-0.3.57.tar.gz/spa/plugins/alsa/alsa-pcm.c
Changed
@@ -10,6 +10,7 @@ #include <spa/pod/filter.h> #include <spa/utils/string.h> +#include <spa/utils/result.h> #include <spa/support/system.h> #include <spa/utils/keys.h> @@ -442,9 +443,31 @@ return changed; } +#define CHECK(s,msg,...) if ((err = (s)) < 0) { spa_log_error(state->log, msg ": %s", ##__VA_ARGS__, snd_strerror(err)); return err; } + +static ssize_t log_write(void *cookie, const char *buf, size_t size) +{ + struct state *state = cookie; + int len; + + while (size > 0) { + len = strcspn(buf, "\n"); + if (len > 0) + spa_log_debug(state->log, "%.*s", (int)len, buf); + buf += len + 1; + size -= len + 1; + } + return size; +} + +static cookie_io_functions_t io_funcs = { + .write = log_write, +}; + int spa_alsa_init(struct state *state, const struct spa_dict *info) { uint32_t i; + int err; snd_config_update_free_global(); @@ -481,20 +504,31 @@ spa_log_error(state->log, "can't create card %u", state->card_index); return -errno; } + state->log_file = fopencookie(state, "w", io_funcs); + if (state->log_file == NULL) { + spa_log_error(state->log, "can't create log file"); + return -errno; + } + CHECK(snd_output_stdio_attach(&state->output, state->log_file, 0), "attach failed"); + return 0; } int spa_alsa_clear(struct state *state) { + int err; + release_card(state->card); state->card = NULL; state->card_index = SPA_ID_INVALID; - return 0; -} + if ((err = snd_output_close(state->output)) < 0) + spa_log_warn(state->log, "output close failed: %s", snd_strerror(err)); + fclose(state->log_file); -#define CHECK(s,msg,...) if ((err = (s)) < 0) { spa_log_error(state->log, msg ": %s", ##__VA_ARGS__, snd_strerror(err)); return err; } + return err; +} int spa_alsa_open(struct state *state, const char *params) { @@ -505,8 +539,6 @@ if (state->opened) return 0; - CHECK(snd_output_stdio_attach(&state->output, stderr, 0), "attach failed"); - spa_scnprintf(device_name, sizeof(device_name), "%s%s%s", state->card->ucm_prefix ? state->card->ucm_prefix : "", props->device, params ? params : ""); @@ -538,6 +570,8 @@ return 0; error_exit_close: + spa_log_info(state->log, "%p: Device '%s' closing: %s", state, state->props.device, + spa_strerror(err)); snd_pcm_close(state->hndl); return err; } @@ -556,9 +590,6 @@ spa_log_warn(state->log, "%s: close failed: %s", state->props.device, snd_strerror(err)); - if ((err = snd_output_close(state->output)) < 0) - spa_log_warn(state->log, "output close failed: %s", snd_strerror(err)); - spa_system_close(state->data_system, state->timerfd); if (state->have_format) @@ -763,6 +794,9 @@ CHECK(snd_pcm_hw_params_get_rate_min(params, &min, &dir), "get_rate_min"); CHECK(snd_pcm_hw_params_get_rate_max(params, &max, &dir), "get_rate_max"); + spa_log_debug(state->log, "min:%u max:%u min-allowed:%u scale:%u all:%d", + min, max, min_allowed_rate, scale, all); + min_allowed_rate /= scale; min = SPA_MAX(min_allowed_rate, min); @@ -782,6 +816,9 @@ rate = SPA_CLAMP(rate, min, max); + spa_log_debug(state->log, "rate:%u multi:%d card:%d def:%d", + rate, state->multi_rate, state->card->rate, state->default_rate); + spa_pod_builder_prop(b, SPA_FORMAT_AUDIO_rate, 0); spa_pod_builder_push_choice(b, &f0, SPA_CHOICE_None, 0); @@ -833,7 +870,8 @@ CHECK(snd_pcm_hw_params_get_channels_min(params, &min), "get_channels_min"); CHECK(snd_pcm_hw_params_get_channels_max(params, &max), "get_channels_max"); - spa_log_debug(state->log, "channels (%d %d)", min, max); + spa_log_debug(state->log, "channels (%d %d) default:%d all:%d", + min, max, state->default_channels, all); if (state->default_channels != 0 && !all) { if (min < state->default_channels) @@ -914,6 +952,14 @@ return 1; } +static void debug_hw_params(struct state *state, const char *prefix, snd_pcm_hw_params_t *params) +{ + if (SPA_UNLIKELY(spa_log_level_topic_enabled(state->log, SPA_LOG_TOPIC_DEFAULT, SPA_LOG_LEVEL_DEBUG))) { + spa_log_debug(state->log, "%s:", prefix); + snd_pcm_hw_params_dump(params, state->output); + fflush(state->log_file); + } +} static int enum_pcm_formats(struct state *state, uint32_t index, uint32_t *next, struct spa_pod **result, struct spa_pod_builder *b) { @@ -931,6 +977,8 @@ snd_pcm_hw_params_alloca(¶ms); CHECK(snd_pcm_hw_params_any(hndl, params), "Broken configuration: no configurations available"); + debug_hw_params(state, __func__, params); + CHECK(snd_pcm_hw_params_set_rate_resample(hndl, params, 0), "set_rate_resample"); if (state->default_channels != 0) { @@ -1077,6 +1125,8 @@ snd_pcm_hw_params_alloca(¶ms); CHECK(snd_pcm_hw_params_any(hndl, params), "Broken configuration: no configurations available"); + debug_hw_params(state, __func__, params); + CHECK(snd_pcm_hw_params_set_rate_resample(hndl, params, 0), "set_rate_resample"); spa_pod_builder_push_object(b, &f0, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat); @@ -1138,6 +1188,8 @@ snd_pcm_hw_params_alloca(¶ms); CHECK(snd_pcm_hw_params_any(hndl, params), "Broken configuration: no configurations available"); + debug_hw_params(state, __func__, params); + snd_pcm_format_mask_alloca(&fmask); snd_pcm_hw_params_get_format_mask(params, fmask); @@ -1197,7 +1249,12 @@ struct spa_result_node_params result; uint32_t count = 0; + spa_log_debug(state->log, "opened:%d format:%d started:%d", state->opened, + state->have_format, state->started); + opened = state->opened; + if (!state->started && state->have_format) + spa_alsa_close(state); if ((err = spa_alsa_open(state, NULL)) < 0) return err; @@ -1258,6 +1315,9 @@ bool match = true, planar = false, is_batch; char spdif_params128 = ""; + spa_log_debug(state->log, "opened:%d format:%d started:%d", state->opened, + state->have_format, state->started); + state->use_mmap = !state->disable_mmap; switch (fmt->media_subtype) { @@ -1370,6 +1430,8 @@ return -EINVAL; } + if (!state->started && state->have_format) + spa_alsa_close(state); if ((err = spa_alsa_open(state, spdif_params)) < 0) return err; @@ -1378,6 +1440,9 @@ snd_pcm_hw_params_alloca(¶ms); /* choose all parameters */ CHECK(snd_pcm_hw_params_any(hndl, params), "Broken configuration for playback: no configurations available"); + + debug_hw_params(state, __func__, params); + /* set hardware resampling, no resample */ CHECK(snd_pcm_hw_params_set_rate_resample(hndl, params, 0), "set_rate_resample"); @@ -1565,6 +1630,12 @@ /* write the parameters to the playback device */ CHECK(snd_pcm_sw_params(hndl, params), "sw_params"); + if (SPA_UNLIKELY(spa_log_level_topic_enabled(state->log, SPA_LOG_TOPIC_DEFAULT, SPA_LOG_LEVEL_DEBUG))) { + spa_log_debug(state->log, "state after sw_params:"); + snd_pcm_dump(hndl, state->output); + fflush(state->log_file); + } + return 0; } @@ -1778,6 +1849,7 @@ *delay = avail; *target = SPA_MAX(*target, state->read_size); } + *target = SPA_MIN(*target, state->buffer_frames); return 0; } @@ -2351,7 +2423,7 @@ } #ifndef FASTPATH - if (SPA_UNLIKELY(spa_log_level_enabled(state->log, SPA_LOG_LEVEL_TRACE))) { + if (SPA_UNLIKELY(spa_log_level_topic_enabled(state->log, SPA_LOG_TOPIC_DEFAULT, SPA_LOG_LEVEL_TRACE))) { struct timespec now; uint64_t nsec; if (spa_system_clock_gettime(state->data_system, CLOCK_MONOTONIC, &now) < 0) @@ -2446,8 +2518,6 @@ state->following, state->matching, state->resample); CHECK(set_swparams(state), "swparams"); - if (SPA_UNLIKELY(spa_log_level_enabled(state->log, SPA_LOG_LEVEL_DEBUG))) - snd_pcm_dump(state->hndl, state->output); if ((err = snd_pcm_prepare(state->hndl)) < 0 && err != -EBUSY) { spa_log_error(state->log, "%s: snd_pcm_prepare error: %s",
View file
pipewire-0.3.56.tar.gz/spa/plugins/alsa/alsa-pcm.h -> pipewire-0.3.57.tar.gz/spa/plugins/alsa/alsa-pcm.h
Changed
@@ -106,6 +106,8 @@ struct spa_system *data_system; struct spa_loop *data_loop; + FILE *log_file; + uint32_t card_index; struct card *card; snd_pcm_stream_t stream;
View file
pipewire-0.3.56.tar.gz/spa/plugins/alsa/alsa-seq.c -> pipewire-0.3.57.tar.gz/spa/plugins/alsa/alsa-seq.c
Changed
@@ -186,7 +186,7 @@ static void debug_event(struct seq_state *state, snd_seq_event_t *ev) { - if (SPA_LIKELY(!spa_log_level_enabled(state->log, SPA_LOG_LEVEL_TRACE))) + if (SPA_LIKELY(!spa_log_level_topic_enabled(state->log, SPA_LOG_TOPIC_DEFAULT, SPA_LOG_LEVEL_TRACE))) return; spa_log_trace(state->log, "event type:%d flags:0x%x", ev->type, ev->flags);
View file
pipewire-0.3.56.tar.gz/spa/plugins/alsa/meson.build -> pipewire-0.3.57.tar.gz/spa/plugins/alsa/meson.build
Changed
@@ -34,13 +34,18 @@ install : true, ) - executable('test-timer', 'test-timer.c' , dependencies : spa_dep, alsa_dep, mathlib, epoll_shim_dep , install : false, ) +executable('test-hw-params', + 'test-hw-params.c' , + dependencies : spa_dep, alsa_dep, mathlib , + install : false, +) + if libudev_dep.found() install_data(alsa_udevrules, install_dir : udevrulesdir,
View file
pipewire-0.3.57.tar.gz/spa/plugins/alsa/test-hw-params.c
Added
@@ -0,0 +1,173 @@ +/* Spa + * + * Copyright © 2022 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <stdio.h> +#include <stdbool.h> +#include <limits.h> +#include <getopt.h> +#include <math.h> + +#include <alsa/asoundlib.h> + +#include <spa/utils/defs.h> + +#define DEFAULT_DEVICE "default" + + +struct state { + const char *device; + snd_output_t *output; + snd_pcm_t *hndl; +}; + +#define CHECK(s,msg,...) { \ + int __err; \ + if ((__err = (s)) < 0) { \ + fprintf(stderr, msg ": %s\n", ##__VA_ARGS__, snd_strerror(__err)); \ + return __err; \ + } \ +} + +static const char *get_class(snd_pcm_class_t c) +{ + switch (c) { + case SND_PCM_CLASS_GENERIC: + return "generic"; + case SND_PCM_CLASS_MULTI: + return "multichannel"; + case SND_PCM_CLASS_MODEM: + return "modem"; + case SND_PCM_CLASS_DIGITIZER: + return "digitizer"; + default: + return "unknown"; + } +} + +static const char *get_subclass(snd_pcm_subclass_t c) +{ + switch (c) { + case SND_PCM_SUBCLASS_GENERIC_MIX: + return "generic-mix"; + case SND_PCM_SUBCLASS_MULTI_MIX: + return "multichannel-mix"; + default: + return "unknown"; + } +} + +static void show_help(const char *name, bool error) +{ + fprintf(error ? stderr : stdout, "%s options\n" + " -h, --help Show this help\n" + " -D, --device device name (default '%s')\n" + " -C, --capture capture mode (default playback)\n", + name, DEFAULT_DEVICE); +} + +int main(int argc, char *argv) +{ + struct state state = { 0, }; + snd_pcm_hw_params_t *hparams; + snd_pcm_info_t *info; + snd_pcm_sync_id_t sync; + snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK; + snd_pcm_chmap_query_t **maps; + int c, i; + static const struct option long_options = { + { "help", no_argument, NULL, 'h' }, + { "device", required_argument, NULL, 'D' }, + { "capture", no_argument, NULL, 'C' }, + { NULL, 0, NULL, 0} + }; + state.device = DEFAULT_DEVICE; + + while ((c = getopt_long(argc, argv, "hD:C", long_options, NULL)) != -1) { + switch (c) { + case 'h': + show_help(argv0, false); + return 0; + case 'D': + state.device = optarg; + break; + case 'C': + stream = SND_PCM_STREAM_CAPTURE; + break; + default: + show_help(argv0, true); + return -1; + } + } + + CHECK(snd_output_stdio_attach(&state.output, stdout, 0), "attach failed"); + + fprintf(stdout, "opening device: '%s'\n", state.device); + + CHECK(snd_pcm_open(&state.hndl, state.device, stream, 0), + "open %s failed", state.device); + + snd_pcm_info_alloca(&info); + snd_pcm_info(state.hndl, info); + + fprintf(stdout, "info:\n"); + fprintf(stdout, " device: %u\n", snd_pcm_info_get_device(info)); + fprintf(stdout, " subdevice: %u\n", snd_pcm_info_get_subdevice(info)); + fprintf(stdout, " stream: %s\n", snd_pcm_stream_name(snd_pcm_info_get_stream(info))); + fprintf(stdout, " card: %d\n", snd_pcm_info_get_card(info)); + fprintf(stdout, " id: '%s'\n", snd_pcm_info_get_id(info)); + fprintf(stdout, " name: '%s'\n", snd_pcm_info_get_name(info)); + fprintf(stdout, " subdevice name: '%s'\n", snd_pcm_info_get_subdevice_name(info)); + fprintf(stdout, " class: %s\n", get_class(snd_pcm_info_get_class(info))); + fprintf(stdout, " subclass: %s\n", get_subclass(snd_pcm_info_get_subclass(info))); + fprintf(stdout, " subdevice count: %u\n", snd_pcm_info_get_subdevices_count(info)); + fprintf(stdout, " subdevice avail: %u\n", snd_pcm_info_get_subdevices_avail(info)); + sync = snd_pcm_info_get_sync(info); + fprintf(stdout, " sync: %08x:%08x:%08x:%08x\n", + sync.id320, sync.id321, sync.id322,sync.id323); + + /* channel maps */ + if ((maps = snd_pcm_query_chmaps(state.hndl)) != NULL) { + fprintf(stdout, "channels:\n"); + + for (i = 0; mapsi; i++) { + snd_pcm_chmap_t* map = &mapsi->map; + char buf2048; + + snd_pcm_chmap_print(map, sizeof(buf), buf); + + fprintf(stdout, " %d: %s\n", map->channels, buf); + } + snd_pcm_free_chmaps(maps); + } + + /* hw params */ + snd_pcm_hw_params_alloca(&hparams); + snd_pcm_hw_params_any(state.hndl, hparams); + + snd_pcm_hw_params_dump(hparams, state.output); + + snd_pcm_close(state.hndl); + + return EXIT_SUCCESS; +}
View file
pipewire-0.3.56.tar.gz/spa/plugins/audioconvert/audioconvert.c -> pipewire-0.3.57.tar.gz/spa/plugins/audioconvert/audioconvert.c
Changed
@@ -909,8 +909,7 @@ } break; case SPA_PROP_rate: - if (spa_pod_get_double(&prop->value, &p->rate) == 0) - changed++; + spa_pod_get_double(&prop->value, &p->rate); break; case SPA_PROP_params: changed += parse_prop_params(this, &prop->value); @@ -1471,26 +1470,29 @@ rate = this->io_position ? this->io_position->clock.rate.denom : DEFAULT_RATE; - if (in->format.info.raw.rate == 0 && in->mode == SPA_PARAM_PORT_CONFIG_MODE_dsp) + /* in DSP mode we always convert to the DSP rate */ + if (in->mode == SPA_PARAM_PORT_CONFIG_MODE_dsp) in->format.info.raw.rate = rate; - if (out->format.info.raw.rate == 0 && out->mode == SPA_PARAM_PORT_CONFIG_MODE_dsp) + if (out->mode == SPA_PARAM_PORT_CONFIG_MODE_dsp) out->format.info.raw.rate = rate; + /* try to passthrough the rates */ if (in->format.info.raw.rate == 0) in->format.info.raw.rate = out->format.info.raw.rate; else if (out->format.info.raw.rate == 0) out->format.info.raw.rate = in->format.info.raw.rate; - if (in->format.info.raw.rate == 0 && out->format.info.raw.rate == 0) - return -EINVAL; - if (in->format.info.raw.channels == 0 && out->format.info.raw.channels == 0) - return -EINVAL; - + /* try to passthrough the channels */ if (in->format.info.raw.channels == 0) in->format.info.raw.channels = out->format.info.raw.channels; else if (out->format.info.raw.channels == 0) out->format.info.raw.channels = in->format.info.raw.channels; + if (in->format.info.raw.rate == 0 || out->format.info.raw.rate == 0) + return -EINVAL; + if (in->format.info.raw.channels == 0 || out->format.info.raw.channels == 0) + return -EINVAL; + if ((res = setup_in_convert(this)) < 0) return res; if ((res = setup_channelmix(this)) < 0) @@ -1722,21 +1724,51 @@ param = spa_format_audio_raw_build(&b, id, &port->format.info.raw); break; case SPA_PARAM_Buffers: + { + uint32_t size; + struct dir *dir; + if (!port->have_format) return -EIO; if (result.index > 0) return 0; + dir = &this->dirdirection; + if (dir->mode == SPA_PARAM_PORT_CONFIG_MODE_dsp) { + /* DSP ports always use the quantum_limit as the buffer + * size. */ + size = this->quantum_limit; + } else { + uint32_t irate, orate; + /* Convert ports are scaled so that they can always + * provide one quantum of data */ + irate = dir->format.info.raw.rate; + + /* collect the other port rate */ + dir = &this->dirSPA_DIRECTION_REVERSE(direction); + if (dir->mode == SPA_PARAM_PORT_CONFIG_MODE_dsp) + orate = this->io_position ? this->io_position->clock.rate.denom : DEFAULT_RATE; + else + orate = dir->format.info.raw.rate; + + /* always keep some extra room for adaptive resampling */ + size = this->quantum_limit * 2; + /* scale the buffer size when we can. */ + if (irate != 0 && orate != 0) + size = size * (irate + orate - 1) / orate; + } + param = spa_pod_builder_add_object(&b, SPA_TYPE_OBJECT_ParamBuffers, id, SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(2, 1, MAX_BUFFERS), SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(port->blocks), SPA_PARAM_BUFFERS_size, SPA_POD_CHOICE_RANGE_Int( - this->quantum_limit * port->stride, + size * port->stride, 16 * port->stride, INT32_MAX), SPA_PARAM_BUFFERS_stride, SPA_POD_Int(port->stride)); break; + } case SPA_PARAM_Meta: switch (result.index) { case 0: @@ -2193,15 +2225,22 @@ return end ? 1 : 0; } +static uint32_t resample_get_in_size(struct impl *this, bool passthrough, uint32_t out_size) +{ + uint32_t match_size = passthrough ? out_size : resample_in_len(&this->resample, out_size); + spa_log_trace_fp(this->log, "%p: current match %u", this, match_size); + return match_size; +} + static uint32_t resample_update_rate_match(struct impl *this, bool passthrough, uint32_t out_size, uint32_t in_queued) { - double rate = this->rate_scale / this->props.rate; uint32_t delay, match_size; if (passthrough) { delay = 0; match_size = out_size; } else { + double rate = this->rate_scale / this->props.rate; if (this->io_rate_match && SPA_FLAG_IS_SET(this->io_rate_match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE)) rate *= this->io_rate_match->rate; @@ -2470,16 +2509,16 @@ /* calculate how many samples we are going to consume. */ if (this->direction == SPA_DIRECTION_INPUT) { - uint32_t n_in; - /* then figure out how much input samples we need to consume */ - n_in = resample_update_rate_match(this, resample_passthrough, n_out, 0); if (!in_avail || this->drained) { + /* no input, ask for more, update rate-match first */ + resample_update_rate_match(this, resample_passthrough, n_out, 0); spa_log_trace_fp(this->log, "%p: no input drained:%d", this, this->drained); - /* no input, ask for more */ res |= this->drained ? SPA_STATUS_DRAINED : SPA_STATUS_NEED_DATA; return res; } - n_samples = SPA_MIN(n_samples, n_in); + /* else figure out how much input samples we need to consume */ + n_samples = SPA_MIN(n_samples, + resample_get_in_size(this, resample_passthrough, n_out)); } else { /* in merge mode we consume one duration of samples */ n_samples = SPA_MIN(n_samples, quant_samples);
View file
pipewire-0.3.56.tar.gz/spa/plugins/audioconvert/channelmix-ops.c -> pipewire-0.3.57.tar.gz/spa/plugins/audioconvert/channelmix-ops.c
Changed
@@ -200,6 +200,7 @@ matrixii= 1.0f; } src_mask = dst_mask = ~0LU; + filter_fc = filter_lfe = true; goto done; } else { spa_log_debug(mix->log, "matching channels"); @@ -398,6 +399,15 @@ spa_log_debug(mix->log, "unassigned upmix %08"PRIx64" lfe:%f", unassigned, mix->lfe_cutoff); + if (unassigned & STEREO) { + if ((src_mask & FRONT) == FRONT) { + spa_log_debug(mix->log, "produce STEREO from FC"); + _MATRIX(FL,FC) += clev; + _MATRIX(FR,FC) += clev; + } else { + spa_log_warn(mix->log, "can't produce STEREO"); + } + } if (unassigned & FRONT) { if ((src_mask & STEREO) == STEREO) { spa_log_debug(mix->log, "produce FC from STEREO"); @@ -431,10 +441,13 @@ spa_log_debug(mix->log, "produce SIDE from STEREO"); _MATRIX(SL,FL) += slev; _MATRIX(SR,FR) += slev; - } else if ((src_mask & FRONT) == FRONT) { + } else if ((src_mask & FRONT) == FRONT && + mix->upmix == CHANNELMIX_UPMIX_SIMPLE) { spa_log_debug(mix->log, "produce SIDE from FC"); _MATRIX(SL,FC) += clev; _MATRIX(SR,FC) += clev; + } else { + spa_log_debug(mix->log, "won't produce SIDE"); } } if (unassigned & REAR) { @@ -446,10 +459,13 @@ spa_log_debug(mix->log, "produce REAR from STEREO"); _MATRIX(RL,FL) += slev; _MATRIX(RR,FR) += slev; - } else if ((src_mask & FRONT) == FRONT) { + } else if ((src_mask & FRONT) == FRONT && + mix->upmix == CHANNELMIX_UPMIX_SIMPLE) { spa_log_debug(mix->log, "produce REAR from FC"); _MATRIX(RL,FC) += clev; _MATRIX(RR,FC) += clev; + } else { + spa_log_debug(mix->log, "won't produce SIDE"); } }
View file
pipewire-0.3.56.tar.gz/spa/plugins/audioconvert/fmt-ops-avx2.c -> pipewire-0.3.57.tar.gz/spa/plugins/audioconvert/fmt-ops-avx2.c
Changed
@@ -362,7 +362,7 @@ float *d0 = dst0, *d1 = dst1, *d2 = dst2, *d3 = dst3; uint32_t n, unrolled; __m256i in4, t4; - __m256 out4, factor = _mm256_set1_ps(1.0f / S32_SCALE); + __m256 out4, factor = _mm256_set1_ps(1.0f / S24_SCALE); __m256i mask1 = _mm256_setr_epi64x(0*n_channels, 0*n_channels+2, 4*n_channels, 4*n_channels+2); __m256i mask2 = _mm256_setr_epi64x(1*n_channels, 1*n_channels+2, 5*n_channels, 5*n_channels+2); __m256i mask3 = _mm256_setr_epi64x(2*n_channels, 2*n_channels+2, 6*n_channels, 6*n_channels+2); @@ -391,6 +391,11 @@ in2 = _mm256_unpacklo_epi64(t1, t3); /* c0 c1 c2 c3 c4 c5 c6 c7 */ in3 = _mm256_unpackhi_epi64(t1, t3); /* d0 d1 d2 d3 d4 d5 d6 d7 */ + in0 = _mm256_srai_epi32(in0, 8); + in1 = _mm256_srai_epi32(in1, 8); + in2 = _mm256_srai_epi32(in2, 8); + in3 = _mm256_srai_epi32(in3, 8); + out0 = _mm256_cvtepi32_ps(in0); out1 = _mm256_cvtepi32_ps(in1); out2 = _mm256_cvtepi32_ps(in2); @@ -409,11 +414,11 @@ s += 8*n_channels; } for(; n < n_samples; n++) { - __m128 out4, factor = _mm_set1_ps(1.0f / S32_SCALE); - out0 = _mm_cvtsi32_ss(factor, s0); - out1 = _mm_cvtsi32_ss(factor, s1); - out2 = _mm_cvtsi32_ss(factor, s2); - out3 = _mm_cvtsi32_ss(factor, s3); + __m128 out4, factor = _mm_set1_ps(1.0f / S24_SCALE); + out0 = _mm_cvtsi32_ss(factor, s0 >> 8); + out1 = _mm_cvtsi32_ss(factor, s1 >> 8); + out2 = _mm_cvtsi32_ss(factor, s2 >> 8); + out3 = _mm_cvtsi32_ss(factor, s3 >> 8); out0 = _mm_mul_ss(out0, factor); out1 = _mm_mul_ss(out1, factor); out2 = _mm_mul_ss(out2, factor); @@ -434,7 +439,7 @@ float *d0 = dst0, *d1 = dst1; uint32_t n, unrolled; __m256i in4, t4; - __m256 out4, factor = _mm256_set1_ps(1.0f / S32_SCALE); + __m256 out4, factor = _mm256_set1_ps(1.0f / S24_SCALE); __m256i perm = _mm256_setr_epi32(0, 2, 4, 6, 1, 3, 5, 7); __m256i mask1 = _mm256_setr_epi64x(0*n_channels, 1*n_channels, 2*n_channels, 3*n_channels); __m256i mask2 = _mm256_setr_epi64x(4*n_channels, 5*n_channels, 6*n_channels, 7*n_channels); @@ -455,6 +460,9 @@ in0 = _mm256_permute2x128_si256(t0, t1, 0 | (2 << 4)); in1 = _mm256_permute2x128_si256(t0, t1, 1 | (3 << 4)); + in0 = _mm256_srai_epi32(in0, 8); + in1 = _mm256_srai_epi32(in1, 8); + out0 = _mm256_cvtepi32_ps(in0); out1 = _mm256_cvtepi32_ps(in1); @@ -467,9 +475,9 @@ s += 8*n_channels; } for(; n < n_samples; n++) { - __m128 out2, factor = _mm_set1_ps(1.0f / S32_SCALE); - out0 = _mm_cvtsi32_ss(factor, s0); - out1 = _mm_cvtsi32_ss(factor, s1); + __m128 out2, factor = _mm_set1_ps(1.0f / S24_SCALE); + out0 = _mm_cvtsi32_ss(factor, s0 >> 8); + out1 = _mm_cvtsi32_ss(factor, s1 >> 8); out0 = _mm_mul_ss(out0, factor); out1 = _mm_mul_ss(out1, factor); _mm_store_ss(&d0n, out0); @@ -486,7 +494,7 @@ float *d0 = dst0; uint32_t n, unrolled; __m256i in2; - __m256 out2, factor = _mm256_set1_ps(1.0f / S32_SCALE); + __m256 out2, factor = _mm256_set1_ps(1.0f / S24_SCALE); __m256i mask1 = _mm256_setr_epi64x(0*n_channels, 1*n_channels, 2*n_channels, 3*n_channels); __m256i mask2 = _mm256_setr_epi64x(4*n_channels, 5*n_channels, 6*n_channels, 7*n_channels); @@ -503,6 +511,9 @@ _mm256_i64gather_epi32(&s 8*n_channels, mask1, 4), _mm256_i64gather_epi32(&s 8*n_channels, mask2, 4)); + in0 = _mm256_srai_epi32(in0, 8); + in1 = _mm256_srai_epi32(in1, 8); + out0 = _mm256_cvtepi32_ps(in0); out1 = _mm256_cvtepi32_ps(in1); @@ -515,8 +526,8 @@ s += 16*n_channels; } for(; n < n_samples; n++) { - __m128 out, factor = _mm_set1_ps(1.0f / S32_SCALE); - out = _mm_cvtsi32_ss(factor, s0); + __m128 out, factor = _mm_set1_ps(1.0f / S24_SCALE); + out = _mm_cvtsi32_ss(factor, s0 >> 8); out = _mm_mul_ss(out, factor); _mm_store_ss(&d0n, out); s += n_channels;
View file
pipewire-0.3.56.tar.gz/spa/plugins/audioconvert/fmt-ops-neon.c -> pipewire-0.3.57.tar.gz/spa/plugins/audioconvert/fmt-ops-neon.c
Changed
@@ -26,6 +26,8 @@ #include <stdio.h> #include <math.h> +#include <arm_neon.h> + #include "fmt-ops.h" void @@ -289,16 +291,19 @@ #ifdef __aarch64__ asm volatile( + " dup v2.4s, %wscale\n" " cmp %n_samples, #0\n" " beq 2f\n" "1:" " ld1 { v0.4s }, %s0, #16\n" " ld1 { v1.4s }, %s1, #16\n" " subs %n_samples, %n_samples, #4\n" - " fcvtzs v0.4s, v0.4s, #31\n" - " fcvtzs v1.4s, v1.4s, #31\n" - " sqrshrn v0.4h, v0.4s, #16\n" - " sqrshrn v1.4h, v1.4s, #16\n" + " sqadd v0.4s, v0.4s, v2.4s\n" + " sqadd v1.4s, v1.4s, v2.4s\n" + " fcvtns v0.4s, v0.4s\n" + " fcvtns v1.4s, v1.4s\n" + " sqxtn v0.4h, v0.4s\n" + " sqxtn v1.4h, v1.4s\n" " st2 { v0.h, v1.h }0, %d, %stride\n" " st2 { v0.h, v1.h }1, %d, %stride\n" " st2 { v0.h, v1.h }2, %d, %stride\n" @@ -311,29 +316,42 @@ " ld1 { v0.s }0, %s0, #4\n" " ld1 { v2.s }0, %s1, #4\n" " subs %remainder, %remainder, #1\n" - " fcvtzs v0.4s, v0.4s, #31\n" - " fcvtzs v1.4s, v1.4s, #31\n" - " sqrshrn v0.4h, v0.4s, #16\n" - " sqrshrn v1.4h, v1.4s, #16\n" + " sqadd v0.4s, v0.4s, v2.4s\n" + " sqadd v1.4s, v1.4s, v2.4s\n" + " fcvtns v0.4s, v0.4s\n" + " fcvtns v1.4s, v1.4s\n" + " sqxtn v0.4h, v0.4s\n" + " sqxtn v1.4h, v1.4s\n" " st2 { v0.h, v1.h }0, %d, %stride\n" " bne 3b\n" "4:" : d "+r" (d), s0 "+r" (s0), s1 "+r" (s1), n_samples "+r" (n_samples), remainder "+r" (remainder) - : stride "r" (stride) + : stride "r" (stride), + scale "r" (15 << 23) : "cc", "v0", "v1"); #else + float32x4_t pos = vdupq_n_f32(0.4999999f / S16_SCALE); + float32x4_t neg = vdupq_n_f32(-0.4999999f / S16_SCALE); + asm volatile( + " veor q2, q2, q2\n" " cmp %n_samples, #0\n" " beq 2f\n" "1:" " vld1.32 { q0 }, %s0!\n" " vld1.32 { q1 }, %s1!\n" " subs %n_samples, %n_samples, #4\n" - " vcvt.s32.f32 q0, q0, #31\n" - " vcvt.s32.f32 q1, q1, #31\n" - " vqrshrn.s32 d0, q0, #16\n" - " vqrshrn.s32 d1, q1, #16\n" + " vcgt.f32 q3, q0, q2\n" + " vcgt.f32 q4, q0, q2\n" + " vbsl q3, %qpos, %qneg\n" + " vbsl q4, %qpos, %qneg\n" + " vadd.f32 q0, q0, q3\n" + " vadd.f32 q1, q1, q4\n" + " vcvt.s32.f32 q0, q0, #15\n" + " vcvt.s32.f32 q1, q1, #15\n" + " vqmovn.s32 d0, q0\n" + " vqmovn.s32 d1, q1\n" " vst2.16 { d00, d10 }, %d, %stride\n" " vst2.16 { d01, d11 }, %d, %stride\n" " vst2.16 { d02, d12 }, %d, %stride\n" @@ -346,17 +364,25 @@ " vld1.32 { d00 }, %s0!\n" " vld1.32 { d20 }, %s1!\n" " subs %remainder, %remainder, #1\n" - " vcvt.s32.f32 q0, q0, #31\n" - " vcvt.s32.f32 q1, q1, #31\n" - " vqrshrn.s32 d0, q0, #16\n" - " vqrshrn.s32 d1, q1, #16\n" + " vcgt.f32 q3, q0, q2\n" + " vcgt.f32 q4, q0, q2\n" + " vbsl q3, %qpos, %qneg\n" + " vbsl q4, %qpos, %qneg\n" + " vadd.f32 q0, q0, q3\n" + " vadd.f32 q1, q1, q4\n" + " vcvt.s32.f32 q0, q0, #15\n" + " vcvt.s32.f32 q1, q1, #15\n" + " vqmovn.s32 d0, q0\n" + " vqmovn.s32 d1, q1\n" " vst2.16 { d00, d10 }, %d, %stride\n" " bne 3b\n" "4:" : d "+r" (d), s0 "+r" (s0), s1 "+r" (s1), n_samples "+r" (n_samples), remainder "+r" (remainder) - : stride "r" (stride) - : "cc", "q0", "q1"); + : stride "r" (stride), + pos"w"(pos), + neg"w"(neg) + : "cc", "q0", "q1", "q2", "q3", "q4"); #endif } @@ -372,13 +398,15 @@ #ifdef __aarch64__ asm volatile( + " dup v2.4s, %wscale\n" " cmp %n_samples, #0\n" " beq 2f\n" "1:" " ld1 { v0.4s }, %s, #16\n" " subs %n_samples, %n_samples, #4\n" - " fcvtzs v0.4s, v0.4s, #31\n" - " sqrshrn v0.4h, v0.4s, #16\n" + " sqadd v0.4s, v0.4s, v2.4s\n" + " fcvtns v0.4s, v0.4s\n" + " sqxtn v0.4h, v0.4s\n" " st1 { v0.h }0, %d, %stride\n" " st1 { v0.h }1, %d, %stride\n" " st1 { v0.h }2, %d, %stride\n" @@ -390,24 +418,33 @@ "3:" " ld1 { v0.s }0, %s, #4\n" " subs %remainder, %remainder, #1\n" - " fcvtzs v0.4s, v0.4s, #31\n" - " sqrshrn v0.4h, v0.4s, #16\n" + " sqadd v0.4s, v0.4s, v2.4s\n" + " fcvtns v0.4s, v0.4s\n" + " sqxtn v0.4h, v0.4s\n" " st1 { v0.h }0, %d, %stride\n" " bne 3b\n" "4:" : d "+r" (d), s "+r" (s), n_samples "+r" (n_samples), remainder "+r" (remainder) - : stride "r" (stride) + : stride "r" (stride), + scale "r" (15 << 23) : "cc", "v0"); #else + float32x4_t pos = vdupq_n_f32(0.4999999f / S16_SCALE); + float32x4_t neg = vdupq_n_f32(-0.4999999f / S16_SCALE); + asm volatile( + " veor q1, q1, q1\n" " cmp %n_samples, #0\n" " beq 2f\n" "1:" " vld1.32 { q0 }, %s!\n" " subs %n_samples, %n_samples, #4\n" - " vcvt.s32.f32 q0, q0, #31\n" - " vqrshrn.s32 d0, q0, #16\n" + " vcgt.f32 q2, q0, q1\n" + " vbsl q2, %qpos, %qneg\n" + " vadd.f32 q0, q0, q2\n" + " vcvt.s32.f32 q0, q0, #15\n" + " vqmovn.s32 d0, q0\n" " vst1.16 { d00 }, %d, %stride\n" " vst1.16 { d01 }, %d, %stride\n" " vst1.16 { d02 }, %d, %stride\n" @@ -419,15 +456,20 @@ "3:" " vld1.32 { d00 }, %s!\n" " subs %remainder, %remainder, #1\n" - " vcvt.s32.f32 q0, q0, #31\n" - " vqrshrn.s32 d0, q0, #16\n" + " vcgt.f32 q2, q0, q1\n" + " vbsl q2, %qpos, %qneg\n" + " vadd.f32 q0, q0, q2\n" + " vcvt.s32.f32 q0, q0, #15\n" + " vqmovn.s32 d0, q0\n" " vst1.16 { d00 }, %d, %stride\n" " bne 3b\n" "4:" : d "+r" (d), s "+r" (s), n_samples "+r" (n_samples), remainder "+r" (remainder) - : stride "r" (stride) - : "cc", "q0"); + : stride "r" (stride), + pos"w"(pos), + neg"w"(neg) + : "cc", "q0", "q1", "q2"); #endif }
View file
pipewire-0.3.56.tar.gz/spa/plugins/audioconvert/fmt-ops.h -> pipewire-0.3.57.tar.gz/spa/plugins/audioconvert/fmt-ops.h
Changed
@@ -40,7 +40,7 @@ #define ITOF(type,v,scale,offs) \ (((type)(v)) * (1.0f / (scale)) - (offs)) #define FTOI(type,v,scale,offs,noise,min,max) \ - (type)f32_round(SPA_CLAMP((v) * (scale) + (offs) + (noise), min, max)) + (type)f32_round(SPA_CLAMPF((v) * (scale) + (offs) + (noise), min, max)) #define FMT_OPS_MAX_ALIGN 32 @@ -119,9 +119,8 @@ #define F32_TO_S24_32S(v) bswap_32(F32_TO_S24_32(v)) #define F32_TO_S24_32S_D(v,d) bswap_32(F32_TO_S24_32_D(v,d)) -#define S32_MIN -2147483648 -#define S32_MAX 2147483647 -#define S32_SCALE 2147483648.f +#define S32_MIN (S24_MIN * 256) +#define S32_MAX (S24_MAX * 256) #define S32_TO_F32(v) ITOF(int32_t, (v) >> 8, S24_SCALE, 0.0f) #define S32S_TO_F32(v) S32_TO_F32(bswap_32(v)) #define F32_TO_S32(v) (F32_TO_S24_32(v) << 8)
View file
pipewire-0.3.56.tar.gz/spa/plugins/audioconvert/resample-native.c -> pipewire-0.3.57.tar.gz/spa/plugins/audioconvert/resample-native.c
Changed
@@ -68,14 +68,15 @@ } static inline double window_cosh(double x, double n_taps) { - double R = 190.0, r; - double A = (-325.1E-6 * R + 0.1677) * R - 3.149; + double r; + double A = 16.97789; double x2; x = 2.0 * x / n_taps; x2 = x * x; if (x2 >= 1.0) return 0.0; - r = cosh(A * sqrt(1 - x2)) / cosh(A); + /* doi:10.1109/RME.2008.4595727 with tweak */ + r = (exp(A * sqrt(1 - x2)) - 1) / (exp(A) - 1); return r; }
View file
pipewire-0.3.56.tar.gz/spa/plugins/audioconvert/test-fmt-ops.c -> pipewire-0.3.57.tar.gz/spa/plugins/audioconvert/test-fmt-ops.c
Changed
@@ -242,6 +242,12 @@ false, true, conv_f32d_to_s16_avx2); } #endif +#if defined(HAVE_NEON) + if (cpu_flags & SPA_CPU_FLAG_NEON) { + run_test("test_f32d_s16_neon", in, sizeof(in0), out, sizeof(out0), SPA_N_ELEMENTS(out), + false, true, conv_f32d_to_s16_neon); + } +#endif } static void test_s16_f32(void) @@ -269,6 +275,12 @@ true, false, conv_s16_to_f32d_avx2); } #endif +#if defined(HAVE_NEON) + if (cpu_flags & SPA_CPU_FLAG_NEON) { + run_test("test_s16_f32d_neon", in, sizeof(in0), out, sizeof(out0), SPA_N_ELEMENTS(out), + true, false, conv_s16_to_f32d_neon); + } +#endif } static void test_f32_u32(void)
View file
pipewire-0.3.56.tar.gz/spa/plugins/audioconvert/test-source.c -> pipewire-0.3.57.tar.gz/spa/plugins/audioconvert/test-source.c
Changed
@@ -749,9 +749,8 @@ spa_return_val_if_fail(this != NULL, -EINVAL); port = GET_OUT_PORT(this, 0); - - io = port->io; - spa_return_val_if_fail(io != NULL, -EIO); + if ((io = port->io) == NULL) + return -EIO; spa_log_trace_fp(this->log, NAME " %p: status %d", this, io->status);
View file
pipewire-0.3.56.tar.gz/spa/plugins/audiomixer/audiomixer.c -> pipewire-0.3.57.tar.gz/spa/plugins/audiomixer/audiomixer.c
Changed
@@ -730,8 +730,8 @@ spa_return_val_if_fail(this != NULL, -EINVAL); outport = GET_OUT_PORT(this, 0); - outio = outport->io; - spa_return_val_if_fail(outio != NULL, -EIO); + if ((outio = outport->io) == NULL) + return -EIO; spa_log_trace_fp(this->log, "%p: status %p %d %d", this, outio, outio->status, outio->buffer_id);
View file
pipewire-0.3.56.tar.gz/spa/plugins/audiomixer/mixer-dsp.c -> pipewire-0.3.57.tar.gz/spa/plugins/audiomixer/mixer-dsp.c
Changed
@@ -675,8 +675,8 @@ spa_return_val_if_fail(this != NULL, -EINVAL); outport = GET_OUT_PORT(this, 0); - outio = outport->io; - spa_return_val_if_fail(outio != NULL, -EIO); + if ((outio = outport->io) == NULL) + return -EIO; spa_log_trace_fp(this->log, "%p: status %p %d %d", this, outio, outio->status, outio->buffer_id);
View file
pipewire-0.3.56.tar.gz/spa/plugins/audiotestsrc/audiotestsrc.c -> pipewire-0.3.57.tar.gz/spa/plugins/audiotestsrc/audiotestsrc.c
Changed
@@ -931,7 +931,8 @@ port = &this->port; io = port->io; - spa_return_val_if_fail(io != NULL, -EIO); + if ((io = port->io) == NULL) + return -EIO; if (port->io_control) process_control(this, &port->io_control->sequence);
View file
pipewire-0.3.56.tar.gz/spa/plugins/avb/avb-pcm-sink.c -> pipewire-0.3.57.tar.gz/spa/plugins/avb/avb-pcm-sink.c
Changed
@@ -699,40 +699,39 @@ { struct state *this = object; struct port *port; - struct spa_io_buffers *input; + struct spa_io_buffers *io; spa_return_val_if_fail(this != NULL, -EINVAL); port = GET_PORT(this, SPA_DIRECTION_INPUT, 0); + if ((io = port->io) == NULL) + return -EIO; - input = port->io; - spa_return_val_if_fail(input != NULL, -EIO); - - spa_log_trace_fp(this->log, "%p: process %d %d/%d", this, input->status, - input->buffer_id, port->n_buffers); + spa_log_trace_fp(this->log, "%p: process %d %d/%d", this, io->status, + io->buffer_id, port->n_buffers); if (this->position && this->position->clock.flags & SPA_IO_CLOCK_FLAG_FREEWHEEL) { - input->status = SPA_STATUS_NEED_DATA; + io->status = SPA_STATUS_NEED_DATA; return SPA_STATUS_HAVE_DATA; } - if (input->status == SPA_STATUS_HAVE_DATA && - input->buffer_id < port->n_buffers) { - struct buffer *b = &port->buffersinput->buffer_id; + if (io->status == SPA_STATUS_HAVE_DATA && + io->buffer_id < port->n_buffers) { + struct buffer *b = &port->buffersio->buffer_id; if (!SPA_FLAG_IS_SET(b->flags, BUFFER_FLAG_OUT)) { spa_log_warn(this->log, "%p: buffer %u in use", - this, input->buffer_id); - input->status = -EINVAL; + this, io->buffer_id); + io->status = -EINVAL; return -EINVAL; } - spa_log_trace_fp(this->log, "%p: queue buffer %u", this, input->buffer_id); + spa_log_trace_fp(this->log, "%p: queue buffer %u", this, io->buffer_id); spa_list_append(&port->ready, &b->link); SPA_FLAG_CLEAR(b->flags, BUFFER_FLAG_OUT); - input->buffer_id = SPA_ID_INVALID; + io->buffer_id = SPA_ID_INVALID; spa_avb_write(this); - input->status = SPA_STATUS_OK; + io->status = SPA_STATUS_OK; } return SPA_STATUS_HAVE_DATA; }
View file
pipewire-0.3.56.tar.gz/spa/plugins/avb/avb-pcm-source.c -> pipewire-0.3.57.tar.gz/spa/plugins/avb/avb-pcm-source.c
Changed
@@ -705,9 +705,8 @@ spa_return_val_if_fail(this != NULL, -EINVAL); port = GET_PORT(this, SPA_DIRECTION_OUTPUT, 0); - - io = port->io; - spa_return_val_if_fail(io != NULL, -EIO); + if ((io = port->io) == NULL) + return -EIO; spa_log_trace_fp(this->log, "%p: process %d %d/%d %d", this, io->status, io->buffer_id, port->n_buffers, this->following);
View file
pipewire-0.3.56.tar.gz/spa/plugins/avb/avbtp/packets.h -> pipewire-0.3.57.tar.gz/spa/plugins/avb/avbtp/packets.h
Changed
@@ -116,7 +116,7 @@ unsigned gv:1; unsigned tv:1; - uint8_t seq_number; + uint8_t seq_num; unsigned _r2:7; unsigned tu:1;
View file
pipewire-0.3.57.tar.gz/spa/plugins/bluez5/README-OPUS-A2DP.md
Added
@@ -0,0 +1,321 @@ +--- +title: OPUS-A2DP-0.5 specification +author: Pauli Virtanen <pav@iki.fi> +date: Jun 4, 2022 +--- + +# OPUS-A2DP-0.5 specification + +DRAFT + +In this file, we specify how to use Opus as an A2DP vendor codec. We +will call this "OPUS-A2DP-0.5". There is no previous public +specification for using Opus as an A2DP vendor codec (to my +knowledge), which is why we need this one. + +_TOC_ + +# A2DP Codec Capabilities + +The A2DP capability structure is as follows. + +Integer fields and multi-byte bitfields are laid out in **little +endian** order. All integer fields are unsigned. + +Each entry may have different meaning when present as a capability. +Below, we indicate this by abbreviations CAP/SNK for sink capability, +CAP/SRC for source capability, CAP for capability as either, and SEL +for the selected value by SRC. + +Bits in fields marked RFA (Reserved For Additions) shall be set to +zero. + +The capability and configuration structure is as follows: + +| Octet | Bits | Meaning | +|-------|------|-----------------------------------------------| +| 0-5 | 0-7 | Vendor ID Part | +| 6-7 | 0-7 | Channel Configuration | +| 8-11 | 0-7 | Audio Location Configuration | +| 12-14 | 0-7 | Limits Configuration | +| 15-16 | 0-7 | Return Direction Channel Configuration | +| 17-20 | 0-7 | Return Direction Audio Location Configuration | +| 21-23 | 0-7 | Return Direction Limits Configuration | + +See `a2dp-codec-caps.h` for definition as C structs. + +## Vendor ID Part + +The fixed value + +| Octet | Bits | Meaning | +|-------|------|-------------------------------| +| 0-3 | 0-7 | A2DP Vendor ID (0x05F1) | +| 4-5 | 0-7 | A2DP Vendor Codec ID (0x1005) | + +The Vendor ID is that of the Linux Foundation, and we are using it +here unofficially. + +## Channel Configuration + +The channel configuration consists of the channel count and a bitfield +indicating which of them are encoded in coupled streams. + +| Octet | Bits | Meaning | +|-------|------|------------------------------------------------------------| +| 6 | 0-7 | Channel Count. CAP: maximum number supported. SEL: actual. | +| 7 | 0-7 | Coupled Stream Count. CAP: 0. SEL: actual. | + +The Channel Count indicates the number of logical channels encoded in +the data stream. + +The Coupled Stream Count indicates the number of streams that encode a +coupled (left & right) channel pair. The count shall satisfy +`(Channel Count) >= 2*(Coupled Stream Count)`. +The Stream Count is `(Channel Count) - (Coupled Stream Count)`. + +Streams and Coupled Streams have the same meaning as in Sec. 5.1.1 of +Opus Multistream RFC7845. + +The logical Channels are identified by a Channel Index *j* such that `0 <= j +< (Channel Count)`. The channels `0 <= j < 2*(Coupled Stream Count)` +are encoded in the *k*-th stream of the payload, where `k = floor(j/2)` and +`j mod 2` determines which of the two channels of the stream the logical +channel is. The channels `2*(Coupled Stream Count) <= j < (Channel Count)` +are encoded in the *k*-th stream of the payload, where `k = j - (Coupled Stream Count)`. +The prescription here is identical to RFC7845 with channel mapping +`mappingj = j`. + +The semantic meaning for each channel is determined by their Audio +Location. + +## Audio Location Configuration + +The channel audio location specification is similar to the location +bitfield of the `Audio_Channel_Allocation` LTV structure in Bluetooth +SIG Assigned Numbers, Generic Audio used in the LE Audio. + +| Octet | Bits | Meaning | +|-------|------|------------------------------------------------------| +| 8-11 | 0-7 | Audio Location bitfield. CAP: available. SEL: actual | + +The values specified in CAP are informative, and SEL may contain bits +that were not set in CAP. SNK shall handle unsupported audio +locations. It may do this for example by ignoring unsupported channels +or via suitable up/downmixing. Hence, SRC may transmit channels with +audio locations that are not marked supported by SNK. The maximum +Channel Count however shall not be exceeded. + +The audio location bitfield values defined in Assigned Numbers, +Generic Audio are: + +| Channel Order | Bitmask | Audio Location | +|---------------|------------|-------------------------| +| 0 | 0x00000001 | Front Left | +| 1 | 0x00000002 | Front Right | +| 2 | 0x00000400 | Side Left | +| 3 | 0x00000800 | Side Right | +| 4 | 0x00000010 | Back Left | +| 5 | 0x00000020 | Back Right | +| 6 | 0x00000040 | Front Left of Center | +| 7 | 0x00000080 | Front Right of Center | +| 8 | 0x00001000 | Top Front Left | +| 9 | 0x00002000 | Top Front Right | +| 10 | 0x00040000 | Top Side Left | +| 11 | 0x00080000 | Top Side Right | +| 12 | 0x00010000 | Top Back Left | +| 13 | 0x00020000 | Top Back Right | +| 14 | 0x00400000 | Bottom Front Left | +| 15 | 0x00800000 | Bottom Front Right | +| 16 | 0x01000000 | Front Left Wide | +| 17 | 0x02000000 | Front Right Wide | +| 18 | 0x04000000 | Left Surround | +| 19 | 0x08000000 | Right Surround | +| 20 | 0x00000004 | Front Center | +| 21 | 0x00000100 | Back Center | +| 22 | 0x00004000 | Top Front Center | +| 23 | 0x00008000 | Top Center | +| 24 | 0x00100000 | Top Back Center | +| 25 | 0x00200000 | Bottom Front Center | +| 26 | 0x00000008 | Low Frequency Effects 1 | +| 27 | 0x00000200 | Low Frequency Effects 2 | +| 28 | 0x10000000 | RFA | +| 29 | 0x20000000 | RFA | +| 30 | 0x40000000 | RFA | +| 31 | 0x80000000 | RFA | + +In addition, we define a specific Channel Order for each. The bits +set in the bitfield define audio locations for the streams present in the +payload. The set bit with the smallest Channel Order value defines the +audio location for the Channel Index *j=0*, the bit with the next +lowest Channel Order value defines the audio location for the Channel +Index *j=1*, and so forth. + +When the Channel Count is larger than the number of bits set in the +Audio Location bitfield, the audio locations of the remaining channels +are unspecified. Implementations may handle them as appropriate for +their use case, considering them as AUX0-AUXN, or in the case of +Channel Count = 1, as the single mono audio channel. + +When the Channel Count is smaller than the number of bits set in the +Audio Location bitfield, the audio locations for the channels are +assigned as above, and remaining excess bits shall be ignored. + +The channel ordering defined here is compatible with the internal +stream ordering in the reference Opus Multistream surround encoder +Mapping Family 0 and 1 output. This allows making use of its surround +masking and LFE handling capabilities. The stream ordering of the +reference Opus surround encoder, although being unchanged since its +addition in 2013, is an internal detail of the +encoder. Implementations using the surround encoder shall check that +the mapping table used by the encoder corresponds to the above channel +ordering. + +For reference, we list the Audio Location bitfield values +corresponding to the different channel counts in Opus Mapping Family 0 +and 1 surround encoder output, and the expected mapping table: + +| Mapping Family | Channel Count | Audio Location Value | Stream Ordering | Mapping Table | +|----------------|---------------|----------------------|---------------------------------|--------------------------| +| 0 | 1 | 0x00000000 | mono | {0} | +| 0 | 2 | 0x00000003 | FL, FR | {0, 1} | +| 1 | 1 | 0x00000000 | mono | {0} | +| 1 | 2 | 0x00000003 | FL, FR | {0, 1} | +| 1 | 3 | 0x00000007 | FL, FR, FC | {0, 2, 1} | +| 1 | 4 | 0x00000033 | FL, FR, BL, BR | {0, 1, 2, 3} | +| 1 | 5 | 0x00000037 | FL, FR, BL, BR, FC | {0, 4, 1, 2, 3} | +| 1 | 6 | 0x0000003f | FL, FR, BL, BR, FC, LFE | {0, 4, 1, 2, 3, 5} | +| 1 | 7 | 0x00000d0f | FL, FR, SL, SR, FC, BC, LFE | {0, 4, 1, 2, 3, 5, 6} | +| 1 | 8 | 0x00000c3f | FL, FR, SL, SR, BL, BR, FC, LFE | {0, 6, 1, 2, 3, 4, 5, 7} | + +The Mapping Table in the table indicates the mapping table selected by +`opus_multistream_surround_encoder_create` (Opus 1.3.1). If the +encoder outputs a different mapping table in a future Opus encoder +release, the channel ordering will be incorrect, and the surround +encoder can not be used. We expect that the probability of the Opus +encoder authors making such changes is negligible. + +## Limits Configuration + +The limits for allowed frame durations and maximum bitrate can also be +configured. + +| Octet | Bits | Meaning | +|-------|------|-----------------------------------------------------| +| 16 | 0 | Frame duration 2.5ms. CAP: supported, SEL: selected | +| 16 | 1 | Frame duration 5ms. CAP: supported, SEL: selected | +| 16 | 2 | Frame duration 10ms. CAP: supported, SEL: selected | +| 16 | 3 | Frame duration 20ms. CAP: supported, SEL: selected | +| 16 | 4 | Frame duration 40ms. CAP: supported, SEL: selected | +| 16 | 5-7 | RFA | + +| Octet | Bits | Meaning | +|-------|------|------------------------------------------------| +| 17-18 | 0-7 | Maximum bitrate. CAP: supported, SEL: selected | + +The maximum bitrate is given in units of 1024 bits per second. + +The maximum bitrate field in CAP may contain value 0 to indicate +everything is supported. + +## Bidirectional Audio Configuration + +Bidirectional audio may be supported. Its Channel Configuration, Audio +Location Configuration, and Limits Configuration have identical form +to the forward direction, and represented by exactly similar +structures. + +Namely: + +| Octet | Bits | Meaning | +|-------|------|----------------------------------------------------| +| 19-20 | 0-7 | Channel Configuration fields, for return direction | +| 21-28 | 0-7 | Audio Location fields, for return direction | +| 29-31 | 0-7 | Limits Configuration fields, for return direction | + +If no return channel is supported or selected, the number of channels +is set to 0 in CAP or SEL. + + +# Packet Structure + +Each packet consists of an RTP header, an RTP payload header, and a +payload containing Opus Multistream data. + +| Octet | Bits | Meaning | +|-------|------|--------------------------| +| 0-11 | 0-7 | RTP header | +| 12 | 0-7 | RTP payload header | +| 13-N | 0-7 | Opus Multistream payload | + +For each Bluetooth packet, the payload shall contain exactly one Opus +Multistream packet, or a fragment of one. The Opus Multistream packet +may be fragmented to several consecutive Bluetooth packets. + +The format of the Multistream data is the same as in the audio packets +of RFC7845, or, as produced/consumed by the Opus Multistream API. + +(Note that we DO NOT follow RFC7587, as we want fragmentation and +multichannel support.) + +## RTP Header + +See RFC3550. + +The RTP payload type is pt=96 (dynamic). + +## RTP Payload Header + +The RTP payload header is used to indicate if and how the Opus +Multistream packet is fragmented across several consecutive Bluetooth +packets. + +| Octet | Bits | Meaning +|--------|------|-------------------------------------------------------- +| 0 | 0-3 | Frame Count +| 4 | 4 | RFA +| 4 | 5 | Is Last Fragment +| 4 | 6 | Is First Fragment +| 4 | 7 | Is Fragmented + +In each packet, Frame Count indicates how many Bluetooth packets are +still to be received (including the present packet) before the Opus +Multistream packet is complete. + +The Is Fragment flag indicates whether the present packet contains +fragmented payload. + +The Is Last Fragment flag indicates whether the present packet is the +last part of fragmented payload. + +The Is First Fragment flag indicates whether the present packet is the +first part of fragmented payload. + +In non-fragmented packets, Frame Count shall be (1), and the other bits +in the header zero. + +## Opus Payload + +The Opus payload is a single Opus Multistream packet, or its fragment. + +In case of fragmentation, as indicated by the RTP payload header, +concatenating the payloads of the fragment Bluetooth packets shall +yield the total Opus Multistream packet. + +The SRC should choose encoder parameters such that Bluetooth bandwidth +limitations are not exceeded. + +The SRC may include FEC data. The SNK may enable forward error +correction instead of PLC. + + +# References + +1. IETF RFC 3550: RFC3550 +2. IETF RFC 7587: RFC7587 +3. IETF RFC 7845: RFC7845 + +RFC3550: https://datatracker.ietf.org/doc/html/rfc3550 +RFC7587: https://datatracker.ietf.org/doc/html/rfc7587 +RFC7845: https://datatracker.ietf.org/doc/html/rfc7845 +Assigned Numbers, Generic Audio: https://www.bluetooth.com/specifications/assigned-numbers/
View file
pipewire-0.3.56.tar.gz/spa/plugins/bluez5/a2dp-codec-aac.c -> pipewire-0.3.57.tar.gz/spa/plugins/bluez5/a2dp-codec-aac.c
Changed
@@ -31,10 +31,16 @@ #include <spa/utils/dict.h> #include <fdk-aac/aacenc_lib.h> +#include <fdk-aac/aacdecoder_lib.h> #include "rtp.h" #include "a2dp-codecs.h" +static struct spa_log *log; +static struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.bluez5.codecs.aac"); +#undef SPA_LOG_TOPIC_DEFAULT +#define SPA_LOG_TOPIC_DEFAULT &log_topic + #define DEFAULT_AAC_BITRATE 320000 #define MIN_AAC_BITRATE 64000 @@ -44,6 +50,7 @@ struct impl { HANDLE_AACENCODER aacenc; + HANDLE_AACDECODER aacdec; struct rtp_header *header; @@ -170,7 +177,7 @@ return sizeof(conf); } -static int codec_enum_config(const struct a2dp_codec *codec, +static int codec_enum_config(const struct a2dp_codec *codec, uint32_t flags, const void *caps, size_t caps_size, uint32_t id, uint32_t idx, struct spa_pod_builder *b, struct spa_pod **param) { @@ -289,7 +296,7 @@ return 0; } -static void *codec_init_props(const struct a2dp_codec *codec, const struct spa_dict *settings) +static void *codec_init_props(const struct a2dp_codec *codec, uint32_t flags, const struct spa_dict *settings) { struct props *p = calloc(1, sizeof(struct props)); const char *str; @@ -412,11 +419,39 @@ this->codesize = enc_info.frameLength * this->channels * this->samplesize; + this->aacdec = aacDecoder_Open(TT_MP4_LATM_MCP1, 1); + if (!this->aacdec) { + res = -EINVAL; + goto error; + } + +#ifdef AACDECODER_LIB_VL0 + res = aacDecoder_SetParam(this->aacdec, AAC_PCM_MIN_OUTPUT_CHANNELS, this->channels); + if (res != AAC_DEC_OK) { + spa_log_debug(log, "Couldn't set min output channels: 0x%04X", res); + goto error; + } + + res = aacDecoder_SetParam(this->aacdec, AAC_PCM_MAX_OUTPUT_CHANNELS, this->channels); + if (res != AAC_DEC_OK) { + spa_log_debug(log, "Couldn't set max output channels: 0x%04X", res); + goto error; + } +#else + res = aacDecoder_SetParam(this->aacdec, AAC_PCM_OUTPUT_CHANNELS, this->channels); + if (res != AAC_DEC_OK) { + spa_log_debug(log, "Couldn't set output channels: 0x%04X", res); + goto error; + } +#endif + return this; error: if (this && this->aacenc) aacEncClose(&this->aacenc); + if (this && this->aacdec) + aacDecoder_Close(this->aacdec); free(this); errno = -res; return NULL; @@ -427,6 +462,8 @@ struct impl *this = data; if (this->aacenc) aacEncClose(&this->aacenc); + if (this->aacdec) + aacDecoder_Close(this->aacdec); free(this); } @@ -502,6 +539,55 @@ return out_args.numInSamples * this->samplesize; } +static int codec_start_decode (void *data, + const void *src, size_t src_size, uint16_t *seqnum, uint32_t *timestamp) +{ + const struct rtp_header *header = src; + size_t header_size = sizeof(struct rtp_header); + + spa_return_val_if_fail (src_size > header_size, -EINVAL); + + if (seqnum) + *seqnum = ntohs(header->sequence_number); + if (timestamp) + *timestamp = ntohl(header->timestamp); + + return header_size; +} + +static int codec_decode(void *data, + const void *src, size_t src_size, + void *dst, size_t dst_size, + size_t *dst_out) +{ + struct impl *this = data; + uint data_size = (uint)src_size; + uint bytes_valid = data_size; + CStreamInfo *aacinf; + int res; + + res = aacDecoder_Fill(this->aacdec, (UCHAR **)&src, &data_size, &bytes_valid); + if (res != AAC_DEC_OK) { + spa_log_debug(log, "AAC buffer fill error: 0x%04X", res); + return -EINVAL; + } + + res = aacDecoder_DecodeFrame(this->aacdec, dst, dst_size, 0); + if (res != AAC_DEC_OK) { + spa_log_debug(log, "AAC decode frame error: 0x%04X", res); + return -EINVAL; + } + + aacinf = aacDecoder_GetStreamInfo(this->aacdec); + if (!aacinf) { + spa_log_debug(log, "AAC get stream info failed"); + return -EINVAL; + } + *dst_out = aacinf->frameSize * aacinf->numChannels * this->samplesize; + + return src_size - bytes_valid; +} + static int codec_abr_process (void *data, size_t unsent) { return -ENOTSUP; @@ -538,6 +624,12 @@ return codec_change_bitrate(this, (this->cur_bitrate * 4) / 3); } +static void codec_set_log(struct spa_log *global_log) +{ + log = global_log; + spa_log_topic_init(log, &log_topic); +} + const struct a2dp_codec a2dp_codec_aac = { .id = SPA_BLUETOOTH_AUDIO_CODEC_AAC, .codec_id = A2DP_CODEC_MPEG24, @@ -554,9 +646,12 @@ .get_block_size = codec_get_block_size, .start_encode = codec_start_encode, .encode = codec_encode, + .start_decode = codec_start_decode, + .decode = codec_decode, .abr_process = codec_abr_process, .reduce_bitpool = codec_reduce_bitpool, .increase_bitpool = codec_increase_bitpool, + .set_log = codec_set_log, }; A2DP_CODEC_EXPORT_DEF(
View file
pipewire-0.3.56.tar.gz/spa/plugins/bluez5/a2dp-codec-aptx.c -> pipewire-0.3.57.tar.gz/spa/plugins/bluez5/a2dp-codec-aptx.c
Changed
@@ -218,7 +218,7 @@ return actual_conf_size; } -static int codec_enum_config(const struct a2dp_codec *codec, +static int codec_enum_config(const struct a2dp_codec *codec, uint32_t flags, const void *caps, size_t caps_size, uint32_t id, uint32_t idx, struct spa_pod_builder *b, struct spa_pod **param) { @@ -458,7 +458,7 @@ * When connected as SRC to SNK, aptX-LL sink may send back mSBC data. */ -static int msbc_enum_config(const struct a2dp_codec *codec, +static int msbc_enum_config(const struct a2dp_codec *codec, uint32_t flags, const void *caps, size_t caps_size, uint32_t id, uint32_t idx, struct spa_pod_builder *b, struct spa_pod **param) { @@ -710,6 +710,11 @@ .increase_bitpool = msbc_increase_bitpool, }; +static const struct spa_dict_item duplex_info_items = { + { "duplex.boost", "true" }, +}; +static const struct spa_dict duplex_info = SPA_DICT_INIT_ARRAY(duplex_info_items); + const struct a2dp_codec a2dp_codec_aptx_ll_duplex_0 = { APTX_LL_COMMON_DEFS, .id = SPA_BLUETOOTH_AUDIO_CODEC_APTX_LL_DUPLEX, @@ -718,6 +723,7 @@ .name = "aptx_ll_duplex", .endpoint_name = "aptx_ll_duplex_0", .duplex_codec = &aptx_ll_msbc, + .info = &duplex_info, }; const struct a2dp_codec a2dp_codec_aptx_ll_duplex_1 = { @@ -728,6 +734,7 @@ .name = "aptx_ll_duplex", .endpoint_name = "aptx_ll_duplex_1", .duplex_codec = &aptx_ll_msbc, + .info = &duplex_info, }; A2DP_CODEC_EXPORT_DEF(
View file
pipewire-0.3.56.tar.gz/spa/plugins/bluez5/a2dp-codec-caps.h -> pipewire-0.3.57.tar.gz/spa/plugins/bluez5/a2dp-codec-caps.h
Changed
@@ -233,6 +233,54 @@ #define LC3PLUS_HR_SAMPLING_FREQ_48000 (1 << 8) #define LC3PLUS_HR_SAMPLING_FREQ_96000 (1 << 7) +#define OPUS_05_VENDOR_ID 0x000005f1 +#define OPUS_05_CODEC_ID 0x1005 + +#define OPUS_05_MAPPING_FAMILY_0 (1 << 0) +#define OPUS_05_MAPPING_FAMILY_1 (1 << 1) +#define OPUS_05_MAPPING_FAMILY_255 (1 << 2) + +#define OPUS_05_FRAME_DURATION_25 (1 << 0) +#define OPUS_05_FRAME_DURATION_50 (1 << 1) +#define OPUS_05_FRAME_DURATION_100 (1 << 2) +#define OPUS_05_FRAME_DURATION_200 (1 << 3) +#define OPUS_05_FRAME_DURATION_400 (1 << 4) + +#define OPUS_05_GET_UINT16(a, field) \ + (((a).field ## 2 << 8) | (a).field ## 1) +#define OPUS_05_INIT_UINT16(field, v) \ + .field ## 1 = ((v) & 0xff), \ + .field ## 2 = (((v) >> 8) & 0xff), +#define OPUS_05_SET_UINT16(a, field, v) \ + do { \ + (a).field ## 1 = ((v) & 0xff); \ + (a).field ## 2 = (((v) >> 8) & 0xff); \ + } while (0) +#define OPUS_05_GET_UINT32(a, field) \ + (((a).field ## 4 << 24) | ((a).field ## 3 << 16) | \ + ((a).field ## 2 << 8) | (a).field ## 1) +#define OPUS_05_INIT_UINT32(field, v) \ + .field ## 1 = ((v) & 0xff), \ + .field ## 2 = (((v) >> 8) & 0xff), \ + .field ## 3 = (((v) >> 16) & 0xff), \ + .field ## 4 = (((v) >> 24) & 0xff), +#define OPUS_05_SET_UINT32(a, field, v) \ + do { \ + (a).field ## 1 = ((v) & 0xff); \ + (a).field ## 2 = (((v) >> 8) & 0xff); \ + (a).field ## 3 = (((v) >> 16) & 0xff); \ + (a).field ## 4 = (((v) >> 24) & 0xff); \ + } while (0) + +#define OPUS_05_GET_LOCATION(a) OPUS_05_GET_UINT32(a, location) +#define OPUS_05_INIT_LOCATION(v) OPUS_05_INIT_UINT32(location, v) +#define OPUS_05_SET_LOCATION(a, v) OPUS_05_SET_UINT32(a, location, v) + +#define OPUS_05_GET_BITRATE(a) OPUS_05_GET_UINT16(a, bitrate) +#define OPUS_05_INIT_BITRATE(v) OPUS_05_INIT_UINT16(bitrate, v) +#define OPUS_05_SET_BITRATE(a, v) OPUS_05_SET_UINT16(a, bitrate, v) + + typedef struct { uint32_t vendor_id; uint16_t codec_id; @@ -391,4 +439,22 @@ uint8_t frequency2; } __attribute__ ((packed)) a2dp_lc3plus_hr_t; +typedef struct { + uint8_t channels; + uint8_t coupled_streams; + uint8_t location1; + uint8_t location2; + uint8_t location3; + uint8_t location4; + uint8_t frame_duration; + uint8_t bitrate1; + uint8_t bitrate2; +} __attribute__ ((packed)) a2dp_opus_05_direction_t; + +typedef struct { + a2dp_vendor_codec_t info; + a2dp_opus_05_direction_t main; + a2dp_opus_05_direction_t bidi; +} __attribute__ ((packed)) a2dp_opus_05_t; + #endif
View file
pipewire-0.3.56.tar.gz/spa/plugins/bluez5/a2dp-codec-faststream.c -> pipewire-0.3.57.tar.gz/spa/plugins/bluez5/a2dp-codec-faststream.c
Changed
@@ -129,7 +129,7 @@ return sizeof(conf); } -static int codec_enum_config(const struct a2dp_codec *codec, +static int codec_enum_config(const struct a2dp_codec *codec, uint32_t flags, const void *caps, size_t caps_size, uint32_t id, uint32_t idx, struct spa_pod_builder *b, struct spa_pod **param) { @@ -372,7 +372,7 @@ * When connected as SRC to SNK, FastStream sink may send back SBC data. */ -static int duplex_enum_config(const struct a2dp_codec *codec, +static int duplex_enum_config(const struct a2dp_codec *codec, uint32_t flags, const void *caps, size_t caps_size, uint32_t id, uint32_t idx, struct spa_pod_builder *b, struct spa_pod **param) { @@ -614,17 +614,23 @@ .reduce_bitpool = codec_reduce_bitpool, \ .increase_bitpool = codec_increase_bitpool -const struct a2dp_codec a2dp_codec_faststream = { +static const struct a2dp_codec a2dp_codec_faststream = { FASTSTREAM_COMMON_DEFS, .id = SPA_BLUETOOTH_AUDIO_CODEC_FASTSTREAM, .name = "faststream", }; +static const struct spa_dict_item duplex_info_items = { + { "duplex.boost", "true" }, +}; +static const struct spa_dict duplex_info = SPA_DICT_INIT_ARRAY(duplex_info_items); + const struct a2dp_codec a2dp_codec_faststream_duplex = { FASTSTREAM_COMMON_DEFS, .id = SPA_BLUETOOTH_AUDIO_CODEC_FASTSTREAM_DUPLEX, .name = "faststream_duplex", .duplex_codec = &duplex_codec, + .info = &duplex_info, }; A2DP_CODEC_EXPORT_DEF(
View file
pipewire-0.3.56.tar.gz/spa/plugins/bluez5/a2dp-codec-lc3plus.c -> pipewire-0.3.57.tar.gz/spa/plugins/bluez5/a2dp-codec-lc3plus.c
Changed
@@ -150,8 +150,8 @@ return sizeof(conf); } -static int codec_caps_preference_cmp(const struct a2dp_codec *codec, const void *caps1, size_t caps1_size, - const void *caps2, size_t caps2_size, const struct a2dp_codec_audio_info *info) +static int codec_caps_preference_cmp(const struct a2dp_codec *codec, uint32_t flags, const void *caps1, size_t caps1_size, + const void *caps2, size_t caps2_size, const struct a2dp_codec_audio_info *info, const struct spa_dict *global_settings) { a2dp_lc3plus_hr_t conf1, conf2; a2dp_lc3plus_hr_t *conf; @@ -160,7 +160,7 @@ /* Order selected configurations by preference */ res1 = codec->select_config(codec, 0, caps1, caps1_size, info, NULL, (uint8_t *)&conf1); - res2 = codec->select_config(codec, 0, caps2, caps2_size, info , NULL, (uint8_t *)&conf2); + res2 = codec->select_config(codec, 0, caps2, caps2_size, info, NULL, (uint8_t *)&conf2); #define PREFER_EXPR(expr) \ do { \ @@ -190,7 +190,7 @@ #undef PREFER_BOOL } -static int codec_enum_config(const struct a2dp_codec *codec, +static int codec_enum_config(const struct a2dp_codec *codec, uint32_t flags, const void *caps, size_t caps_size, uint32_t id, uint32_t idx, struct spa_pod_builder *b, struct spa_pod **param) {
View file
pipewire-0.3.56.tar.gz/spa/plugins/bluez5/a2dp-codec-ldac.c -> pipewire-0.3.57.tar.gz/spa/plugins/bluez5/a2dp-codec-ldac.c
Changed
@@ -150,7 +150,7 @@ return sizeof(conf); } -static int codec_enum_config(const struct a2dp_codec *codec, +static int codec_enum_config(const struct a2dp_codec *codec, uint32_t flags, const void *caps, size_t caps_size, uint32_t id, uint32_t idx, struct spa_pod_builder *b, struct spa_pod **param) { @@ -284,7 +284,7 @@ return LDACBT_EQMID_AUTO; } -static void *codec_init_props(const struct a2dp_codec *codec, const struct spa_dict *settings) +static void *codec_init_props(const struct a2dp_codec *codec, uint32_t flags, const struct spa_dict *settings) { struct props *p = calloc(1, sizeof(struct props)); const char *str; @@ -469,10 +469,10 @@ error_errno: res = -errno; error: - if (this->ldac) + if (this && this->ldac) ldacBT_free_handle(this->ldac); #ifdef ENABLE_LDAC_ABR - if (this->ldac_abr) + if (this && this->ldac_abr) ldac_ABR_free_handle(this->ldac_abr); #endif free(this);
View file
pipewire-0.3.57.tar.gz/spa/plugins/bluez5/a2dp-codec-opus.c
Added
@@ -0,0 +1,1437 @@ +/* Spa A2DP Opus Codec + * + * Copyright © 2020 Wim Taymans + * Copyright © 2022 Pauli Virtanen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <unistd.h> +#include <string.h> +#include <stddef.h> +#include <errno.h> +#include <arpa/inet.h> +#if __BYTE_ORDER != __LITTLE_ENDIAN +#include <byteswap.h> +#endif + +#include <spa/debug/types.h> +#include <spa/param/audio/type-info.h> +#include <spa/param/audio/raw.h> +#include <spa/utils/string.h> +#include <spa/utils/dict.h> +#include <spa/param/audio/format.h> +#include <spa/param/audio/format-utils.h> + +#include <opus.h> +#include <opus_multistream.h> + +#include "rtp.h" +#include "a2dp-codecs.h" + +static struct spa_log *log; +static struct spa_log_topic log_topic = SPA_LOG_TOPIC(0, "spa.bluez5.codecs.opus"); +#undef SPA_LOG_TOPIC_DEFAULT +#define SPA_LOG_TOPIC_DEFAULT &log_topic + +#define BUFSIZE_FROM_BITRATE(frame_dms,bitrate) ((bitrate)/8 * (frame_dms) / 10000 * 5/4) /* estimate */ + +/* + * Opus CVBR target bitrate. When connecting, it is set to the INITIAL + * value, and after that adjusted according to link quality between the MIN and + * MAX values. The bitrate adjusts up to either MAX or the value at + * which the socket buffer starts filling up, whichever is lower. + * + * With perfect connection quality, the target bitrate converges to the MAX + * value. Under realistic conditions, the upper limit may often be as low as + * 300-500kbit/s, so the INITIAL values are not higher than this. + * + * The MAX is here set to 2-2.5x and INITIAL to 1.5x the upper Opus recommended + * values 1, to be safer quality-wise for CVBR, and MIN to the lower + * recommended value. + * + * 1 https://wiki.xiph.org/Opus_Recommended_Settings + */ +#define BITRATE_INITIAL 192000 +#define BITRATE_MAX 320000 +#define BITRATE_MIN 96000 + +#define BITRATE_INITIAL_51 384000 +#define BITRATE_MAX_51 600000 +#define BITRATE_MIN_51 128000 + +#define BITRATE_INITIAL_71 450000 +#define BITRATE_MAX_71 900000 +#define BITRATE_MIN_71 256000 + +#define BITRATE_DUPLEX_BIDI 160000 + +#define OPUS_05_MAX_BYTES (15 * 1024) + +struct props { + uint32_t channels; + uint32_t coupled_streams; + uint32_t location; + uint32_t max_bitrate; + uint8_t frame_duration; + int application; + + uint32_t bidi_channels; + uint32_t bidi_coupled_streams; + uint32_t bidi_location; + uint32_t bidi_max_bitrate; + uint32_t bidi_frame_duration; + int bidi_application; +}; + +struct dec_data { + int fragment_size; + int fragment_count; + uint8_t fragmentOPUS_05_MAX_BYTES; +}; + +struct abr { + uint64_t now; + uint64_t last_update; + + uint32_t buffer_level; + uint32_t packet_size; + uint32_t total_size; + bool bad; + + uint64_t last_change; + uint64_t retry_interval; + + bool prev_bad; +}; + +struct enc_data { + struct rtp_header *header; + struct rtp_payload *payload; + + struct abr abr; + + int samples; + int codesize; + + int packet_size; + int fragment_size; + int fragment_count; + void *fragment; + + int bitrate_min; + int bitrate_max; + + int bitrate; + int next_bitrate; + + int frame_dms; + int application; +}; + +struct impl { + OpusMSEncoder *enc; + OpusMSDecoder *dec; + + int mtu; + int samplerate; + int application; + + uint8_t channels; + uint8_t streams; + uint8_t coupled_streams; + + bool is_bidi; + + struct dec_data d; + struct enc_data e; +}; + +struct audio_location { + uint32_t mask; + enum spa_audio_channel position; +}; + +struct surround_encoder_mapping { + uint8_t channels; + uint8_t coupled_streams; + uint32_t location; + uint8_t mapping8; /**< permutation streams -> vorbis order */ + uint8_t inv_mapping8; /**< permutation vorbis order -> streams */ +}; + +/* Bluetooth SIG, Assigned Numbers, Generic Audio, Audio Location Definitions */ +#define BT_AUDIO_LOCATION_FL 0x00000001 /* Front Left */ +#define BT_AUDIO_LOCATION_FR 0x00000002 /* Front Right */ +#define BT_AUDIO_LOCATION_FC 0x00000004 /* Front Center */ +#define BT_AUDIO_LOCATION_LFE 0x00000008 /* Low Frequency Effects 1 */ +#define BT_AUDIO_LOCATION_RL 0x00000010 /* Back Left */ +#define BT_AUDIO_LOCATION_RR 0x00000020 /* Back Right */ +#define BT_AUDIO_LOCATION_FLC 0x00000040 /* Front Left of Center */ +#define BT_AUDIO_LOCATION_FRC 0x00000080 /* Front Right of Center */ +#define BT_AUDIO_LOCATION_RC 0x00000100 /* Back Center */ +#define BT_AUDIO_LOCATION_LFE2 0x00000200 /* Low Frequency Effects 2 */ +#define BT_AUDIO_LOCATION_SL 0x00000400 /* Side Left */ +#define BT_AUDIO_LOCATION_SR 0x00000800 /* Side Right */ +#define BT_AUDIO_LOCATION_TFL 0x00001000 /* Top Front Left */ +#define BT_AUDIO_LOCATION_TFR 0x00002000 /* Top Front Right */ +#define BT_AUDIO_LOCATION_TFC 0x00004000 /* Top Front Center */ +#define BT_AUDIO_LOCATION_TC 0x00008000 /* Top Center */ +#define BT_AUDIO_LOCATION_TRL 0x00010000 /* Top Back Left */ +#define BT_AUDIO_LOCATION_TRR 0x00020000 /* Top Back Right */ +#define BT_AUDIO_LOCATION_TSL 0x00040000 /* Top Side Left */ +#define BT_AUDIO_LOCATION_TSR 0x00080000 /* Top Side Right */ +#define BT_AUDIO_LOCATION_TRC 0x00100000 /* Top Back Center */ +#define BT_AUDIO_LOCATION_BC 0x00200000 /* Bottom Front Center */ +#define BT_AUDIO_LOCATION_BLC 0x00400000 /* Bottom Front Left */ +#define BT_AUDIO_LOCATION_BRC 0x00800000 /* Bottom Front Right */ +#define BT_AUDIO_LOCATION_FLW 0x01000000 /* Fron Left Wide */ +#define BT_AUDIO_LOCATION_FRW 0x02000000 /* Front Right Wide */ +#define BT_AUDIO_LOCATION_SSL 0x04000000 /* Left Surround */ +#define BT_AUDIO_LOCATION_SSR 0x08000000 /* Right Surround */ + +#define BT_AUDIO_LOCATION_ANY 0x0fffffff + +static const struct audio_location audio_locations = { + { BT_AUDIO_LOCATION_FL, SPA_AUDIO_CHANNEL_FL }, + { BT_AUDIO_LOCATION_FR, SPA_AUDIO_CHANNEL_FR }, + { BT_AUDIO_LOCATION_SL, SPA_AUDIO_CHANNEL_SL }, + { BT_AUDIO_LOCATION_SR, SPA_AUDIO_CHANNEL_SR }, + { BT_AUDIO_LOCATION_RL, SPA_AUDIO_CHANNEL_RL }, + { BT_AUDIO_LOCATION_RR, SPA_AUDIO_CHANNEL_RR }, + { BT_AUDIO_LOCATION_FLC, SPA_AUDIO_CHANNEL_FLC }, + { BT_AUDIO_LOCATION_FRC, SPA_AUDIO_CHANNEL_FRC }, + { BT_AUDIO_LOCATION_TFL, SPA_AUDIO_CHANNEL_TFL }, + { BT_AUDIO_LOCATION_TFR, SPA_AUDIO_CHANNEL_TFR }, + { BT_AUDIO_LOCATION_TSL, SPA_AUDIO_CHANNEL_TSL }, + { BT_AUDIO_LOCATION_TSR, SPA_AUDIO_CHANNEL_TSR }, + { BT_AUDIO_LOCATION_TRL, SPA_AUDIO_CHANNEL_TRL }, + { BT_AUDIO_LOCATION_TRR, SPA_AUDIO_CHANNEL_TRR }, + { BT_AUDIO_LOCATION_BLC, SPA_AUDIO_CHANNEL_BLC }, + { BT_AUDIO_LOCATION_BRC, SPA_AUDIO_CHANNEL_BRC }, + { BT_AUDIO_LOCATION_FLW, SPA_AUDIO_CHANNEL_FLW }, + { BT_AUDIO_LOCATION_FRW, SPA_AUDIO_CHANNEL_FRW }, + { BT_AUDIO_LOCATION_SSL, SPA_AUDIO_CHANNEL_SL }, /* ~ Side Left */ + { BT_AUDIO_LOCATION_SSR, SPA_AUDIO_CHANNEL_SR }, /* ~ Side Right */ + { BT_AUDIO_LOCATION_FC, SPA_AUDIO_CHANNEL_FC }, + { BT_AUDIO_LOCATION_RC, SPA_AUDIO_CHANNEL_RC }, + { BT_AUDIO_LOCATION_TFC, SPA_AUDIO_CHANNEL_TFC }, + { BT_AUDIO_LOCATION_TC, SPA_AUDIO_CHANNEL_TC }, + { BT_AUDIO_LOCATION_TRC, SPA_AUDIO_CHANNEL_TRC }, + { BT_AUDIO_LOCATION_BC, SPA_AUDIO_CHANNEL_BC }, + { BT_AUDIO_LOCATION_LFE, SPA_AUDIO_CHANNEL_LFE }, + { BT_AUDIO_LOCATION_LFE2, SPA_AUDIO_CHANNEL_LFE2 }, +}; + +/* Opus surround encoder mapping tables for the supported channel configurations */ +static const struct surround_encoder_mapping surround_encoders = { + { 1, 0, (0x0), + { 0 }, { 0 } }, + { 2, 1, (BT_AUDIO_LOCATION_FL | BT_AUDIO_LOCATION_FR), + { 0, 1 }, { 0, 1 } }, + { 3, 1, (BT_AUDIO_LOCATION_FL | BT_AUDIO_LOCATION_FR | BT_AUDIO_LOCATION_FC), + { 0, 2, 1 }, { 0, 2, 1 } }, + { 4, 2, (BT_AUDIO_LOCATION_FL | BT_AUDIO_LOCATION_FR | BT_AUDIO_LOCATION_RL | + BT_AUDIO_LOCATION_RR), + { 0, 1, 2, 3 }, { 0, 1, 2, 3 } }, + { 5, 2, (BT_AUDIO_LOCATION_FL | BT_AUDIO_LOCATION_FR | BT_AUDIO_LOCATION_RL | + BT_AUDIO_LOCATION_RR | BT_AUDIO_LOCATION_FC), + { 0, 4, 1, 2, 3 }, { 0, 2, 3, 4, 1 } }, + { 6, 2, (BT_AUDIO_LOCATION_FL | BT_AUDIO_LOCATION_FR | BT_AUDIO_LOCATION_RL | + BT_AUDIO_LOCATION_RR | BT_AUDIO_LOCATION_FC | + BT_AUDIO_LOCATION_LFE), + { 0, 4, 1, 2, 3, 5 }, { 0, 2, 3, 4, 1, 5 } }, + { 7, 3, (BT_AUDIO_LOCATION_FL | BT_AUDIO_LOCATION_FR | BT_AUDIO_LOCATION_SL | + BT_AUDIO_LOCATION_SR | BT_AUDIO_LOCATION_FC | + BT_AUDIO_LOCATION_RC | BT_AUDIO_LOCATION_LFE), + { 0, 4, 1, 2, 3, 5, 6 }, { 0, 2, 3, 4, 1, 5, 6 } }, + { 8, 3, (BT_AUDIO_LOCATION_FL | BT_AUDIO_LOCATION_FR | BT_AUDIO_LOCATION_SL | + BT_AUDIO_LOCATION_SR | BT_AUDIO_LOCATION_RL | + BT_AUDIO_LOCATION_RR | BT_AUDIO_LOCATION_FC | + BT_AUDIO_LOCATION_LFE), + { 0, 6, 1, 2, 3, 4, 5, 7 }, { 0, 2, 3, 4, 5, 6, 1, 7 } }, +}; + +static uint32_t bt_channel_from_name(const char *name) +{ + size_t i; + enum spa_audio_channel position = SPA_AUDIO_CHANNEL_UNKNOWN; + + for (i = 0; spa_type_audio_channeli.name; i++) { + if (spa_streq(name, spa_debug_type_short_name(spa_type_audio_channeli.name))) { + position = spa_type_audio_channeli.type; + break; + } + } + for (i = 0; i < SPA_N_ELEMENTS(audio_locations); i++) { + if (position == audio_locationsi.position) + return audio_locationsi.mask; + } + return 0; +} + +static uint32_t parse_locations(const char *str) +{ + char *s, *p, *save = NULL; + uint32_t location = 0; + + if (!str) + return 0; + + s = strdup(str); + if (s == NULL) + return 0; + + for (p = s; (p = strtok_r(p, ", ", &save)) != NULL; p = NULL) { + if (*p == '\0') + continue; + location |= bt_channel_from_name(p); + } + free(s); + + return location; +} + +static void parse_settings(struct props *props, const struct spa_dict *settings) +{ + const char *str; + uint32_t v; + + /* Pro Audio settings */ + spa_zero(*props); + props->channels = 8; + props->coupled_streams = 0; + props->location = 0; + props->max_bitrate = BITRATE_MAX; + props->frame_duration = OPUS_05_FRAME_DURATION_100; + props->application = OPUS_APPLICATION_AUDIO; + + props->bidi_channels = 1; + props->bidi_coupled_streams = 0; + props->bidi_location = 0; + props->bidi_max_bitrate = BITRATE_DUPLEX_BIDI; + props->bidi_frame_duration = OPUS_05_FRAME_DURATION_400; + props->bidi_application = OPUS_APPLICATION_AUDIO; + + if (settings == NULL) + return; + + if (spa_atou32(spa_dict_lookup(settings, "bluez5.a2dp.opus.pro.channels"), &v, 0)) + props->channels = SPA_CLAMP(v, 1u, SPA_AUDIO_MAX_CHANNELS); + if (spa_atou32(spa_dict_lookup(settings, "bluez5.a2dp.opus.pro.max-bitrate"), &v, 0)) + props->max_bitrate = SPA_MAX(v, (uint32_t)BITRATE_MIN); + if (spa_atou32(spa_dict_lookup(settings, "bluez5.a2dp.opus.pro.coupled-streams"), &v, 0)) + props->coupled_streams = SPA_CLAMP(v, 0u, props->channels / 2); + + if (spa_atou32(spa_dict_lookup(settings, "bluez5.a2dp.opus.pro.bidi.channels"), &v, 0)) + props->bidi_channels = SPA_CLAMP(v, 0u, SPA_AUDIO_MAX_CHANNELS); + if (spa_atou32(spa_dict_lookup(settings, "bluez5.a2dp.opus.pro.bidi.max-bitrate"), &v, 0)) + props->bidi_max_bitrate = SPA_MAX(v, (uint32_t)BITRATE_MIN); + if (spa_atou32(spa_dict_lookup(settings, "bluez5.a2dp.opus.pro.bidi.coupled-streams"), &v, 0)) + props->bidi_coupled_streams = SPA_CLAMP(v, 0u, props->bidi_channels / 2); + + str = spa_dict_lookup(settings, "bluez5.a2dp.opus.pro.locations"); + props->location = parse_locations(str); + + str = spa_dict_lookup(settings, "bluez5.a2dp.opus.pro.bidi.locations"); + props->bidi_location = parse_locations(str); + + str = spa_dict_lookup(settings, "bluez5.a2dp.opus.pro.frame-dms"); + if (spa_streq(str, "25")) + props->frame_duration = OPUS_05_FRAME_DURATION_25; + else if (spa_streq(str, "50")) + props->frame_duration = OPUS_05_FRAME_DURATION_50; + else if (spa_streq(str, "100")) + props->frame_duration = OPUS_05_FRAME_DURATION_100; + else if (spa_streq(str, "200")) + props->frame_duration = OPUS_05_FRAME_DURATION_200; + else if (spa_streq(str, "400")) + props->frame_duration = OPUS_05_FRAME_DURATION_400; + + str = spa_dict_lookup(settings, "bluez5.a2dp.opus.pro.bidi.frame-dms"); + if (spa_streq(str, "25")) + props->bidi_frame_duration = OPUS_05_FRAME_DURATION_25; + else if (spa_streq(str, "50")) + props->bidi_frame_duration = OPUS_05_FRAME_DURATION_50; + else if (spa_streq(str, "100")) + props->bidi_frame_duration = OPUS_05_FRAME_DURATION_100; + else if (spa_streq(str, "200")) + props->bidi_frame_duration = OPUS_05_FRAME_DURATION_200; + else if (spa_streq(str, "400")) + props->bidi_frame_duration = OPUS_05_FRAME_DURATION_400; + + str = spa_dict_lookup(settings, "bluez5.a2dp.opus.pro.application"); + if (spa_streq(str, "audio")) + props->application = OPUS_APPLICATION_AUDIO; + else if (spa_streq(str, "voip")) + props->application = OPUS_APPLICATION_VOIP; + else if (spa_streq(str, "lowdelay")) + props->application = OPUS_APPLICATION_RESTRICTED_LOWDELAY; + + + str = spa_dict_lookup(settings, "bluez5.a2dp.opus.pro.bidi.application"); + if (spa_streq(str, "audio")) + props->bidi_application = OPUS_APPLICATION_AUDIO; + else if (spa_streq(str, "voip")) + props->bidi_application = OPUS_APPLICATION_VOIP; + else if (spa_streq(str, "lowdelay")) + props->bidi_application = OPUS_APPLICATION_RESTRICTED_LOWDELAY; +} + +static int set_channel_conf(const struct a2dp_codec *codec, a2dp_opus_05_t *caps, const struct props *props) +{ + /* + * Predefined codec profiles + */ + if (caps->main.channels < 1) + return -EINVAL; + + caps->main.coupled_streams = 0; + OPUS_05_SET_LOCATION(caps->main, 0); + + caps->bidi.coupled_streams = 0; + OPUS_05_SET_LOCATION(caps->bidi, 0); + + switch (codec->id) { + case SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05: + caps->main.channels = SPA_MIN(2, caps->main.channels); + if (caps->main.channels == 2) { + caps->main.coupled_streams = surround_encoders1.coupled_streams; + OPUS_05_SET_LOCATION(caps->main, surround_encoders1.location); + } + caps->bidi.channels = 0; + break; + case SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_51: + if (caps->main.channels < 6) + return -EINVAL; + caps->main.channels = surround_encoders5.channels; + caps->main.coupled_streams = surround_encoders5.coupled_streams; + OPUS_05_SET_LOCATION(caps->main, surround_encoders5.location); + caps->bidi.channels = 0; + break; + case SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_71: + if (caps->main.channels < 8) + return -EINVAL; + caps->main.channels = surround_encoders7.channels; + caps->main.coupled_streams = surround_encoders7.coupled_streams; + OPUS_05_SET_LOCATION(caps->main, surround_encoders7.location); + caps->bidi.channels = 0; + break; + case SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_DUPLEX: + if (caps->bidi.channels < 1) + return -EINVAL; + caps->main.channels = SPA_MIN(2, caps->main.channels); + if (caps->main.channels == 2) { + caps->main.coupled_streams = surround_encoders1.coupled_streams; + OPUS_05_SET_LOCATION(caps->main, surround_encoders1.location); + } + caps->bidi.channels = SPA_MIN(2, caps->bidi.channels); + if (caps->bidi.channels == 2) { + caps->bidi.coupled_streams = surround_encoders1.coupled_streams; + OPUS_05_SET_LOCATION(caps->bidi, surround_encoders1.location); + } + break; + case SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_PRO: + if (caps->main.channels < props->channels) + return -EINVAL; + if (props->bidi_channels == 0 && caps->bidi.channels != 0) + return -EINVAL; + if (caps->bidi.channels < props->bidi_channels) + return -EINVAL; + caps->main.channels = props->channels; + caps->main.coupled_streams = props->coupled_streams; + OPUS_05_SET_LOCATION(caps->main, props->location); + caps->bidi.channels = props->bidi_channels; + caps->bidi.coupled_streams = props->bidi_coupled_streams; + OPUS_05_SET_LOCATION(caps->bidi, props->bidi_location); + break; + default: + spa_assert(false); + }; + + return 0; +} + +static void get_default_bitrates(const struct a2dp_codec *codec, bool bidi, int *min, int *max, int *init) +{ + int tmp; + + if (min == NULL) + min = &tmp; + if (max == NULL) + max = &tmp; + if (init == NULL) + init = &tmp; + + if (bidi) { + *min = SPA_MIN(BITRATE_MIN, BITRATE_DUPLEX_BIDI); + *max = BITRATE_DUPLEX_BIDI; + *init = BITRATE_DUPLEX_BIDI; + return; + } + + switch (codec->id) { + case SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05: + *min = BITRATE_MIN; + *max = BITRATE_MAX; + *init = BITRATE_INITIAL; + break; + case SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_51: + *min = BITRATE_MIN_51; + *max = BITRATE_MAX_51; + *init = BITRATE_INITIAL_51; + break; + case SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_71: + *min = BITRATE_MIN_71; + *max = BITRATE_MAX_71; + *init = BITRATE_INITIAL_71; + break; + case SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_DUPLEX: + *min = BITRATE_MIN; + *max = BITRATE_MAX; + *init = BITRATE_INITIAL; + break; + case SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_PRO: + default: + spa_assert_not_reached(); + }; +} + +static int get_mapping(const struct a2dp_codec *codec, const a2dp_opus_05_direction_t *conf, + bool use_surround_encoder, uint8_t *streams_ret, uint8_t *coupled_streams_ret, + const uint8_t **surround_mapping, uint32_t *positions) +{ + const uint8_t channels = conf->channels; + const uint32_t location = OPUS_05_GET_LOCATION(*conf); + const uint8_t coupled_streams = conf->coupled_streams; + const uint8_t *permutation = NULL; + size_t i, j; + + if (channels > SPA_AUDIO_MAX_CHANNELS) + return -EINVAL; + if (2 * coupled_streams > channels) + return -EINVAL; + + if (streams_ret) + *streams_ret = channels - coupled_streams; + if (coupled_streams_ret) + *coupled_streams_ret = coupled_streams; + + if (channels == 0) + return 0; + + if (use_surround_encoder) { + /* Opus surround encoder supports only some channel configurations, and + * needs a specific input channel ordering */ + for (i = 0; i < SPA_N_ELEMENTS(surround_encoders); ++i) { + const struct surround_encoder_mapping *m = &surround_encodersi; + + if (m->channels == channels && + m->coupled_streams == coupled_streams && + m->location == location) + { + spa_assert(channels <= SPA_N_ELEMENTS(m->inv_mapping)); + permutation = m->inv_mapping; + if (surround_mapping) + *surround_mapping = m->mapping; + break; + } + } + if (permutation == NULL && surround_mapping) + *surround_mapping = NULL; + } + + if (positions) { + for (i = 0, j = 0; i < SPA_N_ELEMENTS(audio_locations) && j < channels; ++i) { + const struct audio_location loc = audio_locationsi; + + if (location & loc.mask) { + if (permutation) + positionspermutationj++ = loc.position; + else + positionsj++ = loc.position; + } + } + for (i = SPA_AUDIO_CHANNEL_START_Aux; j < channels; ++i, ++j) + positionsj = i; + } + + return 0; +} + +static int codec_fill_caps(const struct a2dp_codec *codec, uint32_t flags, + uint8_t capsA2DP_MAX_CAPS_SIZE) +{ + a2dp_opus_05_t a2dp_opus_05 = { + .info = codec->vendor, + .main = { + .channels = SPA_AUDIO_MAX_CHANNELS, + .frame_duration = (OPUS_05_FRAME_DURATION_25 | + OPUS_05_FRAME_DURATION_50 | + OPUS_05_FRAME_DURATION_100 | + OPUS_05_FRAME_DURATION_200 | + OPUS_05_FRAME_DURATION_400), + OPUS_05_INIT_LOCATION(BT_AUDIO_LOCATION_ANY) + OPUS_05_INIT_BITRATE(0) + }, + .bidi = { + .channels = SPA_AUDIO_MAX_CHANNELS, + .frame_duration = (OPUS_05_FRAME_DURATION_25 | + OPUS_05_FRAME_DURATION_50 | + OPUS_05_FRAME_DURATION_100 | + OPUS_05_FRAME_DURATION_200 | + OPUS_05_FRAME_DURATION_400), + OPUS_05_INIT_LOCATION(BT_AUDIO_LOCATION_ANY) + OPUS_05_INIT_BITRATE(0) + } + }; + + /* Only duplex/pro codec has bidi, since bluez5-device has to know early + * whether to show nodes or not. */ + if (codec->id != SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_DUPLEX && + codec->id != SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_PRO) + spa_zero(a2dp_opus_05.bidi); + + memcpy(caps, &a2dp_opus_05, sizeof(a2dp_opus_05)); + return sizeof(a2dp_opus_05); +} + +static int codec_select_config(const struct a2dp_codec *codec, uint32_t flags, + const void *caps, size_t caps_size, + const struct a2dp_codec_audio_info *info, + const struct spa_dict *global_settings, uint8_t configA2DP_MAX_CAPS_SIZE) +{ + struct props props; + a2dp_opus_05_t conf; + int res; + int max; + + if (caps_size < sizeof(conf)) + return -EINVAL; + + memcpy(&conf, caps, sizeof(conf)); + + if (codec->vendor.vendor_id != conf.info.vendor_id || + codec->vendor.codec_id != conf.info.codec_id) + return -ENOTSUP; + + parse_settings(&props, global_settings); + + /* Channel Configuration & Audio Location */ + if ((res = set_channel_conf(codec, &conf, &props)) < 0) + return res; + + /* Limits */ + if (codec->id == SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_PRO) { + max = props.max_bitrate; + if (OPUS_05_GET_BITRATE(conf.main) != 0) + OPUS_05_SET_BITRATE(conf.main, SPA_MIN(OPUS_05_GET_BITRATE(conf.main), max / 1024)); + else + OPUS_05_SET_BITRATE(conf.main, max / 1024); + + max = props.bidi_max_bitrate; + if (OPUS_05_GET_BITRATE(conf.bidi) != 0) + OPUS_05_SET_BITRATE(conf.bidi, SPA_MIN(OPUS_05_GET_BITRATE(conf.bidi), max / 1024)); + else + OPUS_05_SET_BITRATE(conf.bidi, max / 1024); + + if (conf.main.frame_duration & props.frame_duration) + conf.main.frame_duration = props.frame_duration; + else + return -EINVAL; + + if (conf.bidi.channels == 0) + true; + else if (conf.bidi.frame_duration & props.bidi_frame_duration) + conf.bidi.frame_duration = props.bidi_frame_duration; + else + return -EINVAL; + } else { + if (conf.main.frame_duration & OPUS_05_FRAME_DURATION_100) + conf.main.frame_duration = OPUS_05_FRAME_DURATION_100; + else if (conf.main.frame_duration & OPUS_05_FRAME_DURATION_200) + conf.main.frame_duration = OPUS_05_FRAME_DURATION_200; + else if (conf.main.frame_duration & OPUS_05_FRAME_DURATION_400) + conf.main.frame_duration = OPUS_05_FRAME_DURATION_400; + else if (conf.main.frame_duration & OPUS_05_FRAME_DURATION_50) + conf.main.frame_duration = OPUS_05_FRAME_DURATION_50; + else if (conf.main.frame_duration & OPUS_05_FRAME_DURATION_25) + conf.main.frame_duration = OPUS_05_FRAME_DURATION_25; + else + return -EINVAL; + + get_default_bitrates(codec, false, NULL, &max, NULL); + + if (OPUS_05_GET_BITRATE(conf.main) != 0) + OPUS_05_SET_BITRATE(conf.main, SPA_MIN(OPUS_05_GET_BITRATE(conf.main), max / 1024)); + else + OPUS_05_SET_BITRATE(conf.main, max / 1024); + + /* longer bidi frames appear to work better */ + if (conf.bidi.channels == 0) + true; + else if (conf.bidi.frame_duration & OPUS_05_FRAME_DURATION_200) + conf.bidi.frame_duration = OPUS_05_FRAME_DURATION_200; + else if (conf.bidi.frame_duration & OPUS_05_FRAME_DURATION_100) + conf.bidi.frame_duration = OPUS_05_FRAME_DURATION_100; + else if (conf.bidi.frame_duration & OPUS_05_FRAME_DURATION_400) + conf.bidi.frame_duration = OPUS_05_FRAME_DURATION_400; + else if (conf.bidi.frame_duration & OPUS_05_FRAME_DURATION_50) + conf.bidi.frame_duration = OPUS_05_FRAME_DURATION_50; + else if (conf.bidi.frame_duration & OPUS_05_FRAME_DURATION_25) + conf.bidi.frame_duration = OPUS_05_FRAME_DURATION_25; + else + return -EINVAL; + + get_default_bitrates(codec, true, NULL, &max, NULL); + + if (conf.bidi.channels == 0) + true; + else if (OPUS_05_GET_BITRATE(conf.bidi) != 0) + OPUS_05_SET_BITRATE(conf.bidi, SPA_MIN(OPUS_05_GET_BITRATE(conf.bidi), max / 1024)); + else + OPUS_05_SET_BITRATE(conf.bidi, max / 1024); + } + + memcpy(config, &conf, sizeof(conf)); + + return sizeof(conf); +} + +static int codec_caps_preference_cmp(const struct a2dp_codec *codec, uint32_t flags, const void *caps1, size_t caps1_size, + const void *caps2, size_t caps2_size, const struct a2dp_codec_audio_info *info, + const struct spa_dict *global_settings) +{ + a2dp_opus_05_t conf1, conf2, cap1, cap2; + a2dp_opus_05_t *conf; + int res1, res2; + int a, b; + + /* Order selected configurations by preference */ + res1 = codec->select_config(codec, flags, caps1, caps1_size, info, global_settings, (uint8_t *)&conf1); + res2 = codec->select_config(codec, flags, caps2, caps2_size, info, global_settings, (uint8_t *)&conf2); + +#define PREFER_EXPR(expr) \ + do { \ + conf = &conf1; \ + a = (expr); \ + conf = &conf2; \ + b = (expr); \ + if (a != b) \ + return b - a; \ + } while (0) + +#define PREFER_BOOL(expr) PREFER_EXPR((expr) ? 1 : 0) + + /* Prefer valid */ + a = (res1 > 0 && (size_t)res1 == sizeof(a2dp_opus_05_t)) ? 1 : 0; + b = (res2 > 0 && (size_t)res2 == sizeof(a2dp_opus_05_t)) ? 1 : 0; + if (!a || !b) + return b - a; + + memcpy(&cap1, caps1, sizeof(cap1)); + memcpy(&cap2, caps2, sizeof(cap2)); + + if (conf1.bidi.channels == 0 && conf2.bidi.channels == 0) { + /* If no bidi, prefer the SEP that has none */ + a = (cap1.bidi.channels == 0); + b = (cap2.bidi.channels == 0); + if (a != b) + return b - a; + } + + PREFER_EXPR(conf->main.channels); + PREFER_EXPR(conf->bidi.channels); + PREFER_EXPR(OPUS_05_GET_BITRATE(conf->main)); + PREFER_EXPR(OPUS_05_GET_BITRATE(conf->bidi)); + + return 0; + +#undef PREFER_EXPR +#undef PREFER_BOOL +} + +static bool is_duplex_codec(const struct a2dp_codec *codec) +{ + return codec->id == 0; +} + +static bool use_surround_encoder(const struct a2dp_codec *codec, bool is_sink) +{ + if (codec->id == SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_PRO) + return false; + + if (is_duplex_codec(codec)) + return is_sink; + else + return !is_sink; +} + +static int codec_enum_config(const struct a2dp_codec *codec, uint32_t flags, + const void *caps, size_t caps_size, uint32_t id, uint32_t idx, + struct spa_pod_builder *b, struct spa_pod **param) +{ + const bool surround_encoder = use_surround_encoder(codec, flags & A2DP_CODEC_FLAG_SINK); + a2dp_opus_05_t conf; + a2dp_opus_05_direction_t *dir; + struct spa_pod_frame f1; + uint32_t positionSPA_AUDIO_MAX_CHANNELS; + + if (caps_size < sizeof(conf)) + return -EINVAL; + + memcpy(&conf, caps, sizeof(conf)); + + if (idx > 0) + return 0; + + dir = !is_duplex_codec(codec) ? &conf.main : &conf.bidi; + + if (get_mapping(codec, dir, surround_encoder, NULL, NULL, NULL, position) < 0) + return -EINVAL; + + spa_pod_builder_push_object(b, &f0, SPA_TYPE_OBJECT_Format, id); + spa_pod_builder_add(b, + SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio), + SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), + SPA_FORMAT_AUDIO_format, SPA_POD_Id(SPA_AUDIO_FORMAT_F32), + SPA_FORMAT_AUDIO_rate, SPA_POD_CHOICE_ENUM_Int(6, + 48000, 48000, 24000, 16000, 12000, 8000), + SPA_FORMAT_AUDIO_channels, SPA_POD_Int(dir->channels), + SPA_FORMAT_AUDIO_position, SPA_POD_Array(sizeof(uint32_t), + SPA_TYPE_Id, dir->channels, position), + 0); + + *param = spa_pod_builder_pop(b, &f0); + return *param == NULL ? -EIO : 1; +} + +static int codec_validate_config(const struct a2dp_codec *codec, uint32_t flags, + const void *caps, size_t caps_size, + struct spa_audio_info *info) +{ + const bool surround_encoder = use_surround_encoder(codec, flags & A2DP_CODEC_FLAG_SINK); + const a2dp_opus_05_direction_t *dir1, *dir2; + const a2dp_opus_05_t *conf; + + if (caps == NULL || caps_size < sizeof(*conf)) + return -EINVAL; + + conf = caps; + + spa_zero(*info); + info->media_type = SPA_MEDIA_TYPE_audio; + info->media_subtype = SPA_MEDIA_SUBTYPE_raw; + info->info.raw.format = SPA_AUDIO_FORMAT_F32; + info->info.raw.rate = 0; /* not specified by config */ + + if (2 * conf->main.coupled_streams > conf->main.channels) + return -EINVAL; + if (2 * conf->bidi.coupled_streams > conf->bidi.channels) + return -EINVAL; + + if (!is_duplex_codec(codec)) { + dir1 = &conf->main; + dir2 = &conf->bidi; + } else { + dir1 = &conf->bidi; + dir2 = &conf->main; + } + + info->info.raw.channels = dir1->channels; + if (get_mapping(codec, dir1, surround_encoder, NULL, NULL, NULL, info->info.raw.position) < 0) + return -EINVAL; + if (get_mapping(codec, dir2, surround_encoder, NULL, NULL, NULL, NULL) < 0) + return -EINVAL; + + return 0; +} + +static size_t ceildiv(size_t v, size_t divisor) +{ + if (v % divisor == 0) + return v / divisor; + else + return v / divisor + 1; +} + +static bool check_bitrate_vs_frame_dms(struct impl *this, size_t bitrate) +{ + size_t header_size = sizeof(struct rtp_header) + sizeof(struct rtp_payload); + size_t max_fragments = 0xf; + size_t payload_size = BUFSIZE_FROM_BITRATE(bitrate, this->e.frame_dms); + return (size_t)this->mtu >= header_size + ceildiv(payload_size, max_fragments); +} + +static int parse_frame_dms(int bitfield) +{ + switch (bitfield) { + case OPUS_05_FRAME_DURATION_25: + return 25; + case OPUS_05_FRAME_DURATION_50: + return 50; + case OPUS_05_FRAME_DURATION_100: + return 100; + case OPUS_05_FRAME_DURATION_200: + return 200; + case OPUS_05_FRAME_DURATION_400: + return 400; + default: + return -EINVAL; + } +} + +static void *codec_init_props(const struct a2dp_codec *codec, uint32_t flags, const struct spa_dict *settings) +{ + struct props *p; + + if (codec->id != SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_PRO) + return NULL; + + p = calloc(1, sizeof(struct props)); + if (p == NULL) + return NULL; + + parse_settings(p, settings); + + return p; +} + +static void codec_clear_props(void *props) +{ + free(props); +} + +static void *codec_init(const struct a2dp_codec *codec, uint32_t flags, + void *config, size_t config_len, const struct spa_audio_info *info, + void *props, size_t mtu) +{ + const bool surround_encoder = use_surround_encoder(codec, flags & A2DP_CODEC_FLAG_SINK); + a2dp_opus_05_t *conf = config; + a2dp_opus_05_direction_t *dir; + struct impl *this = NULL; + struct spa_audio_info config_info; + const uint8_t *enc_mapping = NULL; + unsigned char mapping256; + size_t i; + int res; + + if (info->media_type != SPA_MEDIA_TYPE_audio || + info->media_subtype != SPA_MEDIA_SUBTYPE_raw || + info->info.raw.format != SPA_AUDIO_FORMAT_F32) { + res = -EINVAL; + goto error; + } + + if ((this = calloc(1, sizeof(struct impl))) == NULL) + goto error_errno; + + this->is_bidi = is_duplex_codec(codec); + dir = !this->is_bidi ? &conf->main : &conf->bidi; + + if ((res = codec_validate_config(codec, flags, config, config_len, &config_info)) < 0) + goto error; + if ((res = get_mapping(codec, dir, surround_encoder, &this->streams, &this->coupled_streams, + &enc_mapping, NULL)) < 0) + goto error; + if (config_info.info.raw.channels != info->info.raw.channels) { + res = -EINVAL; + goto error; + } + + this->mtu = mtu; + this->samplerate = info->info.raw.rate; + this->channels = config_info.info.raw.channels; + this->application = OPUS_APPLICATION_AUDIO; + + if (codec->id == SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_PRO && props) { + struct props *p = props; + this->application = !this->is_bidi ? p->application : + p->bidi_application; + } + + /* + * Setup encoder + */ + if (enc_mapping) { + int streams, coupled_streams; + bool incompatible_opus_surround_encoder = false; + + this->enc = opus_multistream_surround_encoder_create( + this->samplerate, this->channels, 1, &streams, &coupled_streams, + mapping, this->application, &res); + + if (this->enc) { + /* Check surround encoder channel mapping is what we want */ + if (streams != this->streams || coupled_streams != this->coupled_streams) + incompatible_opus_surround_encoder = true; + for (i = 0; i < this->channels; ++i) + if (enc_mappingi != mappingi) + incompatible_opus_surround_encoder = true; + } + + /* Assert: this should never happen */ + spa_assert(!incompatible_opus_surround_encoder); + if (incompatible_opus_surround_encoder) { + res = -EINVAL; + goto error; + } + } else { + for (i = 0; i < this->channels; ++i) + mappingi = i; + this->enc = opus_multistream_encoder_create( + this->samplerate, this->channels, this->streams, this->coupled_streams, + mapping, this->application, &res); + } + if (this->enc == NULL) { + res = -EINVAL; + goto error; + } + + if ((this->e.frame_dms = parse_frame_dms(dir->frame_duration)) < 0) { + res = -EINVAL; + goto error; + } + + if (codec->id != SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_PRO) { + get_default_bitrates(codec, this->is_bidi, &this->e.bitrate_min, + &this->e.bitrate_max, &this->e.bitrate); + this->e.bitrate_max = SPA_MIN(this->e.bitrate_max, + OPUS_05_GET_BITRATE(*dir) * 1024); + } else { + this->e.bitrate_max = OPUS_05_GET_BITRATE(*dir) * 1024; + this->e.bitrate_min = BITRATE_MIN; + this->e.bitrate = BITRATE_INITIAL; + } + + this->e.bitrate_min = SPA_MIN(this->e.bitrate_min, this->e.bitrate_max); + this->e.bitrate = SPA_CLAMP(this->e.bitrate, this->e.bitrate_min, this->e.bitrate_max); + + this->e.next_bitrate = this->e.bitrate; + opus_multistream_encoder_ctl(this->enc, OPUS_SET_BITRATE(this->e.bitrate)); + + this->e.samples = this->e.frame_dms * this->samplerate / 10000; + this->e.codesize = this->e.samples * (int)this->channels * sizeof(float); + + + /* + * Setup decoder + */ + for (i = 0; i < this->channels; ++i) + mappingi = i; + this->dec = opus_multistream_decoder_create( + this->samplerate, this->channels, + this->streams, this->coupled_streams, + mapping, &res); + if (this->dec == NULL) { + res = -EINVAL; + goto error; + } + + return this; + +error_errno: + res = -errno; + goto error; + +error: + if (this && this->enc) + opus_multistream_encoder_destroy(this->enc); + if (this && this->dec) + opus_multistream_decoder_destroy(this->dec); + free(this); + errno = -res; + return NULL; +} + +static void codec_deinit(void *data) +{ + struct impl *this = data; + opus_multistream_encoder_destroy(this->enc); + opus_multistream_decoder_destroy(this->dec); + free(this); +} + +static int codec_get_block_size(void *data) +{ + struct impl *this = data; + return this->e.codesize; +} + +static int codec_update_bitrate(struct impl *this) +{ + this->e.next_bitrate = SPA_CLAMP(this->e.next_bitrate, + this->e.bitrate_min, this->e.bitrate_max); + + if (!check_bitrate_vs_frame_dms(this, this->e.next_bitrate)) { + this->e.next_bitrate = this->e.bitrate; + return 0; + } + + this->e.bitrate = this->e.next_bitrate; + opus_multistream_encoder_ctl(this->enc, OPUS_SET_BITRATE(this->e.bitrate)); + return 0; +} + +static int codec_start_encode (void *data, + void *dst, size_t dst_size, uint16_t seqnum, uint32_t timestamp) +{ + struct impl *this = data; + size_t header_size = sizeof(struct rtp_header) + sizeof(struct rtp_payload); + + if (dst_size <= header_size) + return -EINVAL; + + codec_update_bitrate(this); + + this->e.header = (struct rtp_header *)dst; + this->e.payload = SPA_PTROFF(dst, sizeof(struct rtp_header), struct rtp_payload); + memset(dst, 0, header_size); + + this->e.payload->frame_count = 0; + this->e.header->v = 2; + this->e.header->pt = 96; + this->e.header->sequence_number = htons(seqnum); + this->e.header->timestamp = htonl(timestamp); + this->e.header->ssrc = htonl(1); + + this->e.packet_size = header_size; + return this->e.packet_size; +} + +static int codec_encode(void *data, + const void *src, size_t src_size, + void *dst, size_t dst_size, + size_t *dst_out, int *need_flush) +{ + struct impl *this = data; + const int header_size = sizeof(struct rtp_header) + sizeof(struct rtp_payload); + int size; + int res; + + if (src == NULL) { + /* Produce fragment packets. + * + * We assume the caller gives the same buffer here as in the previous + * calls to encode(), without changes in the buffer content. + */ + if (this->e.fragment == NULL || + this->e.fragment_count <= 1 || + this->e.fragment < dst || + SPA_PTROFF(this->e.fragment, this->e.fragment_size, void) > SPA_PTROFF(dst, dst_size, void)) { + this->e.fragment = NULL; + return -EINVAL; + } + + size = SPA_MIN(this->mtu - header_size, this->e.fragment_size); + memmove(dst, this->e.fragment, size); + *dst_out = size; + + this->e.payload->is_fragmented = 1; + this->e.payload->frame_count = --this->e.fragment_count; + this->e.payload->is_last_fragment = (this->e.fragment_count == 1); + + if (this->e.fragment_size > size && this->e.fragment_count > 1) { + this->e.fragment = SPA_PTROFF(this->e.fragment, size, void); + this->e.fragment_size -= size; + *need_flush = NEED_FLUSH_FRAGMENT; + } else { + this->e.fragment = NULL; + *need_flush = NEED_FLUSH_ALL; + } + return 0; + } + + if (src_size < (size_t)this->e.codesize) { + *dst_out = 0; + return 0; + } + + res = opus_multistream_encode_float( + this->enc, src, this->e.samples, dst, dst_size); + if (res < 0) + return -EINVAL; + *dst_out = res; + + this->e.packet_size += res; + this->e.payload->frame_count++; + + if (this->e.packet_size > this->mtu) { + /* Fragment packet */ + this->e.fragment_count = ceildiv(this->e.packet_size - header_size, + this->mtu - header_size); + + this->e.payload->is_fragmented = 1; + this->e.payload->is_first_fragment = 1; + this->e.payload->frame_count = this->e.fragment_count; + + this->e.fragment_size = this->e.packet_size - this->mtu; + this->e.fragment = SPA_PTROFF(dst, *dst_out - this->e.fragment_size, void); + *need_flush = NEED_FLUSH_FRAGMENT; + + /* + * We keep the rest of the encoded frame in the same buffer, and rely + * that the caller won't overwrite it before the next call to encode() + */ + *dst_out = SPA_PTRDIFF(this->e.fragment, dst); + } else { + *need_flush = NEED_FLUSH_ALL; + } + + return this->e.codesize; +} + +static SPA_UNUSED int codec_start_decode (void *data, + const void *src, size_t src_size, uint16_t *seqnum, uint32_t *timestamp) +{ + struct impl *this = data; + const struct rtp_header *header = src; + const struct rtp_payload *payload = SPA_PTROFF(src, sizeof(struct rtp_header), void); + size_t header_size = sizeof(struct rtp_header) + sizeof(struct rtp_payload); + + spa_return_val_if_fail (src_size > header_size, -EINVAL); + + if (seqnum) + *seqnum = ntohs(header->sequence_number); + if (timestamp) + *timestamp = ntohl(header->timestamp); + + if (payload->is_fragmented) { + if (payload->is_first_fragment) { + this->d.fragment_size = 0; + } else if (payload->frame_count + 1 != this->d.fragment_count || + (payload->frame_count == 1 && !payload->is_last_fragment)){ + /* Fragments not in right order: drop packet */ + return -EINVAL; + } + this->d.fragment_count = payload->frame_count; + } else { + if (payload->frame_count != 1) + return -EINVAL; + this->d.fragment_count = 0; + } + + return header_size; +} + +static SPA_UNUSED int codec_decode(void *data, + const void *src, size_t src_size, + void *dst, size_t dst_size, + size_t *dst_out) +{ + struct impl *this = data; + int consumed = src_size; + int res; + int dst_samples; + + if (this->d.fragment_count > 0) { + /* Fragmented frame */ + size_t avail; + avail = SPA_MIN(sizeof(this->d.fragment) - this->d.fragment_size, src_size); + memcpy(SPA_PTROFF(this->d.fragment, this->d.fragment_size, void), src, avail); + + this->d.fragment_size += avail; + + if (this->d.fragment_count > 1) { + /* More fragments to come */ + *dst_out = 0; + return consumed; + } + + src = this->d.fragment; + src_size = this->d.fragment_size; + + this->d.fragment_count = 0; + this->d.fragment_size = 0; + } + + dst_samples = dst_size / (sizeof(float) * this->channels); + res = opus_multistream_decode_float(this->dec, src, src_size, dst, dst_samples, 0); + if (res < 0) + return -EINVAL; + *dst_out = (size_t)res * this->channels * sizeof(float); + + return consumed; +} + +static int codec_abr_process(void *data, size_t unsent) +{ + const uint64_t interval = SPA_NSEC_PER_SEC; + struct impl *this = data; + struct abr *abr = &this->e.abr; + bool level_bad, level_good; + uint32_t actual_bitrate; + + abr->total_size += this->e.packet_size; + + if (this->e.payload->is_fragmented && !this->e.payload->is_first_fragment) + return 0; + + abr->now += this->e.frame_dms * SPA_NSEC_PER_MSEC / 10; + + abr->buffer_level = SPA_MAX(abr->buffer_level, unsent); + abr->packet_size = SPA_MAX(abr->packet_size, (uint32_t)this->e.packet_size); + abr->packet_size = SPA_MAX(abr->packet_size, 128u); + + level_bad = abr->buffer_level > 2 * (uint32_t)this->mtu || abr->bad; + level_good = abr->buffer_level == 0; + + if (!(abr->last_update + interval <= abr->now || + (level_bad && abr->last_change + interval <= abr->now))) + return 0; + + actual_bitrate = (uint64_t)abr->total_size*8*SPA_NSEC_PER_SEC + / SPA_MAX(1u, abr->now - abr->last_update); + + spa_log_debug(log, "opus ABR bitrate:%d actual:%d level:%d (%s) bad:%d retry:%ds size:%d", + (int)this->e.bitrate, + (int)actual_bitrate, + (int)abr->buffer_level, + level_bad ? "bad" : (level_good ? "good" : "-"), + (int)abr->bad, + (int)(abr->retry_interval / SPA_NSEC_PER_SEC), + (int)abr->packet_size); + + if (level_bad) { + this->e.next_bitrate = this->e.bitrate * 11 / 12; + abr->last_change = abr->now; + abr->retry_interval = SPA_MIN(abr->retry_interval + 10*interval, + 30 * interval); + } else if (!level_good) { + abr->last_change = abr->now; + } else if (abr->now < abr->last_change + abr->retry_interval) { + /* noop */ + } else if (actual_bitrate*3/2 < (uint32_t)this->e.bitrate) { + /* actual bitrate is small compared to target; probably silence */ + } else { + this->e.next_bitrate = this->e.bitrate + + SPA_MAX(1, this->e.bitrate_max / 40); + abr->last_change = abr->now; + abr->retry_interval = SPA_MAX(abr->retry_interval, (5+4)*interval) + - 4*interval; + } + + abr->last_update = abr->now; + abr->buffer_level = 0; + abr->bad = false; + abr->packet_size = 0; + abr->total_size = 0; + + return 0; +} + +static int codec_reduce_bitpool(void *data) +{ + struct impl *this = data; + struct abr *abr = &this->e.abr; + abr->bad = true; + return 0; +} + +static int codec_increase_bitpool(void *data) +{ + return 0; +} + +static void codec_set_log(struct spa_log *global_log) +{ + log = global_log; + spa_log_topic_init(log, &log_topic); +} + +#define OPUS_05_COMMON_DEFS \ + .codec_id = A2DP_CODEC_VENDOR, \ + .vendor = { .vendor_id = OPUS_05_VENDOR_ID, \ + .codec_id = OPUS_05_CODEC_ID }, \ + .fill_caps = codec_fill_caps, \ + .select_config = codec_select_config, \ + .enum_config = codec_enum_config, \ + .validate_config = codec_validate_config, \ + .caps_preference_cmp = codec_caps_preference_cmp, \ + .init = codec_init, \ + .deinit = codec_deinit, \ + .get_block_size = codec_get_block_size, \ + .abr_process = codec_abr_process, \ + .start_encode = codec_start_encode, \ + .encode = codec_encode, \ + .reduce_bitpool = codec_reduce_bitpool, \ + .increase_bitpool = codec_increase_bitpool, \ + .set_log = codec_set_log + +#define OPUS_05_COMMON_FULL_DEFS \ + OPUS_05_COMMON_DEFS, \ + .start_decode = codec_start_decode, \ + .decode = codec_decode + +const struct a2dp_codec a2dp_codec_opus_05 = { + OPUS_05_COMMON_FULL_DEFS, + .id = SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05, + .name = "opus_05", + .description = "Opus", +}; + +const struct a2dp_codec a2dp_codec_opus_05_51 = { + OPUS_05_COMMON_DEFS, + .id = SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_51, + .name = "opus_05_51", + .description = "Opus 5.1 Surround", +}; + +const struct a2dp_codec a2dp_codec_opus_05_71 = { + OPUS_05_COMMON_DEFS, + .id = SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_71, + .name = "opus_05_71", + .description = "Opus 7.1 Surround", +}; + +/* Bidi return channel codec: doesn't have endpoints */ +const struct a2dp_codec a2dp_codec_opus_05_return = { + OPUS_05_COMMON_FULL_DEFS, + .id = 0, + .name = "opus_05_duplex_bidi", + .description = "Opus Duplex Bidi channel", +}; + +const struct a2dp_codec a2dp_codec_opus_05_duplex = { + OPUS_05_COMMON_FULL_DEFS, + .id = SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_DUPLEX, + .name = "opus_05_duplex", + .description = "Opus Duplex", + .duplex_codec = &a2dp_codec_opus_05_return, +}; + +const struct a2dp_codec a2dp_codec_opus_05_pro = { + OPUS_05_COMMON_DEFS, + .id = SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_PRO, + .name = "opus_05_pro", + .description = "Opus Pro Audio", + .init_props = codec_init_props, + .clear_props = codec_clear_props, + .duplex_codec = &a2dp_codec_opus_05_return, +}; + +A2DP_CODEC_EXPORT_DEF( + "opus", + &a2dp_codec_opus_05, + &a2dp_codec_opus_05_51, + &a2dp_codec_opus_05_71, + &a2dp_codec_opus_05_duplex, + &a2dp_codec_opus_05_pro +);
View file
pipewire-0.3.56.tar.gz/spa/plugins/bluez5/a2dp-codec-sbc.c -> pipewire-0.3.57.tar.gz/spa/plugins/bluez5/a2dp-codec-sbc.c
Changed
@@ -229,8 +229,8 @@ return sizeof(conf); } -static int codec_caps_preference_cmp(const struct a2dp_codec *codec, const void *caps1, size_t caps1_size, - const void *caps2, size_t caps2_size, const struct a2dp_codec_audio_info *info) +static int codec_caps_preference_cmp(const struct a2dp_codec *codec, uint32_t flags, const void *caps1, size_t caps1_size, + const void *caps2, size_t caps2_size, const struct a2dp_codec_audio_info *info, const struct spa_dict *global_settings) { a2dp_sbc_t conf1, conf2; a2dp_sbc_t *conf; @@ -356,7 +356,7 @@ return this->sbc.bitpool; } -static int codec_enum_config(const struct a2dp_codec *codec, +static int codec_enum_config(const struct a2dp_codec *codec, uint32_t flags, const void *caps, size_t caps_size, uint32_t id, uint32_t idx, struct spa_pod_builder *b, struct spa_pod **param) {
View file
pipewire-0.3.56.tar.gz/spa/plugins/bluez5/a2dp-codecs.c -> pipewire-0.3.57.tar.gz/spa/plugins/bluez5/a2dp-codecs.c
Changed
@@ -62,7 +62,8 @@ bool a2dp_codec_check_caps(const struct a2dp_codec *codec, unsigned int codec_id, const void *caps, size_t caps_size, - const struct a2dp_codec_audio_info *info) + const struct a2dp_codec_audio_info *info, + const struct spa_dict *global_settings) { uint8_t configA2DP_MAX_CAPS_SIZE; int res; @@ -73,7 +74,7 @@ if (caps == NULL) return false; - res = codec->select_config(codec, 0, caps, caps_size, info, NULL, config); + res = codec->select_config(codec, 0, caps, caps_size, info, global_settings, config); if (res < 0) return false;
View file
pipewire-0.3.56.tar.gz/spa/plugins/bluez5/a2dp-codecs.h -> pipewire-0.3.57.tar.gz/spa/plugins/bluez5/a2dp-codecs.h
Changed
@@ -33,6 +33,7 @@ #include <spa/support/plugin.h> #include <spa/pod/pod.h> #include <spa/pod/builder.h> +#include <spa/support/log.h> #include "a2dp-codec-caps.h" @@ -43,7 +44,7 @@ #define SPA_TYPE_INTERFACE_Bluez5CodecA2DP SPA_TYPE_INFO_INTERFACE_BASE "Bluez5:Codec:A2DP:Private" -#define SPA_VERSION_BLUEZ5_CODEC_A2DP 1 +#define SPA_VERSION_BLUEZ5_CODEC_A2DP 5 struct spa_bluez5_codec_a2dp { struct spa_interface iface; @@ -62,6 +63,7 @@ extern const char *codec_plugin_factory_name; #endif +#define A2DP_CODEC_FLAG_SINK (1 << 0) #define A2DP_CODEC_DEFAULT_RATE 48000 #define A2DP_CODEC_DEFAULT_CHANNELS 2 @@ -96,8 +98,8 @@ int (*select_config) (const struct a2dp_codec *codec, uint32_t flags, const void *caps, size_t caps_size, const struct a2dp_codec_audio_info *info, - const struct spa_dict *settings, uint8_t configA2DP_MAX_CAPS_SIZE); - int (*enum_config) (const struct a2dp_codec *codec, + const struct spa_dict *global_settings, uint8_t configA2DP_MAX_CAPS_SIZE); + int (*enum_config) (const struct a2dp_codec *codec, uint32_t flags, const void *caps, size_t caps_size, uint32_t id, uint32_t idx, struct spa_pod_builder *builder, struct spa_pod **param); int (*validate_config) (const struct a2dp_codec *codec, uint32_t flags, @@ -109,10 +111,11 @@ * The caps handed in correspond to this codec_id, but are * otherwise not checked beforehand. */ - int (*caps_preference_cmp) (const struct a2dp_codec *codec, const void *caps1, size_t caps1_size, - const void *caps2, size_t caps2_size, const struct a2dp_codec_audio_info *info); + int (*caps_preference_cmp) (const struct a2dp_codec *codec, uint32_t flags, const void *caps1, size_t caps1_size, + const void *caps2, size_t caps2_size, const struct a2dp_codec_audio_info *info, + const struct spa_dict *global_settings); - void *(*init_props) (const struct a2dp_codec *codec, const struct spa_dict *settings); + void *(*init_props) (const struct a2dp_codec *codec, uint32_t flags, const struct spa_dict *settings); void (*clear_props) (void *); int (*enum_props) (void *props, const struct spa_dict *settings, uint32_t id, uint32_t idx, struct spa_pod_builder *builder, struct spa_pod **param); @@ -144,6 +147,8 @@ int (*reduce_bitpool) (void *data); int (*increase_bitpool) (void *data); + + void (*set_log) (struct spa_log *global_log); }; struct a2dp_codec_config { @@ -156,6 +161,7 @@ uint32_t cap, int preferred_value); bool a2dp_codec_check_caps(const struct a2dp_codec *codec, unsigned int codec_id, - const void *caps, size_t caps_size, const struct a2dp_codec_audio_info *info); + const void *caps, size_t caps_size, const struct a2dp_codec_audio_info *info, + const struct spa_dict *global_settings); #endif
View file
pipewire-0.3.56.tar.gz/spa/plugins/bluez5/a2dp-sink.c -> pipewire-0.3.57.tar.gz/spa/plugins/bluez5/a2dp-sink.c
Changed
@@ -137,6 +137,8 @@ unsigned int started:1; unsigned int following:1; + unsigned int is_duplex:1; + struct spa_source source; int timerfd; struct spa_source flush_source; @@ -908,7 +910,8 @@ for (i = 0; i < size; i++) spa_log_debug(this->log, " %d: %02x", i, confi); - this->codec_data = this->codec->init(this->codec, 0, + this->codec_data = this->codec->init(this->codec, + this->is_duplex ? A2DP_CODEC_FLAG_SINK : 0, this->transport->configuration, this->transport->configuration_len, &port->current_format, @@ -1195,6 +1198,7 @@ return -EIO; if ((res = this->codec->enum_config(this->codec, + this->is_duplex ? A2DP_CODEC_FLAG_SINK : 0, this->transport->configuration, this->transport->configuration_len, id, result.index, &b, ¶m)) != 1) @@ -1457,8 +1461,8 @@ spa_return_val_if_fail(this != NULL, -EINVAL); port = &this->port; - io = port->io; - spa_return_val_if_fail(io != NULL, -EIO); + if ((io = port->io) == NULL) + return -EIO; if (this->position && this->position->clock.flags & SPA_IO_CLOCK_FLAG_FREEWHEEL) { io->status = SPA_STATUS_NEED_DATA; @@ -1697,6 +1701,9 @@ spa_list_init(&port->ready); + if (info && (str = spa_dict_lookup(info, "api.bluez5.a2dp-duplex")) != NULL) + this->is_duplex = spa_atob(str); + if (info && (str = spa_dict_lookup(info, SPA_KEY_API_BLUEZ5_TRANSPORT))) sscanf(str, "pointer:%p", &this->transport); @@ -1708,9 +1715,20 @@ spa_log_error(this->log, "a transport codec is needed"); return -EINVAL; } + this->codec = this->transport->a2dp_codec; + + if (this->is_duplex) { + if (!this->codec->duplex_codec) { + spa_log_error(this->log, "transport codec doesn't support duplex"); + return -EINVAL; + } + this->codec = this->codec->duplex_codec; + } + if (this->codec->init_props != NULL) this->codec_props = this->codec->init_props(this->codec, + this->is_duplex ? A2DP_CODEC_FLAG_SINK : 0, this->transport->device->settings); reset_props(this, &this->props);
View file
pipewire-0.3.56.tar.gz/spa/plugins/bluez5/a2dp-source.c -> pipewire-0.3.57.tar.gz/spa/plugins/bluez5/a2dp-source.c
Changed
@@ -142,6 +142,7 @@ unsigned int is_input:1; unsigned int is_duplex:1; + unsigned int use_duplex_source:1; int fd; struct spa_source source; @@ -629,7 +630,8 @@ this->transport_acquired = true; - this->codec_data = this->codec->init(this->codec, 0, + this->codec_data = this->codec->init(this->codec, + this->is_duplex ? 0 : A2DP_CODEC_FLAG_SINK, this->transport->configuration, this->transport->configuration_len, &port->current_format, @@ -668,7 +670,7 @@ this->source.data = this; - if (!this->is_duplex) { + if (!this->use_duplex_source) { this->source.fd = this->transport->fd; this->source.func = a2dp_on_ready_read; this->source.mask = SPA_IO_IN; @@ -683,7 +685,8 @@ * XXX: The reason for this should be found and fixed. * XXX: To work around this, for now we just do the stupid thing and poll * XXX: on a timer, chosen so that it's fast enough for the aptX-LL codec - * XXX: we currently support (which sends mSBC data). + * XXX: we currently support (which sends mSBC data), and also for Opus + * XXX: forward stream. */ this->source.fd = this->duplex_timerfd; this->source.func = a2dp_on_duplex_timeout; @@ -691,7 +694,7 @@ this->source.rmask = 0; spa_loop_add_source(this->data_loop, &this->source); - this->duplex_timeout = SPA_NSEC_PER_MSEC * 75/10; + this->duplex_timeout = SPA_NSEC_PER_MSEC * 25/10; set_duplex_timeout(this, this->duplex_timeout); } @@ -718,13 +721,13 @@ if (this->started) return 0; + spa_return_val_if_fail(this->transport != NULL, -EIO); + this->following = is_following(this); spa_log_debug(this->log, "%p: start state:%d following:%d", this, this->transport->state, this->following); - spa_return_val_if_fail(this->transport != NULL, -EIO); - if (this->transport->state >= SPA_BT_TRANSPORT_STATE_PENDING || this->is_duplex) res = transport_start(this); @@ -965,6 +968,7 @@ return -EIO; if ((res = this->codec->enum_config(this->codec, + this->is_duplex ? 0 : A2DP_CODEC_FLAG_SINK, this->transport->configuration, this->transport->configuration_len, id, result.index, &b, ¶m)) != 1) @@ -1341,8 +1345,8 @@ spa_return_val_if_fail(this != NULL, -EINVAL); port = &this->port; - io = port->io; - spa_return_val_if_fail(io != NULL, -EIO); + if ((io = port->io) == NULL) + return -EIO; spa_log_trace(this->log, "%p status:%d", this, io->status); @@ -1575,9 +1579,11 @@ this->codec = this->codec->duplex_codec; this->is_input = true; } + this->use_duplex_source = this->is_duplex || (this->codec->duplex_codec != NULL); if (this->codec->init_props != NULL) this->codec_props = this->codec->init_props(this->codec, + this->is_duplex ? 0 : A2DP_CODEC_FLAG_SINK, this->transport->device->settings); spa_bt_transport_add_listener(this->transport, @@ -1586,7 +1592,7 @@ this->timerfd = spa_system_timerfd_create(this->data_system, CLOCK_MONOTONIC, SPA_FD_CLOEXEC | SPA_FD_NONBLOCK); - if (this->is_duplex) { + if (this->use_duplex_source) { this->duplex_timerfd = spa_system_timerfd_create(this->data_system, CLOCK_MONOTONIC, SPA_FD_CLOEXEC | SPA_FD_NONBLOCK); } else {
View file
pipewire-0.3.56.tar.gz/spa/plugins/bluez5/bluez-hardware.conf -> pipewire-0.3.57.tar.gz/spa/plugins/bluez5/bluez-hardware.conf
Changed
@@ -39,6 +39,7 @@ { name = "Motorola DC800", no-features = sbc-xq }, # #pipewire-1590 { name = "Motorola S305", no-features = sbc-xq }, # #pipewire-1590 { name = "Soundcore Life P2-L", no-features = msbc-alt1, msbc-alt1-rtl }, + { name = "Soundcore Motion B", no-features = hw-volume }, { name = "SoundCore mini", no-features = hw-volume }, # #pipewire-1686 { name = "SoundCore 2", no-features = sbc-xq }, # #pipewire-2291 { name = "Tribit MAXSound Plus", no-features = hw-volume }, # #pipewire-1592
View file
pipewire-0.3.56.tar.gz/spa/plugins/bluez5/bluez5-dbus.c -> pipewire-0.3.57.tar.gz/spa/plugins/bluez5/bluez5-dbus.c
Changed
@@ -125,6 +125,10 @@ struct spa_bt_quirks *quirks; +#define MAX_SETTINGS 128 + struct spa_dict_item global_setting_itemsMAX_SETTINGS; + struct spa_dict global_settings; + /* A reference audio info for A2DP codec configuration. */ struct a2dp_codec_audio_info default_audio_info; }; @@ -437,18 +441,21 @@ return 0; } -static const struct a2dp_codec *a2dp_endpoint_to_codec(struct spa_bt_monitor *monitor, const char *endpoint) +static const struct a2dp_codec *a2dp_endpoint_to_codec(struct spa_bt_monitor *monitor, const char *endpoint, bool *sink) { const char *ep_name; const struct a2dp_codec * const * const a2dp_codecs = monitor->a2dp_codecs; int i; - if (spa_strstartswith(endpoint, A2DP_SINK_ENDPOINT "/")) + if (spa_strstartswith(endpoint, A2DP_SINK_ENDPOINT "/")) { ep_name = endpoint + strlen(A2DP_SINK_ENDPOINT "/"); - else if (spa_strstartswith(endpoint, A2DP_SOURCE_ENDPOINT "/")) + *sink = true; + } else if (spa_strstartswith(endpoint, A2DP_SOURCE_ENDPOINT "/")) { ep_name = endpoint + strlen(A2DP_SOURCE_ENDPOINT "/"); - else + *sink = false; + } else { return NULL; + } for (i = 0; a2dp_codecsi; i++) { const struct a2dp_codec *codec = a2dp_codecsi; @@ -486,6 +493,7 @@ DBusError err; int i, size, res; const struct a2dp_codec *codec; + bool sink; dbus_error_init(&err); @@ -501,14 +509,15 @@ for (i = 0; i < size; i++) spa_log_debug(monitor->log, " %d: %02x", i, capi); - codec = a2dp_endpoint_to_codec(monitor, path); + codec = a2dp_endpoint_to_codec(monitor, path, &sink); if (codec != NULL) /* FIXME: We can't determine which device the SelectConfiguration() * call is associated with, therefore device settings are not passed. * This causes inconsistency with SelectConfiguration() triggered * by codec switching. */ - res = codec->select_config(codec, 0, cap, size, &monitor->default_audio_info, NULL, config); + res = codec->select_config(codec, sink ? A2DP_CODEC_FLAG_SINK : 0, cap, size, &monitor->default_audio_info, + &monitor->global_settings, config); else res = -ENOTSUP; @@ -1543,7 +1552,7 @@ return device->adapter && device->address; } -bool spa_bt_device_supports_a2dp_codec(struct spa_bt_device *device, const struct a2dp_codec *codec) +bool spa_bt_device_supports_a2dp_codec(struct spa_bt_device *device, const struct a2dp_codec *codec, bool sink) { struct spa_bt_monitor *monitor = device->monitor; struct spa_bt_remote_endpoint *ep; @@ -1579,15 +1588,22 @@ } spa_list_for_each(ep, &device->remote_endpoint_list, device_link) { + const enum spa_bt_profile profile = spa_bt_profile_from_uuid(ep->uuid); + const enum spa_bt_profile expected = sink ? + SPA_BT_PROFILE_A2DP_SINK : SPA_BT_PROFILE_A2DP_SOURCE; + + if (profile != expected) + continue; + if (a2dp_codec_check_caps(codec, ep->codec, ep->capabilities, ep->capabilities_len, - &ep->monitor->default_audio_info)) + &ep->monitor->default_audio_info, &monitor->global_settings)) return true; } return false; } -const struct a2dp_codec **spa_bt_device_get_supported_a2dp_codecs(struct spa_bt_device *device, size_t *count) +const struct a2dp_codec **spa_bt_device_get_supported_a2dp_codecs(struct spa_bt_device *device, size_t *count, bool sink) { struct spa_bt_monitor *monitor = device->monitor; const struct a2dp_codec * const * const a2dp_codecs = monitor->a2dp_codecs; @@ -1603,7 +1619,7 @@ j = 0; for (i = 0; a2dp_codecsi != NULL; ++i) { - if (spa_bt_device_supports_a2dp_codec(device, a2dp_codecsi)) { + if (spa_bt_device_supports_a2dp_codec(device, a2dp_codecsi, sink)) { supported_codecsj = a2dp_codecsi; ++j; } @@ -2511,7 +2527,7 @@ .set_volume = transport_set_volume, }; -static void append_basic_array_variant_dict_entry(DBusMessageIter *dict, int key_type_int, void* key, const char* variant_type_str, const char* array_type_str, int array_type_int, void* data, int data_size); +static void append_basic_array_variant_dict_entry(DBusMessageIter *dict, const char* key, const char* variant_type_str, const char* array_type_str, int array_type_int, void* data, int data_size); static void a2dp_codec_switch_reply(DBusPendingCall *pending, void *userdata); @@ -2569,10 +2585,10 @@ char *local_endpoint = NULL; int res, config_size; dbus_bool_t dbus_ret; - const char *str; DBusMessage *m; DBusMessageIter iter, d; int i; + bool sink; /* Try setting configuration for current codec on current endpoint in list */ @@ -2603,8 +2619,10 @@ if (sw->profile & SPA_BT_PROFILE_A2DP_SINK) { local_endpoint_base = A2DP_SOURCE_ENDPOINT; + sink = false; } else if (sw->profile & SPA_BT_PROFILE_A2DP_SOURCE) { local_endpoint_base = A2DP_SINK_ENDPOINT; + sink = true; } else { spa_log_debug(sw->device->monitor->log, "a2dp codec switch %p: bad profile (%d), try next", sw, sw->profile); @@ -2630,9 +2648,9 @@ } } - res = codec->select_config(codec, 0, ep->capabilities, ep->capabilities_len, + res = codec->select_config(codec, sink ? A2DP_CODEC_FLAG_SINK : 0, ep->capabilities, ep->capabilities_len, &sw->device->monitor->default_audio_info, - sw->device->settings, config); + &sw->device->monitor->global_settings, config); if (res < 0) { spa_log_debug(sw->device->monitor->log, "a2dp codec switch %p: incompatible capabilities (%d), try next", sw, res); @@ -2659,8 +2677,7 @@ dbus_message_iter_init_append(m, &iter); dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &local_endpoint); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &d); - str = "Capabilities"; - append_basic_array_variant_dict_entry(&d, DBUS_TYPE_STRING, &str, "ay", "y", DBUS_TYPE_BYTE, config, config_size); + append_basic_array_variant_dict_entry(&d, "Capabilities", "ay", "y", DBUS_TYPE_BYTE, config, config_size); dbus_message_iter_close_container(&iter, &d); spa_assert(sw->pending == NULL); @@ -2878,6 +2895,7 @@ const struct a2dp_codec *codec = *sw->codec_iter; const char *path1 = *(char **)a, *path2 = *(char **)b; struct spa_bt_remote_endpoint *ep1, *ep2; + uint32_t flags; ep1 = device_remote_endpoint_find(sw->device, path1); ep2 = device_remote_endpoint_find(sw->device, path2); @@ -2886,6 +2904,10 @@ ep1 = NULL; if (ep2 != NULL && (ep2->uuid == NULL || ep2->codec != codec->codec_id || ep2->capabilities == NULL)) ep2 = NULL; + if (ep1 && ep2 && !spa_streq(ep1->uuid, ep2->uuid)) { + ep1 = NULL; + ep2 = NULL; + } if (ep1 == NULL && ep2 == NULL) return 0; @@ -2894,8 +2916,11 @@ else if (ep2 == NULL) return -1; - return codec->caps_preference_cmp(codec, ep1->capabilities, ep1->capabilities_len, - ep2->capabilities, ep2->capabilities_len, &sw->device->monitor->default_audio_info); + flags = spa_streq(ep1->uuid, SPA_BT_UUID_A2DP_SOURCE) ? A2DP_CODEC_FLAG_SINK : 0; + + return codec->caps_preference_cmp(codec, flags, ep1->capabilities, ep1->capabilities_len, + ep2->capabilities, ep2->capabilities_len, &sw->device->monitor->default_audio_info, + &sw->device->monitor->global_settings); } /* Ensure there's a transport for at least one of the listed codecs */ @@ -2913,7 +2938,7 @@ } for (i = 0; codecsi != NULL; ++i) { - if (spa_bt_device_supports_a2dp_codec(device, codecsi)) { + if (spa_bt_device_supports_a2dp_codec(device, codecsi, true)) { preferred_codec = codecsi; break; } @@ -3031,6 +3056,7 @@ struct spa_bt_transport *transport; const struct a2dp_codec *codec; int profile; + bool sink; if (!dbus_message_has_signature(m, "oa{sv}")) { spa_log_warn(monitor->log, "invalid SetConfiguration() signature"); @@ -3039,7 +3065,7 @@ endpoint = dbus_message_get_path(m); profile = a2dp_endpoint_to_profile(endpoint); - codec = a2dp_endpoint_to_codec(monitor, endpoint); + codec = a2dp_endpoint_to_codec(monitor, endpoint, &sink); if (codec == NULL) { spa_log_warn(monitor->log, "unknown SetConfiguration() codec"); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; @@ -3100,7 +3126,7 @@ if (codec->validate_config) { struct spa_audio_info info; - if (codec->validate_config(codec, 0, + if (codec->validate_config(codec, sink ? A2DP_CODEC_FLAG_SINK : 0, transport->configuration, transport->configuration_len, &info) < 0) { spa_log_error(monitor->log, "invalid transport configuration"); @@ -3256,10 +3282,10 @@ dbus_pending_call_unref(pending); } -static void append_basic_variant_dict_entry(DBusMessageIter *dict, int key_type_int, void* key, int variant_type_int, const char* variant_type_str, void* variant) { +static void append_basic_variant_dict_entry(DBusMessageIter *dict, const char* key, int variant_type_int, const char* variant_type_str, void* variant) { DBusMessageIter dict_entry_it, variant_it; dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_it); - dbus_message_iter_append_basic(&dict_entry_it, key_type_int, key); + dbus_message_iter_append_basic(&dict_entry_it, DBUS_TYPE_STRING, &key); dbus_message_iter_open_container(&dict_entry_it, DBUS_TYPE_VARIANT, variant_type_str, &variant_it); dbus_message_iter_append_basic(&variant_it, variant_type_int, variant); @@ -3267,10 +3293,10 @@ dbus_message_iter_close_container(dict, &dict_entry_it); } -static void append_basic_array_variant_dict_entry(DBusMessageIter *dict, int key_type_int, void* key, const char* variant_type_str, const char* array_type_str, int array_type_int, void* data, int data_size) { +static void append_basic_array_variant_dict_entry(DBusMessageIter *dict, const char* key, const char* variant_type_str, const char* array_type_str, int array_type_int, void* data, int data_size) { DBusMessageIter dict_entry_it, variant_it, array_it; dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_it); - dbus_message_iter_append_basic(&dict_entry_it, key_type_int, key); + dbus_message_iter_append_basic(&dict_entry_it, DBUS_TYPE_STRING, &key); dbus_message_iter_open_container(&dict_entry_it, DBUS_TYPE_VARIANT, variant_type_str, &variant_it); dbus_message_iter_open_container(&variant_it, DBUS_TYPE_ARRAY, array_type_str, &array_it); @@ -3283,19 +3309,22 @@ static int bluez_register_endpoint(struct spa_bt_monitor *monitor, const char *path, const char *endpoint, const char *uuid, const struct a2dp_codec *codec) { - char *str, *object_path = NULL; + char *object_path = NULL; DBusMessage *m; DBusMessageIter object_it, dict_it; DBusPendingCall *call; uint8_t capsA2DP_MAX_CAPS_SIZE; int ret, caps_size; uint16_t codec_id = codec->codec_id; + bool sink; ret = a2dp_codec_to_endpoint(codec, endpoint, &object_path); if (ret < 0) goto error; - ret = caps_size = codec->fill_caps(codec, 0, caps); + sink = spa_streq(endpoint, A2DP_SINK_ENDPOINT); + + ret = caps_size = codec->fill_caps(codec, sink ? A2DP_CODEC_FLAG_SINK : 0, caps); if (ret < 0) goto error; @@ -3313,12 +3342,9 @@ dbus_message_iter_open_container(&object_it, DBUS_TYPE_ARRAY, "{sv}", &dict_it); - str = "UUID"; - append_basic_variant_dict_entry(&dict_it, DBUS_TYPE_STRING, &str, DBUS_TYPE_STRING, "s", &uuid); - str = "Codec"; - append_basic_variant_dict_entry(&dict_it, DBUS_TYPE_STRING, &str, DBUS_TYPE_BYTE, "y", &codec_id); - str = "Capabilities"; - append_basic_array_variant_dict_entry(&dict_it, DBUS_TYPE_STRING, &str, "ay", "y", DBUS_TYPE_BYTE, caps, caps_size); + append_basic_variant_dict_entry(&dict_it,"UUID", DBUS_TYPE_STRING, "s", &uuid); + append_basic_variant_dict_entry(&dict_it, "Codec", DBUS_TYPE_BYTE, "y", &codec_id); + append_basic_array_variant_dict_entry(&dict_it, "Capabilities", "ay", "y", DBUS_TYPE_BYTE, caps, caps_size); dbus_message_iter_close_container(&object_it, &dict_it); @@ -3422,7 +3448,6 @@ static void append_a2dp_object(DBusMessageIter *iter, const char *endpoint, const char *uuid, uint8_t codec_id, uint8_t *caps, size_t caps_size) { - char* str; const char *interface_name = BLUEZ_MEDIA_ENDPOINT_INTERFACE; DBusMessageIter object, array, entry, dict; dbus_bool_t delay_reporting; @@ -3437,16 +3462,12 @@ dbus_message_iter_open_container(&entry, DBUS_TYPE_ARRAY, "{sv}", &dict); - str = "UUID"; - append_basic_variant_dict_entry(&dict, DBUS_TYPE_STRING, &str, DBUS_TYPE_STRING, "s", &uuid); - str = "Codec"; - append_basic_variant_dict_entry(&dict, DBUS_TYPE_STRING, &str, DBUS_TYPE_BYTE, "y", &codec_id); - str = "Capabilities"; - append_basic_array_variant_dict_entry(&dict, DBUS_TYPE_STRING, &str, "ay", "y", DBUS_TYPE_BYTE, caps, caps_size); + append_basic_variant_dict_entry(&dict, "UUID", DBUS_TYPE_STRING, "s", &uuid); + append_basic_variant_dict_entry(&dict, "Codec", DBUS_TYPE_BYTE, "y", &codec_id); + append_basic_array_variant_dict_entry(&dict, "Capabilities", "ay", "y", DBUS_TYPE_BYTE, caps, caps_size); if (spa_bt_profile_from_uuid(uuid) & SPA_BT_PROFILE_A2DP_SOURCE) { - str = "DelayReporting"; delay_reporting = TRUE; - append_basic_variant_dict_entry(&dict, DBUS_TYPE_STRING, &str, DBUS_TYPE_BOOLEAN, "b", &delay_reporting); + append_basic_variant_dict_entry(&dict, "DelayReporting", DBUS_TYPE_BOOLEAN, "b", &delay_reporting); } dbus_message_iter_close_container(&entry, &dict); @@ -3501,11 +3522,11 @@ if (!is_a2dp_codec_enabled(monitor, codec)) continue; - caps_size = codec->fill_caps(codec, 0, caps); - if (caps_size < 0) - continue; - if (codec->decode != NULL) { + caps_size = codec->fill_caps(codec, A2DP_CODEC_FLAG_SINK, caps); + if (caps_size < 0) + continue; + ret = a2dp_codec_to_endpoint(codec, A2DP_SINK_ENDPOINT, &endpoint); if (ret == 0) { spa_log_info(monitor->log, "register A2DP sink codec %s: %s", a2dp_codecsi->name, endpoint); @@ -3516,6 +3537,10 @@ } if (codec->encode != NULL) { + caps_size = codec->fill_caps(codec, 0, caps); + if (caps_size < 0) + continue; + ret = a2dp_codec_to_endpoint(codec, A2DP_SOURCE_ENDPOINT, &endpoint); if (ret == 0) { spa_log_info(monitor->log, "register A2DP source codec %s: %s", a2dp_codecsi->name, endpoint); @@ -4286,6 +4311,7 @@ struct spa_bt_device *d; struct spa_bt_remote_endpoint *ep; struct spa_bt_transport *t; + const struct spa_dict_item *it; size_t i; monitor = (struct spa_bt_monitor *) handle; @@ -4317,6 +4343,11 @@ monitor->backendsi = NULL; } + spa_dict_for_each(it, &monitor->global_settings) { + free((void *)it->key); + free((void *)it->value); + } + free((void*)monitor->enabled_codecs.items); spa_zero(monitor->enabled_codecs); @@ -4453,6 +4484,26 @@ return 0; } +static void get_global_settings(struct spa_bt_monitor *this, const struct spa_dict *dict) +{ + uint32_t n_items = 0; + uint32_t i; + + if (dict == NULL) { + this->global_settings = SPA_DICT_INIT(this->global_setting_items, 0); + return; + } + + for (i = 0; i < dict->n_items && n_items < SPA_N_ELEMENTS(this->global_setting_items); i++) { + const struct spa_dict_item *it = &dict->itemsi; + if (spa_strstartswith(it->key, "bluez5.") && it->value != NULL) + this->global_setting_itemsn_items++ = + SPA_DICT_ITEM_INIT(strdup(it->key), strdup(it->value)); + } + + this->global_settings = SPA_DICT_INIT(this->global_setting_items, n_items); +} + static int impl_init(const struct spa_handle_factory *factory, struct spa_handle *handle, @@ -4546,6 +4597,8 @@ this->backend_selection = BACKEND_NATIVE; + get_global_settings(this, info); + if (info) { const char *str; uint32_t tmp;
View file
pipewire-0.3.56.tar.gz/spa/plugins/bluez5/bluez5-device.c -> pipewire-0.3.57.tar.gz/spa/plugins/bluez5/bluez5-device.c
Changed
@@ -301,6 +301,8 @@ static float get_soft_volume_boost(struct node *node) { + const struct a2dp_codec *codec = node->transport ? node->transport->a2dp_codec : NULL; + /* * For A2DP duplex, the duplex microphone channel sometimes does not appear * to have hardware gain, and input volume is very low. @@ -310,7 +312,8 @@ * If this causes clipping, the user can just reduce the mic volume to * bring SW gain below 1. */ - if (node->a2dp_duplex && node->transport && + if (node->a2dp_duplex && node->transport && codec && codec->info && + spa_atob(spa_dict_lookup(codec->info, "duplex.boost")) && node->id == DEVICE_ID_SOURCE && !node->transport->volumesSPA_BT_VOLUME_ID_RX.active) return 10.0f; /* 20 dB boost */ @@ -912,7 +915,7 @@ if (this->bt_dev->connected_profiles & SPA_BT_PROFILE_A2DP_SINK) { free(this->supported_codecs); this->supported_codecs = spa_bt_device_get_supported_a2dp_codecs( - this->bt_dev, &this->supported_codec_count); + this->bt_dev, &this->supported_codec_count, true); } switch (this->profile) { @@ -1127,7 +1130,7 @@ if (this->supported_codecs) free(this->supported_codecs); this->supported_codecs = spa_bt_device_get_supported_a2dp_codecs( - this->bt_dev, &this->supported_codec_count); + this->bt_dev, &this->supported_codec_count, true); /* Prefer A2DP, then HFP, then null, but select AG if the device appears not to have A2DP_SINK or any HEAD_UNIT profile */
View file
pipewire-0.3.56.tar.gz/spa/plugins/bluez5/codec-loader.c -> pipewire-0.3.57.tar.gz/spa/plugins/bluez5/codec-loader.c
Changed
@@ -63,6 +63,11 @@ SPA_BLUETOOTH_AUDIO_CODEC_APTX_LL_DUPLEX, SPA_BLUETOOTH_AUDIO_CODEC_FASTSTREAM, SPA_BLUETOOTH_AUDIO_CODEC_FASTSTREAM_DUPLEX, + SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05, + SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_51, + SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_71, + SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_DUPLEX, + SPA_BLUETOOTH_AUDIO_CODEC_OPUS_05_PRO, }; size_t i; for (i = 0; i < SPA_N_ELEMENTS(order); ++i) @@ -138,6 +143,9 @@ spa_log_debug(impl->log, "loaded A2DP codec %s from %s", c->name, factory_name); + if (c->set_log) + c->set_log(impl->log); + impl->codecsimpl->n_codecs++ = c; ++n_codecs; @@ -171,7 +179,8 @@ A2DP_CODEC_FACTORY_LIB("faststream"), A2DP_CODEC_FACTORY_LIB("ldac"), A2DP_CODEC_FACTORY_LIB("sbc"), - A2DP_CODEC_FACTORY_LIB("lc3plus") + A2DP_CODEC_FACTORY_LIB("lc3plus"), + A2DP_CODEC_FACTORY_LIB("opus") #undef A2DP_CODEC_FACTORY_LIB };
View file
pipewire-0.3.56.tar.gz/spa/plugins/bluez5/decode-buffer.h -> pipewire-0.3.57.tar.gz/spa/plugins/bluez5/decode-buffer.h
Changed
@@ -389,7 +389,8 @@ static void spa_bt_decode_buffer_process(struct spa_bt_decode_buffer *this, uint32_t samples, uint32_t duration) { const uint32_t data_size = samples * this->frame_size; - const int32_t max_level = SPA_MAX(8 * this->packet_size.max, (int32_t)duration); + const int32_t packet_size = SPA_CLAMP(this->packet_size.max, 0, INT32_MAX/8); + const int32_t max_level = SPA_MAX(8 * packet_size, (int32_t)duration); uint32_t avail; if (SPA_UNLIKELY(duration != this->prev_duration)) { @@ -405,8 +406,8 @@ spa_log_trace(this->log, "%p buffering size:%d", this, (int)size); if (this->received && - this->packet_size.max > 0 && - size >= SPA_MAX(3*this->packet_size.max, (int32_t)duration)) + packet_size > 0 && + size >= SPA_MAX(3*packet_size, (int32_t)duration)) this->buffering = false; else return; @@ -428,7 +429,7 @@ spa_bt_ptp_update(&this->spike, this->ctl.avg - level, this->prev_consumed); /* Update target level */ - target = BUFFERING_TARGET(this->spike.max, this->packet_size.max); + target = BUFFERING_TARGET(this->spike.max, packet_size); if (level > SPA_MAX(4 * target, 2*(int32_t)duration) && avail > data_size) {
View file
pipewire-0.3.56.tar.gz/spa/plugins/bluez5/defs.h -> pipewire-0.3.57.tar.gz/spa/plugins/bluez5/defs.h
Changed
@@ -134,13 +134,13 @@ #define BLUEZ_ERROR_NOT_SUPPORTED "org.bluez.Error.NotSupported" -#define SPA_BT_UUID_A2DP_SOURCE "0000110A-0000-1000-8000-00805F9B34FB" -#define SPA_BT_UUID_A2DP_SINK "0000110B-0000-1000-8000-00805F9B34FB" -#define SPA_BT_UUID_HSP_HS "00001108-0000-1000-8000-00805F9B34FB" -#define SPA_BT_UUID_HSP_HS_ALT "00001131-0000-1000-8000-00805F9B34FB" -#define SPA_BT_UUID_HSP_AG "00001112-0000-1000-8000-00805F9B34FB" -#define SPA_BT_UUID_HFP_HF "0000111E-0000-1000-8000-00805F9B34FB" -#define SPA_BT_UUID_HFP_AG "0000111F-0000-1000-8000-00805F9B34FB" +#define SPA_BT_UUID_A2DP_SOURCE "0000110a-0000-1000-8000-00805f9b34fb" +#define SPA_BT_UUID_A2DP_SINK "0000110b-0000-1000-8000-00805f9b34fb" +#define SPA_BT_UUID_HSP_HS "00001108-0000-1000-8000-00805f9b34fb" +#define SPA_BT_UUID_HSP_HS_ALT "00001131-0000-1000-8000-00805f9b34fb" +#define SPA_BT_UUID_HSP_AG "00001112-0000-1000-8000-00805f9b34fb" +#define SPA_BT_UUID_HFP_HF "0000111e-0000-1000-8000-00805f9b34fb" +#define SPA_BT_UUID_HFP_AG "0000111f-0000-1000-8000-00805f9b34fb" #define PROFILE_HSP_AG "/Profile/HSPAG" #define PROFILE_HSP_HS "/Profile/HSPHS" @@ -490,8 +490,8 @@ int spa_bt_device_connect_profile(struct spa_bt_device *device, enum spa_bt_profile profile); int spa_bt_device_check_profiles(struct spa_bt_device *device, bool force); int spa_bt_device_ensure_a2dp_codec(struct spa_bt_device *device, const struct a2dp_codec * const *codecs); -bool spa_bt_device_supports_a2dp_codec(struct spa_bt_device *device, const struct a2dp_codec *codec); -const struct a2dp_codec **spa_bt_device_get_supported_a2dp_codecs(struct spa_bt_device *device, size_t *count); +bool spa_bt_device_supports_a2dp_codec(struct spa_bt_device *device, const struct a2dp_codec *codec, bool sink); +const struct a2dp_codec **spa_bt_device_get_supported_a2dp_codecs(struct spa_bt_device *device, size_t *count, bool sink); int spa_bt_device_ensure_hfp_codec(struct spa_bt_device *device, unsigned int codec); int spa_bt_device_supports_hfp_codec(struct spa_bt_device *device, unsigned int codec); int spa_bt_device_release_transports(struct spa_bt_device *device);
View file
pipewire-0.3.56.tar.gz/spa/plugins/bluez5/meson.build -> pipewire-0.3.57.tar.gz/spa/plugins/bluez5/meson.build
Changed
@@ -111,8 +111,6 @@ endif if get_option('bluez5-codec-lc3plus').allowed() and lc3plus_dep.found() - lc3plus_args = codec_args - lc3plus_dep = lc3plus_dep bluez_codec_lc3plus = shared_library('spa-codec-bluez5-lc3plus', 'a2dp-codec-lc3plus.c', 'a2dp-codecs.c' , include_directories : configinc , @@ -121,3 +119,15 @@ install : true, install_dir : spa_plugindir / 'bluez5') endif + +if get_option('bluez5-codec-opus').allowed() and opus_dep.found() + opus_args = codec_args + opus_dep = opus_dep + bluez_codec_opus = shared_library('spa-codec-bluez5-opus', + 'a2dp-codec-opus.c', 'a2dp-codecs.c' , + include_directories : configinc , + c_args : opus_args, + dependencies : spa_dep, opus_dep, mathlib , + install : true, + install_dir : spa_plugindir / 'bluez5') +endif
View file
pipewire-0.3.56.tar.gz/spa/plugins/bluez5/sco-sink.c -> pipewire-0.3.57.tar.gz/spa/plugins/bluez5/sco-sink.c
Changed
@@ -1147,8 +1147,8 @@ spa_return_val_if_fail(this != NULL, -EINVAL); port = &this->port; - io = port->io; - spa_return_val_if_fail(io != NULL, -EIO); + if ((io = port->io) == NULL) + return -EIO; if (io->status == SPA_STATUS_HAVE_DATA && io->buffer_id < port->n_buffers) { struct buffer *b = &port->buffersio->buffer_id;
View file
pipewire-0.3.56.tar.gz/spa/plugins/bluez5/sco-source.c -> pipewire-0.3.57.tar.gz/spa/plugins/bluez5/sco-source.c
Changed
@@ -542,6 +542,15 @@ return 0; } + if (size_read % port->frame_size != 0) { + /* Unaligned data: reception or adapter problem. + * Consider the whole packet lost and report. + */ + spa_log_debug(this->log, + "received bad Bluetooth SCO CVSD packet"); + return 0; + } + packet = spa_bt_decode_buffer_get_write(&port->buffer, &avail); avail = SPA_MIN(avail, (uint32_t)size_read); spa_memmove(packet, read_data, avail); @@ -1286,8 +1295,8 @@ spa_return_val_if_fail(this != NULL, -EINVAL); port = &this->port; - io = port->io; - spa_return_val_if_fail(io != NULL, -EIO); + if ((io = port->io) == NULL) + return -EIO; /* Return if we already have a buffer */ if (io->status == SPA_STATUS_HAVE_DATA)
View file
pipewire-0.3.56.tar.gz/spa/plugins/control/mixer.c -> pipewire-0.3.57.tar.gz/spa/plugins/control/mixer.c
Changed
@@ -587,8 +587,8 @@ spa_return_val_if_fail(this != NULL, -EINVAL); outport = GET_OUT_PORT(this, 0); - outio = outport->io; - spa_return_val_if_fail(outio != NULL, -EIO); + if ((outio = outport->io) == NULL) + return -EIO; spa_log_trace_fp(this->log, NAME " %p: status %p %d %d", this, outio, outio->status, outio->buffer_id);
View file
pipewire-0.3.56.tar.gz/spa/plugins/libcamera/libcamera-device.cpp -> pipewire-0.3.57.tar.gz/spa/plugins/libcamera/libcamera-device.cpp
Changed
@@ -78,35 +78,32 @@ std::shared_ptr<Camera> camera; }; -std::string cameraModel(const Camera *camera) +static std::string cameraModel(const Camera *camera) { const ControlList &props = camera->properties(); - std::string name; - if (props.contains(properties::Model)) - name = props.get(properties::Model); - else - name = camera->id(); - return name; + + if (auto model = props.get(properties::Model)) + return std::move(model.value()); + + return camera->id(); } -std::string cameraLoc(const Camera *camera) +static const char *cameraLoc(const Camera *camera) { const ControlList &props = camera->properties(); - std::string location; - if (props.contains(properties::Location)) { - switch (props.get(properties::Location)) { + + if (auto location = props.get(properties::Location)) { + switch (location.value()) { case properties::CameraLocationFront: - location = "front"; - break; + return "front"; case properties::CameraLocationBack: - location = "back"; - break; + return "back"; case properties::CameraLocationExternal: - location = "external"; - break; + return "external"; } } - return location; + + return nullptr; } static int emit_info(struct impl *impl, bool full) @@ -116,7 +113,7 @@ uint32_t n_items = 0; struct spa_device_info info; struct spa_param_info params2; - char path256, location10, model256, name256; + char path256, model256, name256; info = SPA_DEVICE_INFO_INIT(); @@ -127,9 +124,11 @@ ADD_ITEM(SPA_KEY_OBJECT_PATH, path); ADD_ITEM(SPA_KEY_DEVICE_API, "libcamera"); ADD_ITEM(SPA_KEY_MEDIA_CLASS, "Video/Device"); - ADD_ITEM(SPA_KEY_API_LIBCAMERA_PATH, (char *)impl->props.device); - snprintf(location, sizeof(location), "%s", cameraLoc(impl->camera.get()).c_str()); - ADD_ITEM(SPA_KEY_API_LIBCAMERA_LOCATION, location); + ADD_ITEM(SPA_KEY_API_LIBCAMERA_PATH, impl->props.device); + + 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);
View file
pipewire-0.3.56.tar.gz/spa/plugins/libcamera/libcamera-source.cpp -> pipewire-0.3.57.tar.gz/spa/plugins/libcamera/libcamera-source.cpp
Changed
@@ -823,8 +823,8 @@ spa_return_val_if_fail(impl != NULL, -EINVAL); port = GET_OUT_PORT(impl, 0); - io = port->io; - spa_return_val_if_fail(io != NULL, -EIO); + if ((io = port->io) == NULL) + return -EIO; if (port->control) process_control(impl, &port->control->sequence);
View file
pipewire-0.3.56.tar.gz/spa/plugins/meson.build -> pipewire-0.3.57.tar.gz/spa/plugins/meson.build
Changed
@@ -1,7 +1,7 @@ if alsa_dep.found() subdir('alsa') endif -if get_option('avb').allowed() +if get_option('avb').require(host_machine.system() == 'linux', error_message: 'AVB support is only available on Linux').allowed() subdir('avb') endif if get_option('audioconvert').allowed() @@ -55,4 +55,4 @@ subdir('libcamera') endif -subdir('aec') \ No newline at end of file +subdir('aec')
View file
pipewire-0.3.56.tar.gz/spa/plugins/support/loop.c -> pipewire-0.3.57.tar.gz/spa/plugins/support/loop.c
Changed
@@ -350,6 +350,7 @@ if (--impl->enter_count == 0) { impl->thread = 0; + flush_items(impl); impl->polling = false; } }
View file
pipewire-0.3.56.tar.gz/spa/plugins/support/null-audio-sink.c -> pipewire-0.3.57.tar.gz/spa/plugins/support/null-audio-sink.c
Changed
@@ -737,9 +737,8 @@ spa_return_val_if_fail(this != NULL, -EINVAL); port = &this->port; - - io = port->io; - spa_return_val_if_fail(io != NULL, -EIO); + if ((io = port->io) == NULL) + return -EIO; if (io->status != SPA_STATUS_HAVE_DATA) return io->status;
View file
pipewire-0.3.56.tar.gz/spa/plugins/test/fakesink.c -> pipewire-0.3.57.tar.gz/spa/plugins/test/fakesink.c
Changed
@@ -639,9 +639,8 @@ spa_return_val_if_fail(this != NULL, -EINVAL); port = &this->port; - - io = port->io; - spa_return_val_if_fail(io != NULL, -EIO); + if ((io = port->io) == NULL) + return -EIO; if (io->status == SPA_STATUS_HAVE_DATA && io->buffer_id < port->n_buffers) { struct buffer *b = &port->buffersio->buffer_id;
View file
pipewire-0.3.56.tar.gz/spa/plugins/test/fakesrc.c -> pipewire-0.3.57.tar.gz/spa/plugins/test/fakesrc.c
Changed
@@ -680,8 +680,8 @@ spa_return_val_if_fail(this != NULL, -EINVAL); port = &this->port; - io = port->io; - spa_return_val_if_fail(io != NULL, -EIO); + if ((io = port->io) == NULL) + return -EIO; if (io->status == SPA_STATUS_HAVE_DATA) return SPA_STATUS_HAVE_DATA;
View file
pipewire-0.3.56.tar.gz/spa/plugins/v4l2/v4l2-source.c -> pipewire-0.3.57.tar.gz/spa/plugins/v4l2/v4l2-source.c
Changed
@@ -879,8 +879,8 @@ spa_return_val_if_fail(this != NULL, -EINVAL); port = GET_OUT_PORT(this, 0); - io = port->io; - spa_return_val_if_fail(io != NULL, -EIO); + if ((io = port->io) == NULL) + return -EIO; if (port->control) process_control(this, &port->control->sequence);
View file
pipewire-0.3.56.tar.gz/spa/plugins/videotestsrc/videotestsrc.c -> pipewire-0.3.57.tar.gz/spa/plugins/videotestsrc/videotestsrc.c
Changed
@@ -787,8 +787,8 @@ spa_return_val_if_fail(this != NULL, -EINVAL); port = &this->port; - io = port->io; - spa_return_val_if_fail(io != NULL, -EIO); + if ((io = port->io) == NULL) + return -EIO; if (io->status == SPA_STATUS_HAVE_DATA) return SPA_STATUS_HAVE_DATA;
View file
pipewire-0.3.56.tar.gz/spa/plugins/volume/volume.c -> pipewire-0.3.57.tar.gz/spa/plugins/volume/volume.c
Changed
@@ -679,8 +679,8 @@ spa_return_val_if_fail(this != NULL, -EINVAL); out_port = GET_OUT_PORT(this, 0); - output = out_port->io; - spa_return_val_if_fail(output != NULL, -EIO); + if ((output = out_port->io) == NULL) + return -EIO; if (output->status == SPA_STATUS_HAVE_DATA) return SPA_STATUS_HAVE_DATA; @@ -692,8 +692,8 @@ } in_port = GET_IN_PORT(this, 0); - input = in_port->io; - spa_return_val_if_fail(input != NULL, -EIO); + if ((input = in_port->io) == NULL) + return -EIO; if (input->status != SPA_STATUS_HAVE_DATA) return SPA_STATUS_NEED_DATA;
View file
pipewire-0.3.56.tar.gz/spa/plugins/vulkan/vulkan-compute-filter.c -> pipewire-0.3.57.tar.gz/spa/plugins/vulkan/vulkan-compute-filter.c
Changed
@@ -578,8 +578,8 @@ spa_return_val_if_fail(this != NULL, -EINVAL); inport = &this->portSPA_DIRECTION_INPUT; - inio = inport->io; - spa_return_val_if_fail(inio != NULL, -EIO); + if ((inio = inport->io) == NULL) + return -EIO; if (inio->status != SPA_STATUS_HAVE_DATA) return inio->status; @@ -590,8 +590,8 @@ } outport = &this->portSPA_DIRECTION_OUTPUT; - outio = outport->io; - spa_return_val_if_fail(outio != NULL, -EIO); + if ((outio = outport->io) == NULL) + return -EIO; if (outio->status == SPA_STATUS_HAVE_DATA) return SPA_STATUS_HAVE_DATA;
View file
pipewire-0.3.56.tar.gz/spa/plugins/vulkan/vulkan-compute-source.c -> pipewire-0.3.57.tar.gz/spa/plugins/vulkan/vulkan-compute-source.c
Changed
@@ -802,8 +802,8 @@ spa_return_val_if_fail(this != NULL, -EINVAL); port = &this->port; - io = port->io; - spa_return_val_if_fail(io != NULL, -EIO); + if ((io = port->io) == NULL) + return -EIO; if (io->status == SPA_STATUS_HAVE_DATA) return SPA_STATUS_HAVE_DATA;
View file
pipewire-0.3.57.tar.gz/src/daemon/systemd/user/filter-chain.service.in
Added
@@ -0,0 +1,21 @@ +Unit +Description=PipeWire filter chain daemon + +After=pipewire.service pipewire-session-manager.service +BindsTo=pipewire.service + +Service +LockPersonality=yes +MemoryDenyWriteExecute=yes +NoNewPrivileges=yes +RestrictNamespaces=yes +SystemCallArchitectures=native +SystemCallFilter=@system-service +Type=simple +ExecStart=@PW_BINARY@ -c filter-chain.conf +Restart=on-failure +Slice=session.slice + +Install +Also=pipewire.socket +WantedBy=default.target
View file
pipewire-0.3.56.tar.gz/src/daemon/systemd/user/meson.build -> pipewire-0.3.57.tar.gz/src/daemon/systemd/user/meson.build
Changed
@@ -20,3 +20,8 @@ output : 'pipewire-pulse.service', configuration : systemd_config, install_dir : systemd_user_services_dir) + +configure_file(input : 'filter-chain.service.in', + output : 'filter-chain.service', + configuration : systemd_config, + install_dir : systemd_user_services_dir)
View file
pipewire-0.3.56.tar.gz/src/gst/gstpipewiresrc.c -> pipewire-0.3.57.tar.gz/src/gst/gstpipewiresrc.c
Changed
@@ -568,19 +568,23 @@ meta->height = crop->region.size.height; } } - gst_buffer_add_parent_buffer_meta (buf, data->buf); - gst_buffer_unref (data->buf); for (i = 0; i < b->buffer->n_datas; i++) { struct spa_data *d = &b->buffer->datasi; GstMemory *pmem = gst_buffer_peek_memory (data->buf, i); if (pmem) { - GstMemory *mem = gst_memory_share (pmem, d->chunk->offset, d->chunk->size); + GstMemory *mem; + if (!pwsrc->always_copy) + mem = gst_memory_share (pmem, d->chunk->offset, d->chunk->size); + else + mem = gst_memory_copy (pmem, d->chunk->offset, d->chunk->size); gst_buffer_insert_memory (buf, i, mem); - spa_assert_se(mem->size <= mem->maxsize); } if (d->chunk->flags & SPA_CHUNK_FLAG_CORRUPTED) GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_CORRUPTED); } + if (!pwsrc->always_copy) + gst_buffer_add_parent_buffer_meta (buf, data->buf); + gst_buffer_unref (data->buf); return buf; } @@ -1091,12 +1095,7 @@ } pw_thread_loop_unlock (pwsrc->core->loop); - if (pwsrc->always_copy) { - *buffer = gst_buffer_copy_deep (buf); - gst_buffer_unref (buf); - } - else - *buffer = buf; + *buffer = buf; if (pwsrc->is_live) base_time = GST_ELEMENT_CAST (psrc)->base_time;
View file
pipewire-0.3.57.tar.gz/src/modules/flatpak-utils.h
Added
@@ -0,0 +1,156 @@ +/* PipeWire + * + * Copyright © 2018 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef FLATPAK_UTILS_H +#define FLATPAK_UTILS_H + +#include <stdio.h> +#include <string.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/stat.h> +#ifdef HAVE_SYS_VFS_H +#include <sys/vfs.h> +#endif + +#include "config.h" + +#ifdef HAVE_GLIB2 +#include <glib.h> +#endif + +#include <spa/utils/result.h> +#include <pipewire/log.h> + +static int pw_check_flatpak_parse_metadata(const char *buf, size_t size, char **app_id, char **devices) +{ +#ifdef HAVE_GLIB2 + /* + * See flatpak-metadata(5) + * + * The .flatpak-info file is in GLib key_file .ini format. + */ + g_autoptr(GKeyFile) metadata = NULL; + char *s; + + metadata = g_key_file_new(); + if (!g_key_file_load_from_data(metadata, buf, size, G_KEY_FILE_NONE, NULL)) + return -EINVAL; + + if (app_id) { + s = g_key_file_get_value(metadata, "Application", "name", NULL); + *app_id = s ? strdup(s) : NULL; + g_free(s); + } + + if (devices) { + s = g_key_file_get_value(metadata, "Context", "devices", NULL); + *devices = s ? strdup(s) : NULL; + g_free(s); + } + + return 0; +#else + return -ENOTSUP; +#endif +} + +static int pw_check_flatpak(pid_t pid, char **app_id, char **devices) +{ +#if defined(__linux__) + char root_path2048; + int root_fd, info_fd, res; + struct stat stat_buf; + + if (app_id) + *app_id = NULL; + if (devices) + *devices = NULL; + + snprintf(root_path, sizeof(root_path), "/proc/%d/root", (int)pid); + root_fd = openat (AT_FDCWD, root_path, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY); + if (root_fd == -1) { + res = -errno; + if (res == -EACCES) { + struct statfs buf; + /* Access to the root dir isn't allowed. This can happen if the root is on a fuse + * filesystem, such as in a toolbox container. We will never have a fuse rootfs + * in the flatpak case, so in that case its safe to ignore this and + * continue to detect other types of apps. */ + if (statfs(root_path, &buf) == 0 && + buf.f_type == 0x65735546) /* FUSE_SUPER_MAGIC */ + return 0; + } + /* Not able to open the root dir shouldn't happen. Probably the app died and + * we're failing due to /proc/$pid not existing. In that case fail instead + * of treating this as privileged. */ + pw_log_info("failed to open \"%s\": %s", root_path, spa_strerror(res)); + return res; + } + info_fd = openat (root_fd, ".flatpak-info", O_RDONLY | O_CLOEXEC | O_NOCTTY); + close (root_fd); + if (info_fd == -1) { + if (errno == ENOENT) { + pw_log_debug("no .flatpak-info, client on the host"); + /* No file => on the host */ + return 0; + } + res = -errno; + pw_log_error("error opening .flatpak-info: %m"); + return res; + } + if (fstat (info_fd, &stat_buf) != 0 || !S_ISREG (stat_buf.st_mode)) { + /* Some weird fd => failure, assume sandboxed */ + pw_log_error("error fstat .flatpak-info: %m"); + } else if (app_id || devices) { + /* Parse the application ID if needed */ + const size_t size = stat_buf.st_size; + + if (size > 0) { + void *buf = mmap(NULL, size, PROT_READ, MAP_PRIVATE, info_fd, 0); + if (buf != MAP_FAILED) { + res = pw_check_flatpak_parse_metadata(buf, size, app_id, devices); + munmap(buf, size); + } else { + res = -errno; + } + } else { + res = -EINVAL; + } + + if (res == -EINVAL) + pw_log_error("PID %d .flatpak-info file is malformed", + (int)pid); + else if (res < 0) + pw_log_error("PID %d .flatpak-info parsing failed: %s", + (int)pid, spa_strerror(res)); + } + close(info_fd); + return 1; +#else + return 0; +#endif +} + +#endif /* FLATPAK_UTILS_H */
View file
pipewire-0.3.56.tar.gz/src/modules/meson.build -> pipewire-0.3.57.tar.gz/src/modules/meson.build
Changed
@@ -33,12 +33,17 @@ 'module-x11-bell.c', +pipewire_module_access_deps = spa_dep, mathlib, dl_lib, pipewire_dep +if flatpak_support + pipewire_module_access_deps += glib2_dep +endif + pipewire_module_access = shared_library('pipewire-module-access', 'module-access.c' , include_directories : configinc, install : true, install_dir : modules_install_dir, install_rpath: modules_install_dir, - dependencies : spa_dep, mathlib, dl_lib, pipewire_dep, + dependencies : pipewire_module_access_deps ) pipewire_module_loopback = shared_library('pipewire-module-loopback', @@ -277,6 +282,10 @@ cdata.set('HAVE_AVAHI', true) endif +if flatpak_support + pipewire_module_protocol_pulse_deps += glib2_dep +endif + pipewire_module_protocol_pulse = shared_library('pipewire-module-protocol-pulse', pipewire_module_protocol_pulse_sources, include_directories : configinc, @@ -470,7 +479,7 @@ endif summary({'raop-sink (requires OpenSSL)': build_module_raop}, bool_yn: true, section: 'Optional Modules') -roc_lib = cc.find_library('roc', required: get_option('roc')) +roc_lib = cc.find_library('roc', has_headers: 'roc/config.h' , required: get_option('roc')) summary({'ROC': roc_lib.found()}, bool_yn: true, section: 'Streaming between daemons') build_module_roc = roc_lib.found() @@ -518,7 +527,7 @@ dependencies : mathlib, dl_lib, rt_lib, pipewire_dep, ) -build_module_avb = get_option('avb').allowed() +build_module_avb = get_option('avb').require(host_machine.system() == 'linux', error_message: 'AVB support is only available on Linux').allowed() if build_module_avb pipewire_module_avb = shared_library('pipewire-module-avb', 'module-avb.c',
View file
pipewire-0.3.56.tar.gz/src/modules/module-access.c -> pipewire-0.3.57.tar.gz/src/modules/module-access.c
Changed
@@ -46,6 +46,8 @@ #include <pipewire/impl.h> #include <pipewire/private.h> +#include "flatpak-utils.h" + /** \page page_module_access PipeWire Module: Access * * @@ -75,6 +77,9 @@ * on an external actor to update that property once permission is * granted or rejected. * + * For connections from applications running inside Flatpak not mediated + * by a portal, the `access` module itself sets the `pipewire.access.portal.app_id` + * property to the Flatpak application ID. * * ## Module Options * @@ -184,54 +189,6 @@ return res; } -#if defined(__linux__) -static int check_flatpak(struct pw_impl_client *client, int pid) -{ - char root_path2048; - int root_fd, info_fd, res; - struct stat stat_buf; - - sprintf(root_path, "/proc/%u/root", pid); - root_fd = openat (AT_FDCWD, root_path, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY); - if (root_fd == -1) { - res = -errno; - if (res == -EACCES) { - struct statfs buf; - /* Access to the root dir isn't allowed. This can happen if the root is on a fuse - * filesystem, such as in a toolbox container. We will never have a fuse rootfs - * in the flatpak case, so in that case its safe to ignore this and - * continue to detect other types of apps. */ - if (statfs(root_path, &buf) == 0 && - buf.f_type == 0x65735546) /* FUSE_SUPER_MAGIC */ - return 0; - } - /* Not able to open the root dir shouldn't happen. Probably the app died and - * we're failing due to /proc/$pid not existing. In that case fail instead - * of treating this as privileged. */ - pw_log_info("failed to open \"%s\": %s", root_path, spa_strerror(res)); - return res; - } - info_fd = openat (root_fd, ".flatpak-info", O_RDONLY | O_CLOEXEC | O_NOCTTY); - close (root_fd); - if (info_fd == -1) { - if (errno == ENOENT) { - pw_log_debug("no .flatpak-info, client on the host"); - /* No file => on the host */ - return 0; - } - res = -errno; - pw_log_error("error opening .flatpak-info: %m"); - return res; - } - if (fstat (info_fd, &stat_buf) != 0 || !S_ISREG (stat_buf.st_mode)) { - /* Some weird fd => failure, assume sandboxed */ - pw_log_error("error fstat .flatpak-info: %m"); - } - close(info_fd); - return 1; -} -#endif - static void context_check_access(void *data, struct pw_impl_client *client) { @@ -240,6 +197,8 @@ struct spa_dict_item items2; const struct pw_properties *props; const char *str, *access; + char *flatpak_app_id = NULL; + int nitems = 0; int pid, res; pid = -EINVAL; @@ -298,8 +257,7 @@ (access = pw_properties_get(impl->properties, "access.force")) != NULL) goto wait_permissions; -#if defined(__linux__) - res = check_flatpak(client, pid); + res = pw_check_flatpak(pid, &flatpak_app_id, NULL); if (res != 0) { if (res < 0) { if (res == -EACCES) { @@ -313,9 +271,11 @@ pw_log_debug(" %p: flatpak client %p added", impl, client); } access = "flatpak"; + itemsnitems++ = SPA_DICT_ITEM_INIT("pipewire.access.portal.app_id", + flatpak_app_id); goto wait_permissions; } -#endif + if ((access = pw_properties_get(props, PW_KEY_CLIENT_ACCESS)) == NULL) access = "unrestricted"; @@ -326,24 +286,28 @@ granted: pw_log_info("%p: client %p '%s' access granted", impl, client, access); - items0 = SPA_DICT_ITEM_INIT(PW_KEY_ACCESS, access); - pw_impl_client_update_properties(client, &SPA_DICT_INIT(items, 1)); + itemsnitems++ = SPA_DICT_ITEM_INIT(PW_KEY_ACCESS, access); + pw_impl_client_update_properties(client, &SPA_DICT_INIT(items, nitems)); permissions0 = PW_PERMISSION_INIT(PW_ID_ANY, PW_PERM_ALL); pw_impl_client_update_permissions(client, 1, permissions); - return; + goto done; wait_permissions: pw_log_info("%p: client %p wait for '%s' permissions", impl, client, access); - items0 = SPA_DICT_ITEM_INIT(PW_KEY_ACCESS, access); - pw_impl_client_update_properties(client, &SPA_DICT_INIT(items, 1)); - return; + itemsnitems++ = SPA_DICT_ITEM_INIT(PW_KEY_ACCESS, access); + pw_impl_client_update_properties(client, &SPA_DICT_INIT(items, nitems)); + goto done; rejected: pw_resource_error(pw_impl_client_get_core_resource(client), res, access); - items0 = SPA_DICT_ITEM_INIT(PW_KEY_ACCESS, access); - pw_impl_client_update_properties(client, &SPA_DICT_INIT(items, 1)); + itemsnitems++ = SPA_DICT_ITEM_INIT(PW_KEY_ACCESS, access); + pw_impl_client_update_properties(client, &SPA_DICT_INIT(items, nitems)); + goto done; + +done: + free(flatpak_app_id); return; }
View file
pipewire-0.3.56.tar.gz/src/modules/module-avb/aaf.h -> pipewire-0.3.57.tar.gz/src/modules/module-avb/aaf.h
Changed
@@ -35,7 +35,7 @@ unsigned gv:1; unsigned tv:1; - uint8_t seq_number; + uint8_t seq_num; unsigned _r2:7; unsigned tu:1;
View file
pipewire-0.3.56.tar.gz/src/modules/module-avb/iec61883.h -> pipewire-0.3.57.tar.gz/src/modules/module-avb/iec61883.h
Changed
@@ -37,7 +37,7 @@ unsigned gv:1; unsigned tv:1; - uint8_t seq_number; + uint8_t seq_num; unsigned _r2:7; unsigned tu:1;
View file
pipewire-0.3.56.tar.gz/src/modules/module-avb/maap.c -> pipewire-0.3.57.tar.gz/src/modules/module-avb/maap.c
Changed
@@ -421,7 +421,10 @@ maap->server = server; pw_log_info("0x%"PRIx64" %d", server->entity_id, server->ifindex); - pw_getrandom(maap->xsubi, sizeof(maap->xsubi), 0); + if (pw_getrandom(maap->xsubi, sizeof(maap->xsubi), 0) != sizeof(maap->xsubi)) { + res = -errno; + goto error_free; + } load_state(maap); maap->source = pw_loop_add_io(server->impl->loop, fd, SPA_IO_IN, true, on_socket_data, maap);
View file
pipewire-0.3.56.tar.gz/src/modules/module-client-node/remote-node.c -> pipewire-0.3.57.tar.gz/src/modules/module-client-node/remote-node.c
Changed
@@ -857,14 +857,8 @@ { struct link *link = user_data; struct spa_system *data_system = link->data->context->data_system; - struct timespec ts = { 0, 0 }; - - pw_log_trace_fp("link %p: signal", link); - - spa_system_clock_gettime(data_system, CLOCK_MONOTONIC, &ts); - link->target.activation->status = PW_NODE_ACTIVATION_TRIGGERED; - link->target.activation->signal_time = SPA_TIMESPEC_TO_NSEC(&ts); + pw_log_trace_fp("link %p: signal %p", link, link->target.activation); if (SPA_UNLIKELY(spa_system_eventfd_write(data_system, link->signalfd, 1) < 0)) pw_log_warn("link %p: write failed %m", link); @@ -930,7 +924,7 @@ link->map = mm; link->target.activation = ptr; link->signalfd = signalfd; - link->target.signal = link_signal_func; + link->target.signal_func = link_signal_func; link->target.data = link; link->target.node = NULL; spa_list_append(&data->links, &link->link);
View file
pipewire-0.3.56.tar.gz/src/modules/module-echo-cancel.c -> pipewire-0.3.57.tar.gz/src/modules/module-echo-cancel.c
Changed
@@ -993,8 +993,6 @@ goto error; } - (void)SPA_SUPPORT_INIT(SPA_TYPE_INTERFACE_AUDIO_AEC, (struct spa_audio_aec *)impl->aec); - pw_log_info("Using plugin AEC %s", impl->aec->name); if ((str = pw_properties_get(props, "aec.args")) != NULL)
View file
pipewire-0.3.56.tar.gz/src/modules/module-filter-chain/convolver.c -> pipewire-0.3.57.tar.gz/src/modules/module-filter-chain/convolver.c
Changed
@@ -232,9 +232,12 @@ fft_cpx_free(&conv->segmentsi); fft_cpx_free(&conv->segmentsIri); } - fft_destroy(conv->fft); - fft_destroy(conv->ifft); - fft_free(conv->fft_buffer); + if (conv->fft) + fft_destroy(conv->fft); + if (conv->ifft) + fft_destroy(conv->ifft); + if (conv->fft_buffer) + fft_free(conv->fft_buffer); free(conv->segments); free(conv->segmentsIr); fft_cpx_free(&conv->pre_mult);
View file
pipewire-0.3.56.tar.gz/src/modules/module-filter-chain/lv2_plugin.c -> pipewire-0.3.57.tar.gz/src/modules/module-filter-chain/lv2_plugin.c
Changed
@@ -37,9 +37,9 @@ #include <lilv/lilv.h> #include <lv2/lv2plug.in/ns/ext/atom/atom.h> #include <lv2/lv2plug.in/ns/ext/buf-size/buf-size.h> -#include "lv2/lv2plug.in/ns/ext/worker/worker.h" -#include "lv2/lv2plug.in/ns/ext/options/options.h" -#include "lv2/lv2plug.in/ns/ext/parameters/parameters.h" +#include <lv2/lv2plug.in/ns/ext/worker/worker.h> +#include <lv2/lv2plug.in/ns/ext/options/options.h> +#include <lv2/lv2plug.in/ns/ext/parameters/parameters.h> #include "plugin.h"
View file
pipewire-0.3.56.tar.gz/src/modules/module-protocol-native.c -> pipewire-0.3.57.tar.gz/src/modules/module-protocol-native.c
Changed
@@ -103,6 +103,11 @@ * - XDG_RUNTIME_DIR * - USERPROFILE * + * The socket address will be written into the notification file descriptor + * if the following environment variable is set: + * + * - PIPEWIRE_NOTIFICATION_FD + * * When a client connect, the connection will be made to: * * - PIPEWIRE_REMOTE : the environment with the remote name @@ -605,12 +610,15 @@ if (client == NULL) goto exit; - this = pw_impl_client_get_user_data(client); spa_list_append(&s->this.client_list, &this->protocol_link); this->server = s; this->client = client; + pw_map_init(&this->compat_v2.types, 0, 32); + + pw_impl_client_add_listener(client, &this->client_listener, &client_events, this); + this->source = pw_loop_add_io(pw_context_get_main_loop(context), fd, SPA_IO_ERR | SPA_IO_HUP, true, connection_data, this); @@ -625,15 +633,11 @@ goto cleanup_client; } - pw_map_init(&this->compat_v2.types, 0, 32); - pw_protocol_native_connection_add_listener(this->connection, &this->conn_listener, &server_conn_events, this); - pw_impl_client_add_listener(client, &this->client_listener, &client_events, this); - if ((res = pw_impl_client_register(client, NULL)) < 0) goto cleanup_client; @@ -761,6 +765,44 @@ } } +static int write_socket_address(struct server *s) +{ + long v; + int fd, res = 0; + char *endptr; + const char *env = getenv("PIPEWIRE_NOTIFICATION_FD"); + + if (env == NULL || env0 == '\0') + return 0; + + errno = 0; + v = strtol(env, &endptr, 10); + if (endptr0 != '\0') + errno = EINVAL; + if (errno != 0) { + res = -errno; + pw_log_error("server %p: strtol() failed with error: %m", s); + goto error; + } + fd = (int)v; + if (v != fd) { + res = -ERANGE; + pw_log_error("server %p: invalid fd %ld: %s", s, v, spa_strerror(res)); + goto error; + } + if (dprintf(fd, "%s\n", s->addr.sun_path) < 0) { + res = -errno; + pw_log_error("server %p: dprintf() failed with error: %m", s); + goto error; + } + close(fd); + unsetenv("PIPEWIRE_NOTIFICATION_FD"); + return 0; + +error: + return res; +} + static int add_socket(struct pw_protocol *protocol, struct server *s) { socklen_t size; @@ -815,6 +857,12 @@ } } + res = write_socket_address(s); + if (res < 0) { + pw_log_error("server %p: failed to write socket address: %s", s, + spa_strerror(res)); + goto error_close; + } s->activated = activated; s->loop = pw_context_get_main_loop(protocol->context); if (s->loop == NULL) { @@ -990,35 +1038,9 @@ goto done; } -static void on_client_connection_destroy(void *data) -{ - struct client *impl = data; - spa_hook_remove(&impl->conn_listener); -} - -static void on_client_need_flush(void *data) -{ - struct client *impl = data; - - pw_log_trace("need flush"); - impl->need_flush = true; - - if (impl->source && !(impl->source->mask & SPA_IO_OUT)) { - pw_loop_update_io(impl->context->main_loop, - impl->source, impl->source->mask | SPA_IO_OUT); - } -} - -static const struct pw_protocol_native_connection_events client_conn_events = { - PW_VERSION_PROTOCOL_NATIVE_CONNECTION_EVENTS, - .destroy = on_client_connection_destroy, - .need_flush = on_client_need_flush, -}; - static int impl_connect_fd(struct pw_protocol_client *client, int fd, bool do_close) { struct client *impl = SPA_CONTAINER_OF(client, struct client, this); - int res; impl->connected = false; impl->disconnecting = false; @@ -1028,23 +1050,10 @@ fd, SPA_IO_IN | SPA_IO_OUT | SPA_IO_HUP | SPA_IO_ERR, do_close, on_remote_data, impl); - if (impl->source == NULL) { - res = -errno; - goto error_cleanup; - } + if (impl->source == NULL) + return -errno; - pw_protocol_native_connection_add_listener(impl->connection, - &impl->conn_listener, - &client_conn_events, - impl); return 0; - -error_cleanup: - if (impl->connection) { - pw_protocol_native_connection_destroy(impl->connection); - impl->connection = NULL; - } - return res; } static void impl_disconnect(struct pw_protocol_client *client) @@ -1057,9 +1066,7 @@ pw_loop_destroy_source(impl->context->main_loop, impl->source); impl->source = NULL; - if (impl->connection) - pw_protocol_native_connection_destroy(impl->connection); - impl->connection = NULL; + pw_protocol_native_connection_set_fd(impl->connection, -1); } static void impl_destroy(struct pw_protocol_client *client) @@ -1068,6 +1075,10 @@ impl_disconnect(client); + if (impl->connection) + pw_protocol_native_connection_destroy(impl->connection); + impl->connection = NULL; + spa_list_remove(&client->link); client_unref(impl); } @@ -1134,6 +1145,31 @@ goto done; } +static void on_client_connection_destroy(void *data) +{ + struct client *impl = data; + spa_hook_remove(&impl->conn_listener); +} + +static void on_client_need_flush(void *data) +{ + struct client *impl = data; + + pw_log_trace("need flush"); + impl->need_flush = true; + + if (impl->source && !(impl->source->mask & SPA_IO_OUT)) { + pw_loop_update_io(impl->context->main_loop, + impl->source, impl->source->mask | SPA_IO_OUT); + } +} + +static const struct pw_protocol_native_connection_events client_conn_events = { + PW_VERSION_PROTOCOL_NATIVE_CONNECTION_EVENTS, + .destroy = on_client_connection_destroy, + .need_flush = on_client_need_flush, +}; + static struct pw_protocol_client * impl_new_client(struct pw_protocol *protocol, struct pw_core *core, @@ -1160,6 +1196,10 @@ res = -errno; goto error_free; } + pw_protocol_native_connection_add_listener(impl->connection, + &impl->conn_listener, + &client_conn_events, + impl); if (props) { str = spa_dict_lookup(props, PW_KEY_REMOTE_INTENTION);
View file
pipewire-0.3.56.tar.gz/src/modules/module-protocol-pulse/pulse-server.c -> pipewire-0.3.57.tar.gz/src/modules/module-protocol-pulse/pulse-server.c
Changed
@@ -668,15 +668,16 @@ attr->fragsize = SPA_ROUND_UP(attr->fragsize, frame_size); attr->fragsize = SPA_MAX(attr->fragsize, minfrag); - attr->tlength = attr->minreq = attr->prebuf = 0; + /* pulseaudio configures the source to half of the fragsize. It also + * immediately sends chunks to clients. Configure a 2/3 of the fragsize + * as the latency. */ + latency = attr->fragsize * 2 / 3; + + if (s->adjust_latency) + attr->fragsize = SPA_ROUND_UP(latency, frame_size); + + attr->tlength = attr->prebuf = 0; - if (s->early_requests) { - latency = attr->fragsize; - } else if (s->adjust_latency) { - latency = attr->fragsize; - } else { - latency = attr->fragsize; - } /* make sure can queue at least to fragsize without overruns */ if (attr->maxlength < attr->fragsize * 4) attr->maxlength = attr->fragsize * 4;
View file
pipewire-0.3.56.tar.gz/src/modules/module-protocol-pulse/server.c -> pipewire-0.3.57.tar.gz/src/modules/module-protocol-pulse/server.c
Changed
@@ -60,6 +60,7 @@ #include "server.h" #include "stream.h" #include "utils.h" +#include "flatpak-utils.h" #define LISTEN_BACKLOG 32 #define MAX_CLIENTS 64 @@ -417,14 +418,47 @@ client_access = server->client_access; if (server->addr.ss_family == AF_UNIX) { + char *app_id = NULL, *devices = NULL; + #ifdef SO_PRIORITY val = 6; if (setsockopt(client_fd, SOL_SOCKET, SO_PRIORITY, &val, sizeof(val)) < 0) pw_log_warn("setsockopt(SO_PRIORITY) failed: %m"); #endif pid = get_client_pid(client, client_fd); - if (pid != 0 && check_flatpak(client, pid) == 1) + if (pid != 0 && pw_check_flatpak(pid, &app_id, &devices) == 1) { + /* + * XXX: we should really use Portal client access here + * + * However, session managers currently support only camera + * permissions, and the XDG Portal doesn't have a "Sound Manager" + * permission defined. So for now, use access=flatpak, and determine + * extra permissions here. + * + * The application has access to the Pulseaudio socket, + * and with real PA it would always then have full sound access. + * We'll restrict the full access here behind devices=all; + * if the application can access all devices it can then + * also sound and camera devices directly, so granting also the + * Manager permissions here is reasonable. + * + * The "Manager" permission in any case is also currently not safe + * as the session manager does not check any permission store + * for it. + */ client_access = "flatpak"; + pw_properties_set(client->props, "pipewire.access.portal.app_id", + app_id); + + if (devices && (spa_streq(devices, "all") || + spa_strstartswith(devices, "all;") || + strstr(devices, ";all;"))) + pw_properties_set(client->props, PW_KEY_MEDIA_CATEGORY, "Manager"); + else + pw_properties_set(client->props, PW_KEY_MEDIA_CATEGORY, NULL); + } + free(devices); + free(app_id); } else if (server->addr.ss_family == AF_INET || server->addr.ss_family == AF_INET6) {
View file
pipewire-0.3.56.tar.gz/src/modules/module-pulse-tunnel.c -> pipewire-0.3.57.tar.gz/src/modules/module-pulse-tunnel.c
Changed
@@ -278,7 +278,7 @@ } else { float error, corr; - error = (float)(impl->current_latency) - (float)impl->target_latency; + error = (float)impl->target_latency - (float)impl->current_latency; error = SPA_CLAMP(error, -impl->max_error, impl->max_error); corr = spa_dll_update(&impl->dll, error); @@ -422,33 +422,47 @@ static void context_state_cb(pa_context *c, void *userdata) { struct impl *impl = userdata; + bool do_destroy = false; switch (pa_context_get_state(c)) { - case PA_CONTEXT_READY: case PA_CONTEXT_TERMINATED: case PA_CONTEXT_FAILED: + do_destroy = true; + SPA_FALLTHROUGH; + case PA_CONTEXT_READY: pa_threaded_mainloop_signal(impl->pa_mainloop, 0); break; case PA_CONTEXT_UNCONNECTED: + do_destroy = true; + break; case PA_CONTEXT_CONNECTING: case PA_CONTEXT_AUTHORIZING: case PA_CONTEXT_SETTING_NAME: break; } + if (do_destroy) + pw_impl_module_schedule_destroy(impl->module); } static void stream_state_cb(pa_stream *s, void * userdata) { struct impl *impl = userdata; + bool do_destroy = false; switch (pa_stream_get_state(s)) { - case PA_STREAM_READY: case PA_STREAM_FAILED: case PA_STREAM_TERMINATED: + do_destroy = true; + SPA_FALLTHROUGH; + case PA_STREAM_READY: pa_threaded_mainloop_signal(impl->pa_mainloop, 0); break; case PA_STREAM_UNCONNECTED: + do_destroy = true; + break; case PA_STREAM_CREATING: break; } + if (do_destroy) + pw_impl_module_schedule_destroy(impl->module); } static void stream_read_request_cb(pa_stream *s, size_t length, void *userdata)
View file
pipewire-0.3.56.tar.gz/src/modules/module-rt.c -> pipewire-0.3.57.tar.gz/src/modules/module-rt.c
Changed
@@ -153,6 +153,11 @@ #ifdef HAVE_DBUS #define RTKIT_SERVICE_NAME "org.freedesktop.RealtimeKit1" #define RTKIT_OBJECT_PATH "/org/freedesktop/RealtimeKit1" +#define RTKIT_INTERFACE "org.freedesktop.RealtimeKit1" + +#define XDG_PORTAL_SERVICE_NAME "org.freedesktop.portal.Desktop" +#define XDG_PORTAL_OBJECT_PATH "/org/freedesktop/portal/desktop" +#define XDG_PORTAL_INTERFACE "org.freedesktop.portal.Realtime" /** \cond */ struct pw_rtkit_bus { @@ -184,7 +189,11 @@ #ifdef HAVE_DBUS bool use_rtkit; - struct pw_rtkit_bus *system_bus; + /* For D-Bus. These are const static. */ + const char* service_name; + const char* object_path; + const char* interface; + struct pw_rtkit_bus *rtkit_bus; /* These are only for the RTKit implementation to fill in the `thread` * struct. Since there's barely any overhead here we'll do this @@ -215,7 +224,7 @@ } #ifdef HAVE_DBUS -struct pw_rtkit_bus *pw_rtkit_bus_get_system(void) +struct pw_rtkit_bus *pw_rtkit_bus_get(DBusBusType bus_type) { struct pw_rtkit_bus *bus; DBusError error; @@ -231,7 +240,7 @@ if (bus == NULL) return NULL; - bus->bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error); + bus->bus = dbus_bus_get_private(bus_type, &error); if (bus->bus == NULL) goto error; @@ -241,12 +250,41 @@ error: free(bus); - pw_log_error("Failed to connect to system bus: %s", error.message); + pw_log_error("Failed to connect to %s bus: %s", + bus_type == DBUS_BUS_SYSTEM ? "system" : "session", error.message); dbus_error_free(&error); errno = ECONNREFUSED; return NULL; } +struct pw_rtkit_bus *pw_rtkit_bus_get_system(void) +{ + return pw_rtkit_bus_get(DBUS_BUS_SYSTEM); +} + +struct pw_rtkit_bus *pw_rtkit_bus_get_session(void) +{ + return pw_rtkit_bus_get(DBUS_BUS_SESSION); +} + +bool pw_rtkit_check_xdg_portal(struct pw_rtkit_bus *system_bus) +{ + DBusError error; + bool ret = true; + + dbus_error_init(&error); + + if (!dbus_bus_name_has_owner(system_bus->bus, XDG_PORTAL_SERVICE_NAME, &error)) { + pw_log_warn("Can't find xdg-portal: %s", error.name); + ret = false; + goto finish; + } +finish: + dbus_error_free(&error); + + return ret; +} + void pw_rtkit_bus_free(struct pw_rtkit_bus *system_bus) { dbus_connection_close(system_bus->bus); @@ -270,7 +308,7 @@ return -EIO; } -static long long rtkit_get_int_property(struct pw_rtkit_bus *connection, const char *propname, +static long long rtkit_get_int_property(struct impl *impl, const char *propname, long long *propval) { DBusMessage *m = NULL, *r = NULL; @@ -280,19 +318,19 @@ DBusError error; int current_type; long long ret; - const char *interfacestr = "org.freedesktop.RealtimeKit1"; + struct pw_rtkit_bus *connection = impl->rtkit_bus; dbus_error_init(&error); - if (!(m = dbus_message_new_method_call(RTKIT_SERVICE_NAME, - RTKIT_OBJECT_PATH, + if (!(m = dbus_message_new_method_call(impl->service_name, + impl->object_path, "org.freedesktop.DBus.Properties", "Get"))) { ret = -ENOMEM; goto finish; } if (!dbus_message_append_args(m, - DBUS_TYPE_STRING, &interfacestr, + DBUS_TYPE_STRING, &impl->interface, DBUS_TYPE_STRING, &propname, DBUS_TYPE_INVALID)) { ret = -ENOMEM; goto finish; @@ -349,60 +387,63 @@ return ret; } -int pw_rtkit_get_max_realtime_priority(struct pw_rtkit_bus *connection) +int pw_rtkit_get_max_realtime_priority(struct impl *impl) { long long retval; int err; - err = rtkit_get_int_property(connection, "MaxRealtimePriority", &retval); + err = rtkit_get_int_property(impl, "MaxRealtimePriority", &retval); return err < 0 ? err : retval; } -int pw_rtkit_get_min_nice_level(struct pw_rtkit_bus *connection, int *min_nice_level) +int pw_rtkit_get_min_nice_level(struct impl *impl, int *min_nice_level) { long long retval; int err; - err = rtkit_get_int_property(connection, "MinNiceLevel", &retval); + err = rtkit_get_int_property(impl, "MinNiceLevel", &retval); if (err >= 0) *min_nice_level = retval; return err; } -long long pw_rtkit_get_rttime_usec_max(struct pw_rtkit_bus *connection) +long long pw_rtkit_get_rttime_usec_max(struct impl *impl) { long long retval; int err; - err = rtkit_get_int_property(connection, "RTTimeUSecMax", &retval); + err = rtkit_get_int_property(impl, "RTTimeUSecMax", &retval); return err < 0 ? err : retval; } -int pw_rtkit_make_realtime(struct pw_rtkit_bus *connection, pid_t thread, int priority) +int pw_rtkit_make_realtime(struct impl *impl, pid_t thread, int priority) { DBusMessage *m = NULL, *r = NULL; + dbus_uint64_t pid; dbus_uint64_t u64; dbus_uint32_t u32; DBusError error; int ret; + struct pw_rtkit_bus *connection = impl->rtkit_bus; dbus_error_init(&error); if (thread == 0) thread = _gettid(); - if (!(m = dbus_message_new_method_call(RTKIT_SERVICE_NAME, - RTKIT_OBJECT_PATH, - "org.freedesktop.RealtimeKit1", - "MakeThreadRealtime"))) { + if (!(m = dbus_message_new_method_call(impl->service_name, + impl->object_path, impl->interface, + "MakeThreadRealtimeWithPID"))) { ret = -ENOMEM; goto finish; } + pid = (dbus_uint64_t) getpid(); u64 = (dbus_uint64_t) thread; u32 = (dbus_uint32_t) priority; if (!dbus_message_append_args(m, + DBUS_TYPE_UINT64, &pid, DBUS_TYPE_UINT64, &u64, DBUS_TYPE_UINT32, &u32, DBUS_TYPE_INVALID)) { ret = -ENOMEM; @@ -435,31 +476,34 @@ return ret; } -int pw_rtkit_make_high_priority(struct pw_rtkit_bus *connection, pid_t thread, int nice_level) +int pw_rtkit_make_high_priority(struct impl *impl, pid_t thread, int nice_level) { DBusMessage *m = NULL, *r = NULL; + dbus_uint64_t pid; dbus_uint64_t u64; dbus_int32_t s32; DBusError error; int ret; + struct pw_rtkit_bus *connection = impl->rtkit_bus; dbus_error_init(&error); if (thread == 0) thread = _gettid(); - if (!(m = dbus_message_new_method_call(RTKIT_SERVICE_NAME, - RTKIT_OBJECT_PATH, - "org.freedesktop.RealtimeKit1", - "MakeThreadHighPriority"))) { + if (!(m = dbus_message_new_method_call(impl->service_name, + impl->object_path, impl->interface, + "MakeThreadHighPriorityWithPID"))) { ret = -ENOMEM; goto finish; } + pid = (dbus_uint64_t) getpid(); u64 = (dbus_uint64_t) thread; s32 = (dbus_int32_t) nice_level; if (!dbus_message_append_args(m, + DBUS_TYPE_UINT64, &pid, DBUS_TYPE_UINT64, &u64, DBUS_TYPE_INT32, &s32, DBUS_TYPE_INVALID)) { ret = -ENOMEM; @@ -502,8 +546,8 @@ spa_hook_remove(&impl->module_listener); #ifdef HAVE_DBUS - if (impl->system_bus) - pw_rtkit_bus_free(impl->system_bus); + if (impl->rtkit_bus) + pw_rtkit_bus_free(impl->rtkit_bus); #endif free(impl); @@ -560,13 +604,13 @@ return -errno; } -static int set_nice(struct impl *impl, int nice_level) +static int set_nice(struct impl *impl, int nice_level, bool warn) { int res = 0; #ifdef HAVE_DBUS if (impl->use_rtkit) - res = pw_rtkit_make_high_priority(impl->system_bus, 0, nice_level); + res = pw_rtkit_make_high_priority(impl, 0, nice_level); else res = sched_set_nice(nice_level); #else @@ -574,13 +618,13 @@ #endif if (res < 0) { - pw_log_warn("could not set nice-level to %d: %s", - nice_level, spa_strerror(res)); + if (warn) + pw_log_warn("could not set nice-level to %d: %s", + nice_level, spa_strerror(res)); } else { pw_log_info("main thread nice level set to %d", nice_level); } - return res; } @@ -596,7 +640,7 @@ #ifdef HAVE_DBUS if (impl->use_rtkit) { long long rttime; - rttime = pw_rtkit_get_rttime_usec_max(impl->system_bus); + rttime = pw_rtkit_get_rttime_usec_max(impl); if (rttime >= 0) { if ((rlim_t)rttime < rl.rlim_cur) { pw_log_debug("clamping rt.time.soft from %llu to %lld because of RTKit", @@ -741,7 +785,7 @@ if (min) *min = 1; if (max) - *max = pw_rtkit_get_max_realtime_priority(impl->system_bus); + *max = pw_rtkit_get_max_realtime_priority(impl); } else { if (min) *min = sched_get_priority_min(REALTIME_POLICY); @@ -782,7 +826,7 @@ if (impl->use_rtkit) { pid = impl_gettid(impl, pt); - rtprio_limit = pw_rtkit_get_max_realtime_priority(impl->system_bus); + rtprio_limit = pw_rtkit_get_max_realtime_priority(impl); if (rtprio_limit >= 0 && rtprio_limit < priority) { pw_log_info("dropping requested priority %d for thread %d down to %d because of RTKit limits", priority, pid, rtprio_limit); priority = rtprio_limit; @@ -795,7 +839,7 @@ pw_log_debug("SCHED_OTHER|SCHED_RESET_ON_FORK worked."); } - if ((err = pw_rtkit_make_realtime(impl->system_bus, pid, priority)) < 0) { + if ((err = pw_rtkit_make_realtime(impl, pid, priority)) < 0) { pw_log_warn("could not make thread %d realtime using RTKit: %s", pid, spa_strerror(err)); return err; } @@ -863,31 +907,17 @@ #ifdef HAVE_DBUS -static int should_use_rtkit(struct impl *impl, struct pw_context *context, bool *use_rtkit) +static int check_rtkit(struct impl *impl, struct pw_context *context, bool *can_use_rtkit) { const struct pw_properties *context_props; const char *str; - *use_rtkit = true; + *can_use_rtkit = true; if ((context_props = pw_context_get_properties(context)) != NULL && (str = pw_properties_get(context_props, "support.dbus")) != NULL && !pw_properties_parse_bool(str)) - *use_rtkit = false; - - /* If the user has permissions to use regular realtime scheduling, then - * we'll use that instead of RTKit */ - if (check_realtime_privileges(impl->rt_prio)) { - *use_rtkit = false; - } else { - if (!(*use_rtkit)) { - pw_log_warn("neither regular realtime scheduling nor RTKit are available"); - return -ENOTSUP; - } - - /* TODO: Should this be pw_log_warn or pw_log_debug instead? */ - pw_log_info("could not use realtime scheduling, falling back to using RTKit instead"); - } + *can_use_rtkit = false; return 0; } @@ -921,35 +951,68 @@ impl->rt_time_soft = pw_properties_get_int32(props, "rt.time.soft", DEFAULT_RT_TIME_SOFT); impl->rt_time_hard = pw_properties_get_int32(props, "rt.time.hard", DEFAULT_RT_TIME_HARD); + bool can_use_rtkit = false, use_rtkit = false; + #ifdef HAVE_DBUS spa_list_init(&impl->threads_list); pthread_mutex_init(&impl->lock, NULL); pthread_cond_init(&impl->cond, NULL); - if ((res = should_use_rtkit(impl, context, &impl->use_rtkit)) < 0) { + if ((res = check_rtkit(impl, context, &can_use_rtkit)) < 0) goto error; +#endif + /* If the user has permissions to use regular realtime scheduling, as well as + * the nice level we want, then we'll use that instead of RTKit */ + if (!check_realtime_privileges(impl->rt_prio)) { + if (!can_use_rtkit) { + res = -ENOTSUP; + pw_log_warn("regular realtime scheduling not available (RTKit fallback disabled)"); + goto error; + } + use_rtkit = true; } + if (IS_VALID_NICE_LEVEL(impl->nice_level)) { + if (set_nice(impl, impl->nice_level, !can_use_rtkit) < 0) + use_rtkit = can_use_rtkit; + } + set_rlimit(impl); + +#ifdef HAVE_DBUS + impl->use_rtkit = use_rtkit; if (impl->use_rtkit) { - impl->system_bus = pw_rtkit_bus_get_system(); - if (impl->system_bus == NULL) { - res = -errno; - pw_log_warn("could not get system bus: %m"); - goto error; + /* Checking xdg-desktop-portal. It works fine in all situations. */ + impl->rtkit_bus = pw_rtkit_bus_get_session(); + if (impl->rtkit_bus != NULL) { + if (pw_rtkit_check_xdg_portal(impl->rtkit_bus)) { + impl->service_name = XDG_PORTAL_SERVICE_NAME; + impl->object_path = XDG_PORTAL_OBJECT_PATH; + impl->interface = XDG_PORTAL_INTERFACE; + } else { + pw_log_warn("found session bus but no portal"); + pw_rtkit_bus_free(impl->rtkit_bus); + impl->rtkit_bus = NULL; + } } - } -#else - if (!check_realtime_privileges(impl->rt_prio)) { - res = -ENOTSUP; - pw_log_warn("regular realtime scheduling not available (RTKit fallback disabled)"); - goto error; + /* Failed to get xdg-desktop-portal, try to use rtkit. */ + if (impl->rtkit_bus == NULL) { + impl->rtkit_bus = pw_rtkit_bus_get_system(); + if (impl->rtkit_bus != NULL) { + impl->service_name = RTKIT_SERVICE_NAME; + impl->object_path = RTKIT_OBJECT_PATH; + impl->interface = RTKIT_INTERFACE; + } else { + res = -errno; + pw_log_warn("could not get system bus: %m"); + goto error; + } + } + /* Retry set_nice with rtkit */ + if (IS_VALID_NICE_LEVEL(impl->nice_level)) + set_nice(impl, impl->nice_level, true); } #endif - if (IS_VALID_NICE_LEVEL(impl->nice_level)) - set_nice(impl, impl->nice_level); - set_rlimit(impl); - impl->thread_utils.iface = SPA_INTERFACE_INIT( SPA_TYPE_INTERFACE_ThreadUtils, SPA_VERSION_THREAD_UTILS, @@ -977,8 +1040,8 @@ error: #ifdef HAVE_DBUS - if (impl->system_bus) - pw_rtkit_bus_free(impl->system_bus); + if (impl->rtkit_bus) + pw_rtkit_bus_free(impl->rtkit_bus); #endif free(impl); done:
View file
pipewire-0.3.56.tar.gz/src/pipewire/conf.c -> pipewire-0.3.57.tar.gz/src/pipewire/conf.c
Changed
@@ -39,8 +39,10 @@ #include <pwd.h> #endif #if defined(__FreeBSD__) || defined(__MidnightBSD__) +#ifndef O_PATH #define O_PATH 0 #endif +#endif #include <spa/utils/result.h> #include <spa/utils/string.h> @@ -190,6 +192,9 @@ return -ENOENT; } + if (pw_check_option("no-config", "true")) + goto no_config; + if ((res = get_envconf_path(path, size, prefix, name)) != 0) { if ((*level)++ == 0) return res; @@ -198,20 +203,18 @@ if (*level == 0) { (*level)++; - if ((res = get_confdata_path(path, size, prefix, name)) != 0) + if ((res = get_homeconf_path(path, size, prefix, name)) != 0) return res; } - if (pw_check_option("no-config", "true")) - return 0; - if (*level == 1) { (*level)++; if ((res = get_configdir_path(path, size, prefix, name)) != 0) return res; } if (*level == 2) { +no_config: (*level)++; - if ((res = get_homeconf_path(path, size, prefix, name)) != 0) + if ((res = get_confdata_path(path, size, prefix, name)) != 0) return res; } return 0; @@ -405,12 +408,17 @@ if (fstat(fd, &sbuf) < 0) goto error_close; - if ((data = mmap(NULL, sbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) - goto error_close; - close(fd); - count = pw_properties_update_string(conf, data, sbuf.st_size); - munmap(data, sbuf.st_size); + if (sbuf.st_size > 0) { + if ((data = mmap(NULL, sbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) + goto error_close; + + count = pw_properties_update_string(conf, data, sbuf.st_size); + munmap(data, sbuf.st_size); + } else { + count = 0; + } + close(fd); pw_log_info("%p: loaded config '%s' with %d items", conf, path, count); @@ -423,13 +431,33 @@ return -errno; } +static bool check_override(struct pw_properties *conf, const char *name, int level) +{ + const struct spa_dict_item *it; + + spa_dict_for_each(it, &conf->dict) { + int lev, idx; + + if (!spa_streq(name, it->value)) + continue; + if (sscanf(it->key, "override.%d.%d.config.name", &lev, &idx) != 2) + continue; + if (lev < level) + return false; + } + return true; +} + static void add_override(struct pw_properties *conf, struct pw_properties *override, - const char *path, int level, int index) + const char *path, const char *name, int level, int index) { const struct spa_dict_item *it; char key1024; + snprintf(key, sizeof(key), "override.%d.%d.config.path", level, index); pw_properties_set(conf, key, path); + snprintf(key, sizeof(key), "override.%d.%d.config.name", level, index); + pw_properties_set(conf, key, name); spa_dict_for_each(it, &override->dict) { snprintf(key, sizeof(key), "override.%d.%d.%s", level, index, it->key); pw_properties_set(conf, key, it->value); @@ -488,10 +516,16 @@ return -errno; for (i = 0; i < n; i++) { - snprintf(fname, sizeof(fname), "%s/%s", path, entriesi->d_name); - if (conf_load(fname, override) >= 0) - add_override(conf, override, fname, level, i); - pw_properties_clear(override); + const char *name = entriesi->d_name; + + snprintf(fname, sizeof(fname), "%s/%s", path, name); + if (check_override(conf, name, level)) { + if (conf_load(fname, override) >= 0) + add_override(conf, override, fname, name, level, i); + pw_properties_clear(override); + } else { + pw_log_info("skip override %s with lower priority", fname); + } free(entriesi); } free(entries); @@ -891,6 +925,75 @@ return 0; } +static int try_load_conf(const char *conf_prefix, const char *conf_name, + struct pw_properties *conf) +{ + int res; + + if (conf_name == NULL) + return -EINVAL; + if (spa_streq(conf_name, "null")) + return 0; + if ((res = pw_conf_load_conf(conf_prefix, conf_name, conf)) < 0) { + bool skip_prefix = conf_prefix == NULL || conf_name0 == '/'; + pw_log_warn("can't load config %s%s%s: %s", + skip_prefix ? "" : conf_prefix, + skip_prefix ? "" : "/", + conf_name, spa_strerror(res)); + } + return res; +} + +SPA_EXPORT +int pw_conf_load_conf_for_context(struct pw_properties *props, struct pw_properties *conf) +{ + const char *conf_prefix, *conf_name; + int res; + + conf_prefix = getenv("PIPEWIRE_CONFIG_PREFIX"); + if (conf_prefix == NULL) + conf_prefix = pw_properties_get(props, PW_KEY_CONFIG_PREFIX); + + conf_name = getenv("PIPEWIRE_CONFIG_NAME"); + if ((res = try_load_conf(conf_prefix, conf_name, conf)) < 0) { + conf_name = pw_properties_get(props, PW_KEY_CONFIG_NAME); + if ((res = try_load_conf(conf_prefix, conf_name, conf)) < 0) { + conf_name = "client.conf"; + if ((res = try_load_conf(conf_prefix, conf_name, conf)) < 0) { + pw_log_error("can't load default config %s: %s", + conf_name, spa_strerror(res)); + return res; + } + } + } + + conf_name = pw_properties_get(props, PW_KEY_CONFIG_OVERRIDE_NAME); + if (conf_name != NULL) { + struct pw_properties *override; + const char *path, *name; + + override = pw_properties_new(NULL, NULL); + if (override == NULL) { + res = -errno; + return res; + } + + conf_prefix = pw_properties_get(props, PW_KEY_CONFIG_OVERRIDE_PREFIX); + if ((res = try_load_conf(conf_prefix, conf_name, override)) < 0) { + pw_log_error("can't load default override config %s: %s", + conf_name, spa_strerror(res)); + pw_properties_free (override); + return res; + } + path = pw_properties_get(override, "config.path"); + name = pw_properties_get(override, "config.name"); + add_override(conf, override, path, name, 0, 1); + pw_properties_free(override); + } + + return res; +} + SPA_EXPORT int pw_context_conf_update_props(struct pw_context *context, const char *section, struct pw_properties *props)
View file
pipewire-0.3.56.tar.gz/src/pipewire/conf.h -> pipewire-0.3.57.tar.gz/src/pipewire/conf.h
Changed
@@ -33,6 +33,7 @@ * \{ */ +int pw_conf_load_conf_for_context(struct pw_properties *props, struct pw_properties *conf); int pw_conf_load_conf(const char *prefix, const char *name, struct pw_properties *conf); int pw_conf_load_state(const char *prefix, const char *name, struct pw_properties *conf); int pw_conf_save_state(const char *prefix, const char *name, const struct pw_properties *conf);
View file
pipewire-0.3.56.tar.gz/src/pipewire/context.c -> pipewire-0.3.57.tar.gz/src/pipewire/context.c
Changed
@@ -101,26 +101,6 @@ pw_properties_set(properties, PW_KEY_CORE_NAME, context->core->info.name); } -static int try_load_conf(struct pw_context *this, const char *conf_prefix, - const char *conf_name, struct pw_properties *conf) -{ - int res; - - if (conf_name == NULL) - return -EINVAL; - if (spa_streq(conf_name, "null")) - return 0; - if ((res = pw_conf_load_conf(conf_prefix, conf_name, conf)) < 0) { - bool skip_prefix = conf_prefix == NULL || conf_name0 == '/'; - pw_log_warn("%p: can't load config %s%s%s: %s", - this, - skip_prefix ? "" : conf_prefix, - skip_prefix ? "" : "/", - conf_name, spa_strerror(res)); - } - return res; -} - static int context_set_freewheel(struct pw_context *context, bool freewheel) { struct spa_thread *thr; @@ -211,7 +191,7 @@ { struct impl *impl; struct pw_context *this; - const char *lib, *str, *conf_prefix, *conf_name; + const char *lib, *str; void *dbus_iface = NULL; uint32_t n_support; struct pw_properties *pr, *conf; @@ -270,23 +250,8 @@ goto error_free; } this->conf = conf; - - conf_prefix = getenv("PIPEWIRE_CONFIG_PREFIX"); - if (conf_prefix == NULL) - conf_prefix = pw_properties_get(properties, PW_KEY_CONFIG_PREFIX); - - conf_name = getenv("PIPEWIRE_CONFIG_NAME"); - if (try_load_conf(this, conf_prefix, conf_name, conf) < 0) { - conf_name = pw_properties_get(properties, PW_KEY_CONFIG_NAME); - if (try_load_conf(this, conf_prefix, conf_name, conf) < 0) { - conf_name = "client.conf"; - if ((res = try_load_conf(this, conf_prefix, conf_name, conf)) < 0) { - pw_log_error("%p: can't load config %s: %s", - this, conf_name, spa_strerror(res)); - goto error_free; - } - } - } + if ((res = pw_conf_load_conf_for_context (properties, conf)) < 0) + goto error_free; n_support = pw_get_support(this->support, SPA_N_ELEMENTS(this->support) - 6); cpu = spa_support_find(this->support, n_support, SPA_TYPE_INTERFACE_CPU); @@ -627,98 +592,6 @@ return global; } -/** Find a port to link with - * - * \param context a context - * \param other_port a port to find a link with - * \param id the id of a port or PW_ID_ANY - * \param props extra properties - * \param n_format_filters number of filters - * \param format_filters array of format filters - * \paramout error an error when something is wrong - * \return a port that can be used to link to \a otherport or NULL on error - */ -struct pw_impl_port *pw_context_find_port(struct pw_context *context, - struct pw_impl_port *other_port, - uint32_t id, - struct pw_properties *props, - uint32_t n_format_filters, - struct spa_pod **format_filters, - char **error) -{ - struct pw_impl_port *best = NULL; - bool have_id; - struct pw_impl_node *n; - - have_id = id != PW_ID_ANY; - - pw_log_debug("%p: id:%u", context, id); - - spa_list_for_each(n, &context->node_list, link) { - if (n->global == NULL) - continue; - - if (other_port->node == n) - continue; - - if (!global_can_read(context, n->global)) - continue; - - pw_log_debug("%p: node id:%d", context, n->global->id); - - if (have_id) { - if (n->global->id == id) { - pw_log_debug("%p: id:%u matches node %p", context, id, n); - - best = - pw_impl_node_find_port(n, - pw_direction_reverse(other_port->direction), - PW_ID_ANY); - if (best) - break; - } - } else { - struct pw_impl_port *p, *pin, *pout; - uint8_t buf4096; - struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf)); - struct spa_pod *dummy; - - p = pw_impl_node_find_port(n, - pw_direction_reverse(other_port->direction), - PW_ID_ANY); - if (p == NULL) - continue; - - if (p->direction == PW_DIRECTION_OUTPUT) { - pin = other_port; - pout = p; - } else { - pin = p; - pout = other_port; - } - - if (pw_context_find_format(context, - pout, - pin, - props, - n_format_filters, - format_filters, - &dummy, - &b, - error) < 0) { - free(*error); - continue; - } - best = p; - break; - } - } - if (best == NULL) { - *error = spa_aprintf("No matching Node found"); - } - return best; -} - SPA_PRINTF_FUNC(7, 8) int pw_context_debug_port_params(struct pw_context *this, struct spa_node *node, enum spa_direction direction, uint32_t port_id, uint32_t id, int err, const char *debug, ...) @@ -1382,6 +1255,9 @@ * panding change. Apply the change to the position now so * that we have the right values when we change the node * states of the driver and followers to RUNNING below */ + pw_log_debug("%p: apply duration:%"PRIu64" rate:%u/%u", context, + n->current_quantum, n->current_rate.num, + n->current_rate.denom); n->rt.position->clock.duration = n->current_quantum; n->rt.position->clock.rate = n->current_rate; n->current_pending = false;
View file
pipewire-0.3.56.tar.gz/src/pipewire/data-loop.c -> pipewire-0.3.57.tar.gz/src/pipewire/data-loop.c
Changed
@@ -274,12 +274,7 @@ spa_invoke_func_t func, uint32_t seq, const void *data, size_t size, bool block, void *user_data) { - int res; - if (loop->running) - res = pw_loop_invoke(loop->loop, func, seq, data, size, block, user_data); - else - res = func(loop->loop->loop, false, seq, data, size, user_data); - return res; + return pw_loop_invoke(loop->loop, func, seq, data, size, block, user_data); } /** Set a thread utils implementation.
View file
pipewire-0.3.56.tar.gz/src/pipewire/impl-link.c -> pipewire-0.3.57.tar.gz/src/pipewire/impl-link.c
Changed
@@ -281,8 +281,10 @@ /* find a common format for the ports */ if ((res = pw_context_find_format(context, output, input, NULL, 0, NULL, - &format, &b, &error)) < 0) + &format, &b, &error)) < 0) { + format = NULL; goto error; + } format = spa_pod_copy(format); spa_pod_fixate(format); @@ -1262,7 +1264,7 @@ impl->inode = input_node; } - this->rt.target.signal = impl->inode->rt.target.signal; + this->rt.target.signal_func = impl->inode->rt.target.signal_func; this->rt.target.data = impl->inode->rt.target.data; pw_log_debug("%p: constructed out:%p:%d.%d -> in:%p:%d.%d", impl,
View file
pipewire-0.3.56.tar.gz/src/pipewire/impl-node.c -> pipewire-0.3.57.tar.gz/src/pipewire/impl-node.c
Changed
@@ -1047,7 +1047,7 @@ if (pw_node_activation_state_dec(state, 1)) { a->status = PW_NODE_ACTIVATION_TRIGGERED; a->signal_time = nsec; - t->signal(t->data); + t->signal_func(t->data); } } return 0; @@ -1145,7 +1145,7 @@ this->name, this->info.id, cmd - 1); pw_log_trace_fp("%p: got process", this); - this->rt.target.signal(this->rt.target.data); + this->rt.target.signal_func(this->rt.target.data); } } @@ -1262,9 +1262,9 @@ this->rt.activation = this->activation->map->ptr; this->rt.target.activation = this->rt.activation; this->rt.target.node = this; - this->rt.target.signal = process_node; + this->rt.target.signal_func = process_node; this->rt.target.data = this; - this->rt.driver_target.signal = process_node; + this->rt.driver_target.signal_func = process_node; reset_position(this, &this->rt.activation->position); this->rt.activation->sync_timeout = DEFAULT_SYNC_TIMEOUT; @@ -1613,7 +1613,7 @@ state->pending, state->required); dump_states(node); } - node->rt.target.signal(node->rt.target.data); + node->rt.target.signal_func(node->rt.target.data); } if (node->current_pending) {
View file
pipewire-0.3.56.tar.gz/src/pipewire/impl-port.c -> pipewire-0.3.57.tar.gz/src/pipewire/impl-port.c
Changed
@@ -209,6 +209,7 @@ int pw_impl_port_init_mix(struct pw_impl_port *port, struct pw_impl_port_mix *mix) { uint32_t port_id; + struct pw_impl_node *node = port->node; int res = 0; port_id = pw_map_insert_new(&port->mix_port_map, mix); @@ -252,6 +253,13 @@ port->n_mix, port->port_id, mix->port.port_id, mix->io, spa_strerror(res)); + if (port->n_mix == 1) { + pw_log_debug("%p: setting port io", port); + spa_node_port_set_io(node->node, + port->direction, port->port_id, + SPA_IO_Buffers, + &port->rt.io, sizeof(port->rt.io)); + } return res; error_remove_port: @@ -266,6 +274,7 @@ { int res = 0; uint32_t port_id = mix->port.port_id; + struct pw_impl_node *node = port->node; pw_map_remove(&port->mix_port_map, port_id); spa_list_remove(&mix->link); @@ -280,6 +289,13 @@ pw_log_debug("%p: release mix %d %d.%d", port, port->n_mix, port->port_id, mix->port.port_id); + if (port->n_mix == 0) { + pw_log_debug("%p: clearing port io", port); + spa_node_port_set_io(node->node, + port->direction, port->port_id, + SPA_IO_Buffers, + NULL, sizeof(port->rt.io)); + } return res; } @@ -1025,12 +1041,7 @@ if (control) { pw_log_debug("%p: setting node control", port); } else { - pw_log_debug("%p: setting node io", port); - spa_node_port_set_io(node->node, - port->direction, port->port_id, - SPA_IO_Buffers, - &port->rt.io, sizeof(port->rt.io)); - + pw_log_debug("%p: setting mixer io", port); spa_node_port_set_io(port->mix, pw_direction_reverse(port->direction), 0, SPA_IO_Buffers,
View file
pipewire-0.3.56.tar.gz/src/pipewire/keys.h -> pipewire-0.3.57.tar.gz/src/pipewire/keys.h
Changed
@@ -76,6 +76,8 @@ /* config */ #define PW_KEY_CONFIG_PREFIX "config.prefix" /**< a config prefix directory */ #define PW_KEY_CONFIG_NAME "config.name" /**< a config file name */ +#define PW_KEY_CONFIG_OVERRIDE_PREFIX "config.override.prefix" /**< a config override prefix directory */ +#define PW_KEY_CONFIG_OVERRIDE_NAME "config.override.name" /**< a config override file name */ /* context */ #define PW_KEY_CONTEXT_PROFILE_MODULES "context.profile.modules" /**< a context profile for modules, deprecated */ @@ -170,7 +172,10 @@ #define PW_KEY_NODE_FORCE_RATE "node.force-rate" /**< force a rate while the node is * active */ -#define PW_KEY_NODE_DONT_RECONNECT "node.dont-reconnect" /**< don't reconnect this node */ +#define PW_KEY_NODE_DONT_RECONNECT "node.dont-reconnect" /**< don't reconnect this node. The node is + * initially linked to node.target or + * target.object or the default node. If the + * targets is removed, the node is destroyed */ #define PW_KEY_NODE_ALWAYS_PROCESS "node.always-process" /**< process even when unlinked */ #define PW_KEY_NODE_WANT_DRIVER "node.want-driver" /**< the node wants to be grouped with a driver * node in order to schedule the graph. */
View file
pipewire-0.3.56.tar.gz/src/pipewire/mem.c -> pipewire-0.3.57.tar.gz/src/pipewire/mem.c
Changed
@@ -485,7 +485,12 @@ spa_list_init(&b->memmaps); #ifdef HAVE_MEMFD_CREATE - b->this.fd = memfd_create("pipewire-memfd", MFD_CLOEXEC | MFD_ALLOW_SEALING); + char name128; + snprintf(name, sizeof(name), + "pipewire-memfd:flags=0x%08x,type=%" PRIu32 ",size=%zu", + (unsigned int) flags, type, size); + + b->this.fd = memfd_create(name, MFD_CLOEXEC | MFD_ALLOW_SEALING); if (b->this.fd == -1) { res = -errno; pw_log_error("%p: Failed to create memfd: %m", pool); @@ -499,7 +504,11 @@ goto error_free; } #else - char filename = "/dev/shm/pipewire-tmpfile.XXXXXX"; + char filename128; + snprintf(filename, sizeof(filename), + "/dev/shm/pipewire-tmpfile:flags=0x%08x,type=%" PRIu32 ",size=%zu:XXXXXX", + (unsigned int) flags, type, size); + b->this.fd = mkostemp(filename, O_CLOEXEC); if (b->this.fd == -1) { res = -errno;
View file
pipewire-0.3.56.tar.gz/src/pipewire/meson.build -> pipewire-0.3.57.tar.gz/src/pipewire/meson.build
Changed
@@ -94,7 +94,7 @@ '-DOLD_MEDIA_SESSION_WORKAROUND=1' -if build_machine.system() != 'freebsd' and build_machine.system() != 'midnightbsd' +if host_machine.system() != 'freebsd' and host_machine.system() != 'midnightbsd' libpipewire_c_args += '-D_POSIX_C_SOURCE'
View file
pipewire-0.3.56.tar.gz/src/pipewire/private.h -> pipewire-0.3.57.tar.gz/src/pipewire/private.h
Changed
@@ -573,7 +573,7 @@ struct spa_list link; struct pw_impl_node *node; struct pw_node_activation *activation; - int (*signal) (void *data); + int (*signal_func) (void *data); void *data; unsigned int active:1; }; @@ -1153,16 +1153,6 @@ struct spa_pod_builder *builder, char **error); -/** Find a ports compatible with \a other_port and the format filters */ -struct pw_impl_port * -pw_context_find_port(struct pw_context *context, - struct pw_impl_port *other_port, - uint32_t id, - struct pw_properties *props, - uint32_t n_format_filters, - struct spa_pod **format_filters, - char **error); - int pw_context_debug_port_params(struct pw_context *context, struct spa_node *node, enum spa_direction direction, uint32_t port_id, uint32_t id, int err, const char *debug, ...);
View file
pipewire-0.3.56.tar.gz/src/pipewire/stream.c -> pipewire-0.3.57.tar.gz/src/pipewire/stream.c
Changed
@@ -1261,11 +1261,9 @@ { struct spa_pod_prop *prop; struct spa_pod_object *obj = (struct spa_pod_object *) param; - union { - float f; - double d; - bool b; - } value; + float value_f; + double value_d; + bool value_b; float *values; uint32_t i, n_values; @@ -1278,24 +1276,24 @@ switch (c->container) { case SPA_TYPE_Float: - if (spa_pod_get_float(&prop->value, &value.f) < 0) + if (spa_pod_get_float(&prop->value, &value_f) < 0) continue; n_values = 1; - values = &value.f; + values = &value_f; break; case SPA_TYPE_Double: - if (spa_pod_get_double(&prop->value, &value.d) < 0) + if (spa_pod_get_double(&prop->value, &value_d) < 0) continue; n_values = 1; - value.f = value.d; - values = &value.f; + value_f = value_d; + values = &value_f; break; case SPA_TYPE_Bool: - if (spa_pod_get_bool(&prop->value, &value.b) < 0) + if (spa_pod_get_bool(&prop->value, &value_b) < 0) continue; - value.f = value.b ? 1.0f : 0.0f; + value_f = value_b ? 1.0f : 0.0f; n_values = 1; - values = &value.f; + values = &value_f; break; case SPA_TYPE_Array: if ((values = spa_pod_get_array(&prop->value, &n_values)) == NULL ||
View file
pipewire-0.3.56.tar.gz/src/pipewire/utils.c -> pipewire-0.3.57.tar.gz/src/pipewire/utils.c
Changed
@@ -154,6 +154,7 @@ ssize_t pw_getrandom(void *buf, size_t buflen, unsigned int flags) { ssize_t bytes; + int read_errno; #ifdef HAVE_GETRANDOM bytes = getrandom(buf, buflen, flags); @@ -165,7 +166,9 @@ if (fd < 0) return -1; bytes = read(fd, buf, buflen); + read_errno = errno; close(fd); + errno = read_errno; return bytes; }
View file
pipewire-0.3.56.tar.gz/src/pipewire/utils.h -> pipewire-0.3.57.tar.gz/src/pipewire/utils.h
Changed
@@ -86,6 +86,7 @@ }) #endif +SPA_WARN_UNUSED_RESULT ssize_t pw_getrandom(void *buf, size_t buflen, unsigned int flags); void* pw_reallocarray(void *ptr, size_t nmemb, size_t size);
View file
pipewire-0.3.56.tar.gz/src/tools/pw-cat.c -> pipewire-0.3.57.tar.gz/src/tools/pw-cat.c
Changed
@@ -1663,6 +1663,7 @@ pw_stream_destroy(data.stream); } error_no_stream: +error_bad_file: spa_hook_remove(&data.core_listener); pw_core_disconnect(data.core); error_ctx_connect_failed: @@ -1671,7 +1672,6 @@ pw_main_loop_destroy(data.loop); error_no_props: error_no_main_loop: -error_bad_file: pw_properties_free(data.props); if (data.file) sf_close(data.file);
View file
pipewire-0.3.56.tar.gz/src/tools/pw-cli.c -> pipewire-0.3.57.tar.gz/src/tools/pw-cli.c
Changed
@@ -226,7 +226,6 @@ static bool do_permissions(struct data *data, const char *cmd, char *args, char **error); static bool do_get_permissions(struct data *data, const char *cmd, char *args, char **error); static bool do_send_command(struct data *data, const char *cmd, char *args, char **error); -static bool do_dump(struct data *data, const char *cmd, char *args, char **error); static bool do_quit(struct data *data, const char *cmd, char *args, char **error); #define DUMP_NAMES "Core|Module|Device|Node|Port|Factory|Client|Link|Session|Endpoint|EndpointStream" @@ -251,8 +250,6 @@ { "permissions", "sp", "Set permissions for a client <client-id> <object> <permission>", do_permissions }, { "get-permissions", "gp", "Get permissions of a client <client-id>", do_get_permissions }, { "send-command", "c", "Send a command <object-id>", do_send_command }, - { "dump", "D", "Dump objects in ways that are cleaner for humans to understand " - "short|deep|resolve|notype -sdrt all|"DUMP_NAMES"|<id>", do_dump }, { "quit", "q", "Quit", do_quit }, }; @@ -269,7 +266,10 @@ printf("Available commands:\n"); for (i = 0; i < SPA_N_ELEMENTS(command_list); i++) { - printf("\t%-20.20s\t%s\n", command_listi.name, command_listi.description); + char cmd256; + snprintf(cmd, sizeof(cmd), "%s | %s", + command_listi.name, command_listi.alias); + printf("\t%-20.20s\t%s\n", cmd, command_listi.description); } return true; } @@ -1929,20 +1929,6 @@ return true; } -static const char * -pw_interface_short(const char *type) -{ - size_t ilen; - - ilen = strlen(PW_TYPE_INFO_INTERFACE_BASE); - - if (!type || strlen(type) <= ilen || - memcmp(type, PW_TYPE_INFO_INTERFACE_BASE, ilen)) - return NULL; - - return type + ilen; -} - static struct global * obj_global(struct remote_data *rd, uint32_t id) { @@ -2001,20 +1987,6 @@ return NULL; } -static struct spa_dict * -obj_props(struct remote_data *rd, uint32_t id) -{ - struct global *global; - - if (!rd) - return NULL; - - global = obj_global(rd, id); - if (!global) - return NULL; - return global_props(global); -} - static const char * global_lookup(struct global *global, const char *key) { @@ -2026,16 +1998,6 @@ return spa_dict_lookup(dict, key); } -static const char * -obj_lookup(struct remote_data *rd, uint32_t id, const char *key) -{ - struct spa_dict *dict; - - dict = obj_props(rd, id); - if (!dict) - return NULL; - return spa_dict_lookup(dict, key); -} static int children_of(struct remote_data *rd, uint32_t parent_id, @@ -2135,67 +2097,6 @@ return count; } -#ifndef BIT -#define BIT(x) (1U << (x)) -#endif - -enum dump_flags { - is_default = 0, - is_short = BIT(0), - is_deep = BIT(1), - is_resolve = BIT(2), - is_notype = BIT(3) -}; - -static const char * const dump_types = { - PW_TYPE_INTERFACE_Core, - PW_TYPE_INTERFACE_Module, - PW_TYPE_INTERFACE_Device, - PW_TYPE_INTERFACE_Node, - PW_TYPE_INTERFACE_Port, - PW_TYPE_INTERFACE_Factory, - PW_TYPE_INTERFACE_Client, - PW_TYPE_INTERFACE_Link, - PW_TYPE_INTERFACE_Session, - PW_TYPE_INTERFACE_Endpoint, - PW_TYPE_INTERFACE_EndpointStream, -}; - -int dump_type_index(const char *type) -{ - unsigned int i; - - if (!type) - return -1; - - for (i = 0; i < SPA_N_ELEMENTS(dump_types); i++) { - if (spa_streq(dump_typesi, type)) - return (int)i; - } - - return -1; -} - -static inline unsigned int dump_type_count(void) -{ - return SPA_N_ELEMENTS(dump_types); -} - -static const char *name_to_dump_type(const char *name) -{ - unsigned int i; - - if (!name) - return NULL; - - for (i = 0; i < SPA_N_ELEMENTS(dump_types); i++) { - if (!strcasecmp(name, pw_interface_short(dump_typesi))) - return dump_typesi; - } - - return NULL; -} - #define INDENT(_level) \ ({ \ int __level = (_level); \ @@ -2205,817 +2106,6 @@ (const char *)_indent; \ }) -static void -dump(struct data *data, struct global *global, - enum dump_flags flags, int level); - -static void -dump_properties(struct data *data, struct global *global, - enum dump_flags flags, int level) -{ - struct remote_data *rd = data->current; - struct spa_dict *props; - const struct spa_dict_item *item; - const char *ind; - int id; - const char *extra; - - if (!global) - return; - - props = global_props(global); - if (!props || !props->n_items) - return; - - ind = INDENT(level + 2); - spa_dict_for_each(item, props) { - printf("%s%s = \"%s\"", - ind, item->key, item->value); - - extra = NULL; - if (spa_streq(global->type, PW_TYPE_INTERFACE_Port) && spa_streq(item->key, PW_KEY_NODE_ID)) { - id = atoi(item->value); - if (id >= 0) - extra = obj_lookup(rd, id, PW_KEY_NODE_NAME); - } else if (spa_streq(global->type, PW_TYPE_INTERFACE_Factory) && spa_streq(item->key, PW_KEY_MODULE_ID)) { - id = atoi(item->value); - if (id >= 0) - extra = obj_lookup(rd, id, PW_KEY_MODULE_NAME); - } else if (spa_streq(global->type, PW_TYPE_INTERFACE_Device) && spa_streq(item->key, PW_KEY_FACTORY_ID)) { - id = atoi(item->value); - if (id >= 0) - extra = obj_lookup(rd, id, PW_KEY_FACTORY_NAME); - } else if (spa_streq(global->type, PW_TYPE_INTERFACE_Device) && spa_streq(item->key, PW_KEY_CLIENT_ID)) { - id = atoi(item->value); - if (id >= 0) - extra = obj_lookup(rd, id, PW_KEY_CLIENT_NAME); - } - - if (extra) - printf(" (\"%s\")", extra); - - printf("\n"); - } -} - -static void -dump_params(struct data *data, struct global *global, - struct spa_param_info *params, uint32_t n_params, - enum dump_flags flags, int level) -{ - uint32_t i; - const char *ind; - - if (params == NULL || n_params == 0) - return; - - ind = INDENT(level + 1); - for (i = 0; i < n_params; i++) { - const struct spa_type_info *type_info = spa_type_param; - - printf("%s %d (%s) %c%c\n", ind, - paramsi.id, - spa_debug_type_find_name(type_info, paramsi.id), - paramsi.flags & SPA_PARAM_INFO_READ ? 'r' : '-', - paramsi.flags & SPA_PARAM_INFO_WRITE ? 'w' : '-'); - } -} - - -static void -dump_global_common(struct data *data, struct global *global, - enum dump_flags flags, int level) -{ - const char *ind; - - if (!(flags & is_short)) { - ind = INDENT(level + 1); - printf("%sid: %"PRIu32"\n", ind, global->id); - printf("%spermissions: "PW_PERMISSION_FORMAT"\n", ind, - PW_PERMISSION_ARGS(global->permissions)); - printf("%stype: %s/%d\n", ind, - global->type, global->version); - } else { - ind = INDENT(level); - printf("%s%"PRIu32":", ind, global->id); - if (!(flags & is_notype)) - printf(" %s", pw_interface_short(global->type)); - } -} - -static bool -dump_core(struct data *data, struct global *global, - enum dump_flags flags, int level) -{ - struct proxy_data *pd = pw_proxy_get_user_data(global->proxy); - struct pw_core_info *info; - const char *ind; - - if (!pd->info) - return false; - - dump_global_common(data, global, flags, level); - - info = pd->info; - if (!(flags & is_short)) { - ind = INDENT(level + 1); - printf("%scookie: %u\n", ind, info->cookie); - printf("%suser-name: \"%s\"\n", ind, info->user_name); - printf("%shost-name: \"%s\"\n", ind, info->host_name); - printf("%sversion: \"%s\"\n", ind, info->version); - printf("%sname: \"%s\"\n", ind, info->name); - printf("%sproperties:\n", ind); - dump_properties(data, global, flags, level); - } else { - printf(" u=\"%s\" h=\"%s\" v=\"%s\" n=\"%s\"", - info->user_name, info->host_name, info->version, info->name); - printf("\n"); - } - - return true; -} - -static bool -dump_module(struct data *data, struct global *global, - enum dump_flags flags, int level) -{ - struct remote_data *rd = global->rd; - struct proxy_data *pd = pw_proxy_get_user_data(global->proxy); - struct pw_module_info *info; - const char *args, *desc; - const char *ind; - uint32_t *factories = NULL; - int i, factory_count; - struct global *global_factory; - - if (!pd->info) - return false; - - info = pd->info; - - dump_global_common(data, global, flags, level); - - if (!(flags & is_short)) { - ind = INDENT(level + 1); - printf("%sname: \"%s\"\n", ind, info->name); - printf("%sfilename: \"%s\"\n", ind, info->filename); - printf("%sargs: \"%s\"\n", ind, info->args); - printf("%sproperties:\n", ind); - dump_properties(data, global, flags, level); - } else { - desc = spa_dict_lookup(info->props, PW_KEY_MODULE_DESCRIPTION); - args = info->args && strcmp(info->args, "(null)") ? info->args : NULL; - printf(" n=\"%s\" f=\"%s\"" "%s%s%s" "%s%s%s", - info->name, info->filename, - args ? " a=\"" : "", - args ? args : "", - args ? "\"" : "", - desc ? " d=\"" : "", - desc ? desc : "", - desc ? "\"" : ""); - printf("\n"); - } - - if (!(flags & is_deep)) - return true; - - factory_count = children_of(rd, global->id, PW_TYPE_INTERFACE_Factory, &factories); - if (factory_count >= 0) { - ind = INDENT(level + 1); - printf("%sfactories:\n", ind); - for (i = 0; i < factory_count; i++) { - global_factory = obj_global(rd, factoriesi); - if (!global_factory) - continue; - dump(data, global_factory, flags | is_notype, level + 1); - } - free(factories); - } - - return true; -} - -static bool -dump_device(struct data *data, struct global *global, - enum dump_flags flags, int level) -{ - struct remote_data *rd = data->current; - struct proxy_data *pd = pw_proxy_get_user_data(global->proxy); - struct pw_device_info *info; - const char *media_class, *api, *desc, *name; - const char *alsa_path, *alsa_card_id; - const char *ind; - uint32_t *nodes = NULL; - int i, node_count; - struct global *global_node; - - if (!pd->info) - return false; - - info = pd->info; - - dump_global_common(data, global, flags, level); - - if (!(flags & is_short)) { - ind = INDENT(level + 1); - printf("%sproperties:\n", ind); - dump_properties(data, global, flags, level); - printf("%sparams:\n", ind); - dump_params(data, global, info->params, info->n_params, flags, level); - } else { - media_class = spa_dict_lookup(info->props, PW_KEY_MEDIA_CLASS); - name = spa_dict_lookup(info->props, PW_KEY_DEVICE_NAME); - desc = spa_dict_lookup(info->props, PW_KEY_DEVICE_DESCRIPTION); - api = spa_dict_lookup(info->props, PW_KEY_DEVICE_API); - - printf("%s%s%s" "%s%s%s" "%s%s%s" "%s%s%s", - media_class ? " c=\"" : "", - media_class ? media_class : "", - media_class ? "\"" : "", - name ? " n=\"" : "", - name ? name : "", - name ? "\"" : "", - desc ? " d=\"" : "", - desc ? desc : "", - desc ? "\"" : "", - api ? " a=\"" : "", - api ? api : "", - api ? "\"" : ""); - - if (media_class && spa_streq(media_class, "Audio/Device") && - api && spa_streq(api, "alsa:pcm")) { - - alsa_path = spa_dict_lookup(info->props, SPA_KEY_API_ALSA_PATH); - alsa_card_id = spa_dict_lookup(info->props, SPA_KEY_API_ALSA_CARD_ID); - - printf("%s%s%s" "%s%s%s", - alsa_path ? " p=\"" : "", - alsa_path ? alsa_path : "", - alsa_path ? "\"" : "", - alsa_card_id ? " id=\"" : "", - alsa_card_id ? alsa_card_id : "", - alsa_card_id ? "\"" : ""); - } - - printf("\n"); - } - - if (!(flags & is_deep)) - return true; - - node_count = children_of(rd, global->id, PW_TYPE_INTERFACE_Node, &nodes); - if (node_count >= 0) { - ind = INDENT(level + 1); - printf("%snodes:\n", ind); - for (i = 0; i < node_count; i++) { - global_node = obj_global(rd, nodesi); - if (!global_node) - continue; - dump(data, global_node, flags | is_notype, level + 1); - } - free(nodes); - } - - return true; -} - -static bool -dump_node(struct data *data, struct global *global, - enum dump_flags flags, int level) -{ - struct remote_data *rd = data->current; - struct proxy_data *pd = pw_proxy_get_user_data(global->proxy); - struct pw_node_info *info; - const char *name, *path; - const char *ind; - uint32_t *ports = NULL; - int i, port_count; - struct global *global_port; - - if (!pd->info) - return false; - - dump_global_common(data, global, flags, level); - - info = pd->info; - - if (!(flags & is_short)) { - ind = INDENT(level + 1); - printf("%sinput ports: %u/%u\n", ind, info->n_input_ports, info->max_input_ports); - printf("%soutput ports: %u/%u\n", ind, info->n_output_ports, info->max_output_ports); - printf("%sstate: \"%s\"", ind, pw_node_state_as_string(info->state)); - if (info->state == PW_NODE_STATE_ERROR && info->error) - printf(" \"%s\"\n", info->error); - else - printf("\n"); - printf("%sproperties:\n", ind); - dump_properties(data, global, flags, level); - printf("%sparams:\n", ind); - dump_params(data, global, info->params, info->n_params, flags, level); - } else { - name = spa_dict_lookup(info->props, PW_KEY_NODE_NAME); - path = spa_dict_lookup(info->props, SPA_KEY_OBJECT_PATH); - - printf(" s=\"%s\"", pw_node_state_as_string(info->state)); - - if (info->max_input_ports) { - printf(" i=%u/%u", info->n_input_ports, info->max_input_ports); - } - if (info->max_output_ports) { - printf(" o=%u/%u", info->n_output_ports, info->max_output_ports); - } - - printf("%s%s%s" "%s%s%s", - name ? " n=\"" : "", - name ? name : "", - name ? "\"" : "", - path ? " p=\"" : "", - path ? path : "", - path ? "\"" : ""); - - printf("\n"); - } - - if (!(flags & is_deep)) - return true; - - port_count = children_of(rd, global->id, PW_TYPE_INTERFACE_Port, &ports); - if (port_count >= 0) { - ind = INDENT(level + 1); - printf("%sports:\n", ind); - for (i = 0; i < port_count; i++) { - global_port = obj_global(rd, portsi); - if (!global_port) - continue; - dump(data, global_port, flags | is_notype, level + 1); - } - free(ports); - } - return true; -} - -static bool -dump_port(struct data *data, struct global *global, - enum dump_flags flags, int level) -{ - struct remote_data *rd = data->current; - struct proxy_data *pd = pw_proxy_get_user_data(global->proxy); - struct pw_port_info *info; - const char *ind; - const char *name, *format; - - if (!pd->info) - return false; - - dump_global_common(data, global, flags, level); - - info = pd->info; - - if (!(flags & is_short)) { - ind = INDENT(level + 1); - printf("%sdirection: \"%s\"\n", ind, - pw_direction_as_string(info->direction)); - printf("%sproperties:\n", ind); - dump_properties(data, global, flags, level); - printf("%sparams:\n", ind); - dump_params(data, global, info->params, info->n_params, flags, level); - } else { - printf(" d=\"%s\"", pw_direction_as_string(info->direction)); - - name = spa_dict_lookup(info->props, PW_KEY_PORT_NAME); - format = spa_dict_lookup(info->props, PW_KEY_FORMAT_DSP); - - printf("%s%s%s" "%s%s%s", - name ? " n=\"" : "", - name ? name : "", - name ? "\"" : "", - format ? " f=\"" : "", - format ? format : "", - format ? "\"" : ""); - - printf("\n"); - } - - (void)rd; - - return true; -} - -static bool -dump_factory(struct data *data, struct global *global, - enum dump_flags flags, int level) -{ - struct remote_data *rd = data->current; - struct proxy_data *pd = pw_proxy_get_user_data(global->proxy); - struct pw_factory_info *info; - const char *ind; - const char *module_id, *module_name; - - if (!pd->info) - return false; - - dump_global_common(data, global, flags, level); - - info = pd->info; - - if (!(flags & is_short)) { - ind = INDENT(level + 1); - printf("%sname: \"%s\"\n", ind, info->name); - printf("%sproperties:\n", ind); - dump_properties(data, global, flags, level); - } else { - printf(" n=\"%s\"", info->name); - - module_id = spa_dict_lookup(info->props, PW_KEY_MODULE_ID); - module_name = module_id ? obj_lookup(rd, atoi(module_id), PW_KEY_MODULE_NAME) : NULL; - - printf("%s%s%s", - module_name ? " m=\"" : "", - module_name ? module_name : "", - module_name ? "\"" : ""); - - printf("\n"); - } - - return true; -} - -static bool -dump_client(struct data *data, struct global *global, - enum dump_flags flags, int level) -{ - struct remote_data *rd = data->current; - struct proxy_data *pd = pw_proxy_get_user_data(global->proxy); - struct pw_client_info *info; - const char *ind; - const char *app_name, *app_pid; - - if (!pd->info) - return false; - - dump_global_common(data, global, flags, level); - - info = pd->info; - - if (!(flags & is_short)) { - ind = INDENT(level + 1); - printf("%sproperties:\n", ind); - dump_properties(data, global, flags, level); - } else { - app_name = spa_dict_lookup(info->props, PW_KEY_APP_NAME); - app_pid = spa_dict_lookup(info->props, PW_KEY_APP_PROCESS_ID); - - printf("%s%s%s" "%s%s%s", - app_name ? " ap=\"" : "", - app_name ? app_name : "", - app_name ? "\"" : "", - app_pid ? " ai=\"" : "", - app_pid ? app_pid : "", - app_pid ? "\"" : ""); - - printf("\n"); - } - - (void)rd; - - return true; -} - -static bool -dump_link(struct data *data, struct global *global, - enum dump_flags flags, int level) -{ - struct remote_data *rd = data->current; - struct proxy_data *pd = pw_proxy_get_user_data(global->proxy); - struct pw_link_info *info; - const char *ind; - const char *in_node_name, *in_port_name; - const char *out_node_name, *out_port_name; - - if (!pd->info) - return false; - - dump_global_common(data, global, flags, level); - - info = pd->info; - - if (!(flags & is_short)) { - ind = INDENT(level + 1); - printf("%soutput-node-id: %u\n", ind, info->output_node_id); - printf("%soutput-port-id: %u\n", ind, info->output_port_id); - printf("%sinput-node-id: %u\n", ind, info->input_node_id); - printf("%sinput-port-id: %u\n", ind, info->input_port_id); - - printf("%sstate: \"%s\"", ind, - pw_link_state_as_string(info->state)); - if (info->state == PW_LINK_STATE_ERROR && info->error) - printf(" \"%s\"\n", info->error); - else - printf("\n"); - printf("%sformat:\n", ind); - if (info->format) - spa_debug_pod(8 * (level + 1) + 2, NULL, info->format); - else - printf("%s\tnone\n", ind); - - printf("%sproperties:\n", ind); - dump_properties(data, global, flags, level); - } else { - out_node_name = obj_lookup(rd, info->output_node_id, PW_KEY_NODE_NAME); - in_node_name = obj_lookup(rd, info->input_node_id, PW_KEY_NODE_NAME); - out_port_name = obj_lookup(rd, info->output_port_id, PW_KEY_PORT_NAME); - in_port_name = obj_lookup(rd, info->input_port_id, PW_KEY_PORT_NAME); - - printf(" s=\"%s\"", pw_link_state_as_string(info->state)); - - if (out_node_name && out_port_name) - printf(" on=\"%s\"" " op=\"%s\"", - out_node_name, out_port_name); - if (in_node_name && in_port_name) - printf(" in=\"%s\"" " ip=\"%s\"", - in_node_name, in_port_name); - - printf("\n"); - } - - (void)rd; - - return true; -} - -static bool -dump_session(struct data *data, struct global *global, - enum dump_flags flags, int level) -{ - struct remote_data *rd = data->current; - struct proxy_data *pd = pw_proxy_get_user_data(global->proxy); - struct pw_session_info *info; - const char *ind; - - if (!pd->info) - return false; - - dump_global_common(data, global, flags, level); - - info = pd->info; - - if (!(flags & is_short)) { - ind = INDENT(level + 1); - printf("%sproperties:\n", ind); - dump_properties(data, global, flags, level); - printf("%sparams:\n", ind); - dump_params(data, global, info->params, info->n_params, flags, level); - } else { - printf("\n"); - } - - (void)rd; - - return true; -} - -static bool -dump_endpoint(struct data *data, struct global *global, - enum dump_flags flags, int level) -{ - struct remote_data *rd = data->current; - struct proxy_data *pd = pw_proxy_get_user_data(global->proxy); - struct pw_endpoint_info *info; - const char *ind; - const char *direction; - - if (!pd->info) - return false; - - dump_global_common(data, global, flags, level); - - info = pd->info; - - switch(info->direction) { - case PW_DIRECTION_OUTPUT: - direction = "source"; - break; - case PW_DIRECTION_INPUT: - direction = "sink"; - break; - default: - direction = "invalid"; - break; - } - - if (!(flags & is_short)) { - ind = INDENT(level + 1); - printf("%sname: %s\n", ind, info->name); - printf("%smedia-class: %s\n", ind, info->media_class); - printf("%sdirection: %s\n", ind, direction); - printf("%sflags: 0x%x\n", ind, info->flags); - printf("%sstreams: %u\n", ind, info->n_streams); - printf("%ssession: %u\n", ind, info->session_id); - printf("%sproperties:\n", ind); - dump_properties(data, global, flags, level); - printf("%sparams:\n", ind); - dump_params(data, global, info->params, info->n_params, flags, level); - } else { - printf(" n=\"%s\" c=\"%s\" d=\"%s\" s=%u si=%"PRIu32"", - info->name, info->media_class, direction, - info->n_streams, info->session_id); - printf("\n"); - } - - (void)rd; - - return true; -} - -static bool -dump_endpoint_stream(struct data *data, struct global *global, - enum dump_flags flags, int level) -{ - struct remote_data *rd = data->current; - struct proxy_data *pd = pw_proxy_get_user_data(global->proxy); - struct pw_endpoint_stream_info *info; - const char *ind; - - if (!pd->info) - return false; - - dump_global_common(data, global, flags, level); - - info = pd->info; - - if (!(flags & is_short)) { - ind = INDENT(level + 1); - printf("%sid: %u\n", ind, info->id); - printf("%sendpoint-id: %u\n", ind, info->endpoint_id); - printf("%sname: %s\n", ind, info->name); - printf("%sproperties:\n", ind); - dump_properties(data, global, flags, level); - printf("%sparams:\n", ind); - dump_params(data, global, info->params, info->n_params, flags, level); - } else { - printf(" n=\"%s\" i=%"PRIu32" ei=%"PRIu32"", - info->name, info->id, info->endpoint_id); - printf("\n"); - } - - (void)rd; - - return true; -} - -static void -dump(struct data *data, struct global *global, - enum dump_flags flags, int level) -{ - if (!global) - return; - - if (spa_streq(global->type, PW_TYPE_INTERFACE_Core)) - dump_core(data, global, flags, level); - - if (spa_streq(global->type, PW_TYPE_INTERFACE_Module)) - dump_module(data, global, flags, level); - - if (spa_streq(global->type, PW_TYPE_INTERFACE_Device)) - dump_device(data, global, flags, level); - - if (spa_streq(global->type, PW_TYPE_INTERFACE_Node)) - dump_node(data, global, flags, level); - - if (spa_streq(global->type, PW_TYPE_INTERFACE_Port)) - dump_port(data, global, flags, level); - - if (spa_streq(global->type, PW_TYPE_INTERFACE_Factory)) - dump_factory(data, global, flags, level); - - if (spa_streq(global->type, PW_TYPE_INTERFACE_Client)) - dump_client(data, global, flags, level); - - if (spa_streq(global->type, PW_TYPE_INTERFACE_Link)) - dump_link(data, global, flags, level); - - if (spa_streq(global->type, PW_TYPE_INTERFACE_Session)) - dump_session(data, global, flags, level); - - if (spa_streq(global->type, PW_TYPE_INTERFACE_Endpoint)) - dump_endpoint(data, global, flags, level); - - if (spa_streq(global->type, PW_TYPE_INTERFACE_EndpointStream)) - dump_endpoint_stream(data, global, flags, level); -} - -static bool do_dump(struct data *data, const char *cmd, char *args, char **error) -{ - struct remote_data *rd = data->current; - union pw_map_item *item; - struct global *global; - char *aa32, **a; - char c; - int i, n, idx; - enum dump_flags flags = is_default; - bool match; - unsigned int type_mask; - - n = pw_split_ip(args, WHITESPACE, SPA_N_ELEMENTS(aa), aa); - if (n < 0) - goto usage; - - a = aa; - while (n > 0 && - (spa_streq(a0, "short") || - spa_streq(a0, "deep") || - spa_streq(a0, "resolve") || - spa_streq(a0, "notype"))) { - if (spa_streq(a0, "short")) - flags |= is_short; - else if (spa_streq(a0, "deep")) - flags |= is_deep; - else if (spa_streq(a0, "resolve")) - flags |= is_resolve; - else if (spa_streq(a0, "notype")) - flags |= is_notype; - n--; - a++; - } - - while (n > 0 && a00 == '-') { - for (i = 1; (c = a0i) != '\0'; i++) { - if (c == 's') - flags |= is_short; - else if (c == 'd') - flags |= is_deep; - else if (c == 'r') - flags |= is_resolve; - else if (c == 't') - flags |= is_notype; - else - goto usage; - } - n--; - a++; - } - - if (n == 0 || spa_streq(a0, "all")) { - type_mask = (1U << dump_type_count()) - 1; - flags &= ~is_notype; - } else { - type_mask = 0; - for (i = 0; i < n; i++) { - /* skip direct IDs */ - if (isdigit(ai0)) - continue; - idx = dump_type_index(name_to_dump_type(ai)); - if (idx < 0) - goto usage; - type_mask |= 1U << idx; - } - - /* single bit set? disable type */ - if ((type_mask & (type_mask - 1)) == 0) - flags |= is_notype; - } - - pw_array_for_each(item, &rd->globals.items) { - if (pw_map_item_is_free(item) || item->data == NULL) - continue; - - global = item->data; - - /* unknown type, ignore completely */ - idx = dump_type_index(global->type); - if (idx < 0) - continue; - - match = false; - - /* first check direct ids */ - for (i = 0; i < n; i++) { - /* skip non direct IDs */ - if (!isdigit(ai0)) - continue; - if (atoi(ai) == (int)global->id) { - match = true; - break; - } - } - - /* if type match */ - if (!match && (type_mask & (1U << idx))) - match = true; - - if (!match) - continue; - - dump(data, global, flags, 0); - } - - return true; -usage: - *error = spa_aprintf("%s short|deep|resolve|notype -sdrt all|%s|<id>", - cmd, DUMP_NAMES); - return false; -} - static bool parse(struct data *data, char *buf, char **error) { char *a2;
View file
pipewire-0.3.56.tar.gz/test/test-spa-utils.c -> pipewire-0.3.57.tar.gz/test/test-spa-utils.c
Changed
@@ -419,6 +419,12 @@ } pwtest_int_eq(count, 4); pwtest_int_eq(hook_free_count, 4); + + /* remove a zeroed hook */ + struct spa_hook hook; + spa_zero(hook); + spa_hook_remove(&hook); + return PWTEST_PASS; }
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.