From b55bcc3df33be268a59aa8b8263fa6713487e182 Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Fri, 27 May 2022 22:41:51 +0300 Subject: [PATCH 001/260] rtp: Accept CRLF delimiters in SDP as required by RFC 4566 RFC 4566 states that SDP record is terminated with CRLF, and parsers should be able to accept records terminated with just LF. Pulseaudio only accepts LF here. Fix this by accepting both CRLF and LF terminators. --- src/modules/rtp/sap.c | 4 +++- src/modules/rtp/sdp.c | 31 ++++++++++++++++++++++++++----- src/modules/rtp/sdp.h | 2 +- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/modules/rtp/sap.c b/src/modules/rtp/sap.c index 7fb1a3895..8614022f8 100644 --- a/src/modules/rtp/sap.c +++ b/src/modules/rtp/sap.c @@ -213,7 +213,9 @@ int pa_sap_recv(pa_sap_context *c, bool *goodbye) { if ((unsigned) size >= sizeof(MIME_TYPE) && pa_streq(e, MIME_TYPE)) { e += sizeof(MIME_TYPE); size -= (int) sizeof(MIME_TYPE); - } else if ((unsigned) size < sizeof(PA_SDP_HEADER)-1 || strncmp(e, PA_SDP_HEADER, sizeof(PA_SDP_HEADER)-1)) { + } else if ((unsigned) size < sizeof(PA_SDP_HEADER)-1 || strncmp(e, PA_SDP_HEADER, sizeof(PA_SDP_HEADER)-1) + || strcspn(e, "\r\n") != sizeof(PA_SDP_HEADER)-1) { + /* SDP header does not start with v=0[\r]\n */ pa_log_warn("Invalid SDP header."); goto fail; } diff --git a/src/modules/rtp/sdp.c b/src/modules/rtp/sdp.c index e130509df..4e6a442f8 100644 --- a/src/modules/rtp/sdp.c +++ b/src/modules/rtp/sdp.c @@ -73,7 +73,7 @@ char *pa_sdp_build(int af, const void *src, const void *dst, const char *name, u pa_assert_se(inet_ntop(af, dst, buf_dst, sizeof(buf_dst))); return pa_sprintf_malloc( - PA_SDP_HEADER + PA_SDP_HEADER "\n" "o=%s %lu 0 IN %s %s\n" "s=%s\n" "c=IN %s %s\n" @@ -130,17 +130,29 @@ pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *i, int is_goodbye) { i->salen = 0; i->payload = 255; - if (!pa_startswith(t, PA_SDP_HEADER)) { + if (pa_startswith(t, PA_SDP_HEADER)) { + t += sizeof(PA_SDP_HEADER) - 1; + + /* CR delimiter is optional */ + if (*t == '\r') + t++; + + /* LF delimiter is mandatory */ + if (*t == '\n') + t++; + else { + pa_log("Failed to parse SDP data: missing header record terminator LF."); + goto fail; + } + } else { pa_log("Failed to parse SDP data: invalid header."); goto fail; } - t += sizeof(PA_SDP_HEADER)-1; - while (*t) { size_t l; - l = strcspn(t, "\n"); + l = strcspn(t, "\r\n"); if (l <= 2) { pa_log("Failed to parse SDP data: line too short: >%s<.", t); @@ -240,8 +252,17 @@ pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *i, int is_goodbye) { t += l; + /* CR delimiter is optional */ + if (*t == '\r') + t++; + + /* LF delimiter is mandatory */ if (*t == '\n') t++; + else { + pa_log("Failed to parse SDP data: missing record terminator LF."); + goto fail; + } } if (!i->origin || (!is_goodbye && (!i->salen || i->payload > 127 || !ss_valid || port == 0))) { diff --git a/src/modules/rtp/sdp.h b/src/modules/rtp/sdp.h index 28c755a27..80ab3636e 100644 --- a/src/modules/rtp/sdp.h +++ b/src/modules/rtp/sdp.h @@ -26,7 +26,7 @@ #include -#define PA_SDP_HEADER "v=0\n" +#define PA_SDP_HEADER "v=0" typedef struct pa_sdp_info { char *origin; From 05c06afa58e30b7958e96766d1e917099c8a4041 Mon Sep 17 00:00:00 2001 From: Sean Greenslade Date: Sat, 4 Jun 2022 00:24:49 -0700 Subject: [PATCH 002/260] pactl: fix parsing of percentages with decimal points The logic for detecting which type of volume was given incorrectly interpreted any value with a decimal as a VOL_LINEAR. It also could set multiple flags, which would put the flags variable into an indeterminate state. Additionally, the flags stack variable was uninitialized which could also lead to an indeterminate flag state. Percentages are now prioritized over all other types, and only one type flag can be set. --- src/utils/pactl.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/utils/pactl.c b/src/utils/pactl.c index 35163f277..2761ebaaf 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -2527,16 +2527,16 @@ static int parse_volume(const char *vol_spec, pa_volume_t *vol, enum volume_flag vs = pa_xstrdup(vol_spec); *vol_flags = (pa_startswith(vs, "+") || pa_startswith(vs, "-")) ? VOL_RELATIVE : VOL_ABSOLUTE; - if (strchr(vs, '.')) - *vol_flags |= VOL_LINEAR; if (pa_endswith(vs, "%")) { *vol_flags |= VOL_PERCENT; vs[strlen(vs)-1] = 0; } - if (pa_endswith(vs, "db") || pa_endswith(vs, "dB")) { + else if (pa_endswith(vs, "db") || pa_endswith(vs, "dB")) { *vol_flags |= VOL_DECIBEL; vs[strlen(vs)-2] = 0; } + else if (strchr(vs, '.')) + *vol_flags |= VOL_LINEAR; atod_input = vs; @@ -2597,7 +2597,7 @@ static int parse_volumes(char *args[], unsigned n) { volume.channels = n; for (i = 0; i < volume.channels; i++) { - enum volume_flags flags; + enum volume_flags flags = 0; if (parse_volume(args[i], &volume.values[i], &flags) < 0) return -1; From a8a2a31408c4acf54530d65922d235d3e590ce05 Mon Sep 17 00:00:00 2001 From: Jaechul Lee Date: Thu, 2 Jun 2022 15:07:09 +0900 Subject: [PATCH 003/260] sound-file-stream: Fix crash when playing a file which is not aligned pulseaudio crash occurred when I play a file using pacmd play-file command. The file is not aligned with its frame size and the last rendering size is also not aligned. Thus, an assertion was generated at the end of the file as the following. memblockq.c: Assertion 'uchunk->length % bq->base == 0' failed at ../src/pulsecore/memblockq.c:288, function pa_memblockq_push(). Aborting. When I play the file using paplay, it works good. So, I changed to pa_memblockq_push_align instead of pa_memblockq_push to prevent the assertion. Signed-off-by: Jaechul Lee Part-of: --- src/pulsecore/sound-file-stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulsecore/sound-file-stream.c b/src/pulsecore/sound-file-stream.c index 147aa2288..255f4b61a 100644 --- a/src/pulsecore/sound-file-stream.c +++ b/src/pulsecore/sound-file-stream.c @@ -185,7 +185,7 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk tchunk.length = (size_t) n * fs; - pa_memblockq_push(u->memblockq, &tchunk); + pa_memblockq_push_align(u->memblockq, &tchunk); pa_memblock_unref(tchunk.memblock); } From d7a633df899dda8738a30df318269e28c902e815 Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Mon, 13 Jun 2022 21:38:08 +0300 Subject: [PATCH 004/260] rtp: Initialize SDP info struct field added for OPUS Turned out that pa_sdp_info::enable_opus is never initialized, which seldom makes module-rtp-recv believe it will be playing OPUS-encoded stream even though discovered SDP record does not indicate OPUS codec in metadata. Fix this by adding missing initializer. Part-of: --- src/modules/rtp/sdp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/rtp/sdp.c b/src/modules/rtp/sdp.c index 4e6a442f8..bf131a27e 100644 --- a/src/modules/rtp/sdp.c +++ b/src/modules/rtp/sdp.c @@ -129,6 +129,7 @@ pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *i, int is_goodbye) { i->origin = i->session_name = NULL; i->salen = 0; i->payload = 255; + i->enable_opus = false; if (pa_startswith(t, PA_SDP_HEADER)) { t += sizeof(PA_SDP_HEADER) - 1; From 9f32b7d7eec1a8dbb32cf5348063b580590e4a55 Mon Sep 17 00:00:00 2001 From: redfast00 Date: Thu, 9 Jun 2022 13:57:15 +0200 Subject: [PATCH 005/260] rtp: fix 'size mismatch' on BSD style operating systems On FreeBSD (and probably other BSDs as well), the FIONREAD ioctl on UDP sockets does not return the size of the next datagram (like it does on Linux), but returns the size of the output buffer: this count contain multiple datagrams and also contains the headers. We fixed this by taking the result of the FIONREAD as lower bound for the size, adding an upper bound and then removing the check that the sizes should be exactly the same. Part-of: --- src/modules/rtp/rtp-native.c | 22 ++++++++++++++++------ src/modules/rtp/sap.c | 18 ++++++++++++++---- 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/modules/rtp/rtp-native.c b/src/modules/rtp/rtp-native.c index 86760a627..d1a3911d7 100644 --- a/src/modules/rtp/rtp-native.c +++ b/src/modules/rtp/rtp-native.c @@ -200,7 +200,6 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool, uint32_ uint32_t ssrc; uint8_t payload; unsigned cc; - ssize_t r; uint8_t aux[1024]; bool found_tstamp = false; @@ -209,6 +208,15 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool, uint32_ pa_memchunk_reset(chunk); + /* FIONREAD works on both BSD and Linux, but they do something different: + * - on Linux it returns the amount of bytes in the next datagram + * - on BSDs it returns the total amount of bytes in the output buffer; this can be + * more than one datagram and includes headers + * + * So the result will be a lower bound of how many bytes are needed, but might not be + * the exact size of the buffer size needed. + */ + if (ioctl(c->fd, FIONREAD, &size) < 0) { pa_log_warn("FIONREAD failed: %s", pa_cstrerror(errno)); goto fail; @@ -238,6 +246,9 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool, uint32_ size = 1; } + /* Since size is a lower bound, also constrain it to an upper bound */ + size = PA_MIN(size, 1<<16); + if (c->recv_buf_size < (size_t) size) { do c->recv_buf_size *= 2; @@ -259,12 +270,11 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool, uint32_ m.msg_controllen = sizeof(aux); m.msg_flags = 0; - r = recvmsg(c->fd, &m, 0); - - if (r != size) { - if (r < 0 && errno != EAGAIN && errno != EINTR) - pa_log_warn("recvmsg() failed: %s", r < 0 ? pa_cstrerror(errno) : "size mismatch"); + size = recvmsg(c->fd, &m, 0); + if (size < 0) { + if (errno != EAGAIN && errno != EINTR) + pa_log_warn("recvmsg() failed: %s", pa_cstrerror(errno)); goto fail; } diff --git a/src/modules/rtp/sap.c b/src/modules/rtp/sap.c index 8614022f8..00a648057 100644 --- a/src/modules/rtp/sap.c +++ b/src/modules/rtp/sap.c @@ -146,15 +146,25 @@ int pa_sap_recv(pa_sap_context *c, bool *goodbye) { char *buf = NULL, *e; uint32_t header; unsigned six, ac, k; - ssize_t r; - + pa_assert(c); pa_assert(goodbye); + /* FIONREAD works on both BSD and Linux, but they do something different: + * - on Linux it returns the amount of bytes in the next datagram + * - on BSDs it returns the total amount of bytes in the output buffer; this can be + * more than one datagram and includes headers + * + * So the result will be a lower bound of how many bytes are needed, but might not be + * the exact size of the buffer size needed. + */ + if (ioctl(c->fd, FIONREAD, &size) < 0) { pa_log_warn("FIONREAD failed: %s", pa_cstrerror(errno)); goto fail; } + /* Since size is a lower bound, also constrain it to an upper bound */ + size = PA_MIN(size, 1<<16); buf = pa_xnew(char, (unsigned) size+1); buf[size] = 0; @@ -170,8 +180,8 @@ int pa_sap_recv(pa_sap_context *c, bool *goodbye) { m.msg_controllen = 0; m.msg_flags = 0; - if ((r = recvmsg(c->fd, &m, 0)) != size) { - pa_log_warn("recvmsg() failed: %s", r < 0 ? pa_cstrerror(errno) : "size mismatch"); + if ((size = recvmsg(c->fd, &m, 0)) < 0) { + pa_log_warn("recvmsg() failed: %s", pa_cstrerror(errno)); goto fail; } From 823e46fba0742605f557b68cd591f61624b93966 Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Sun, 12 Jun 2022 21:49:32 +0300 Subject: [PATCH 006/260] build-sys: meson: Make module-console-kit optional Default build configuration would fail to run on a system without systemd-logind (or elogind) and without ConsoleKit daemon responding on dbus interface. Here, module-console-kit would fail to initialize, preventing daemon from starting. Make module-console-kit an optional build feature to allow opt-out. Part-of: --- meson.build | 5 +++++ meson_options.txt | 3 +++ src/modules/meson.build | 7 ++++++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index d4cdbd6a5..c6db7e670 100644 --- a/meson.build +++ b/meson.build @@ -732,6 +732,10 @@ if get_option('daemon') cdata.set('HAVE_SYSTEMD_LOGIN', 1) endif + if get_option('consolekit').enabled() + assert(dbus_dep.found(), 'ConsoleKit requires D-Bus support') + endif + tcpwrap_dep = cc.find_library('wrap', required: get_option('tcpwrap')) if cc.has_header('tcpd.h') and cc.has_function('hosts_access', dependencies : tcpwrap_dep) cdata.set('HAVE_LIBWRAP', 1) @@ -1001,6 +1005,7 @@ summary += [ ' Enable HAL->udev compat: @0@'.format(get_option('hal-compat')), 'Enable systemd units: @0@'.format(systemd_dep.found()), 'Enable elogind: @0@'.format(libelogind_dep.found()), + 'Enable ConsoleKit: @0@'.format(not get_option('consolekit').disabled() and dbus_dep.found()), 'Enable TCP Wrappers: @0@'.format(tcpwrap_dep.found()), 'Enable OpenSSL (for Airtunes): @0@'.format(openssl_dep.found()), 'Database: @0@'.format(get_option('database')), diff --git a/meson_options.txt b/meson_options.txt index b23210072..e7160a3a7 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -99,6 +99,9 @@ option('bluez5-native-headset', option('bluez5-ofono-headset', type : 'boolean', description : 'Optional oFono headset backend support (BlueZ 5)') +option('consolekit', + type : 'feature', value : 'auto', + description : 'Optional ConsoleKit support') option('dbus', type : 'feature', value : 'auto', description : 'Optional D-Bus support') diff --git a/src/modules/meson.build b/src/modules/meson.build index cdf372c8e..1d8004300 100644 --- a/src/modules/meson.build +++ b/src/modules/meson.build @@ -130,7 +130,6 @@ endif if dbus_dep.found() all_modules += [ - [ 'module-console-kit', 'module-console-kit.c', [], [], [dbus_dep] ], [ 'module-dbus-protocol', [ 'dbus/iface-card.c', 'dbus/iface-card.h', 'dbus/iface-card-profile.c', 'dbus/iface-card-profile.h', @@ -147,6 +146,12 @@ if dbus_dep.found() [], [], [dbus_dep] ], [ 'module-rygel-media-server', 'module-rygel-media-server.c', [], [], [dbus_dep], libprotocol_http ], ] + + if not get_option('consolekit').disabled() + all_modules += [ + [ 'module-console-kit', 'module-console-kit.c', [], [], [dbus_dep] ], + ] + endif endif if fftw_dep.found() From ee8bfb49adddd271d8a8cafa796c6f9fa84de48a Mon Sep 17 00:00:00 2001 From: Georg Chini Date: Fri, 17 Jun 2022 13:11:11 +0200 Subject: [PATCH 007/260] combine-sink: Fix threading issue during underrun A recent commit added i->origin sink for the sink inputs of the combine sinks. Therefore pa_sink_process_input_underruns() treated the combine sink like filter sinks. pa_sink_process_input_underruns() calls itself with the origin sink, which is only correct for filter sinks because they run in the thread context of the origin sink. The combine sink however has its own thread context, so pa_sink_process_input_underruns() was executed in the wrong context. This patch fixes the issue by skipping the section for module-combine-sink. Part-of: --- src/pulsecore/sink.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index 3108ae765..0f0dc56fc 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -1016,20 +1016,29 @@ size_t pa_sink_process_input_underruns(pa_sink *s, size_t left_to_play) { if (i->origin_sink) { size_t filter_result, left_to_play_origin; - /* The recursive call works in the origin sink domain ... */ - left_to_play_origin = pa_convert_size(left_to_play, &i->sink->sample_spec, &i->origin_sink->sample_spec); + /* The combine sink sets i->origin sink but has a different threading model + * than the filter sinks. Therefore the recursion below may not be executed + * because pa_sink_process_input_underruns() was not called in the thread + * context of the origin sink. + * FIXME: It is unclear if some other kind of recursion would be necessary + * for the combine sink. */ + if (!i->module || !pa_safe_streq(i->module->name, "module-combine-sink")) { - /* .. and returns the time to sleep before waking up. We need the - * underrun duration for comparisons, so we undo the subtraction on - * the return value... */ - filter_result = left_to_play_origin - pa_sink_process_input_underruns(i->origin_sink, left_to_play_origin); + /* The recursive call works in the origin sink domain ... */ + left_to_play_origin = pa_convert_size(left_to_play, &i->sink->sample_spec, &i->origin_sink->sample_spec); - /* ... and convert it back to the master sink domain */ - filter_result = pa_convert_size(filter_result, &i->origin_sink->sample_spec, &i->sink->sample_spec); + /* .. and returns the time to sleep before waking up. We need the + * underrun duration for comparisons, so we undo the subtraction on + * the return value... */ + filter_result = left_to_play_origin - pa_sink_process_input_underruns(i->origin_sink, left_to_play_origin); - /* Remember the longest underrun so far */ - if (filter_result > result) - result = filter_result; + /* ... and convert it back to the master sink domain */ + filter_result = pa_convert_size(filter_result, &i->origin_sink->sample_spec, &i->sink->sample_spec); + + /* Remember the longest underrun so far */ + if (filter_result > result) + result = filter_result; + } } if (uf == 0) { From dd4dc5e8bce2c03631c3613dbddee1a691bdd17d Mon Sep 17 00:00:00 2001 From: Jan Palus Date: Fri, 17 Jun 2022 14:36:36 +0200 Subject: [PATCH 008/260] bluetooth/gst: Correct var type for GST_TYPE_BITMASK GST_TYPE_BITMASK is 64-bit bit mask while corresponding channel_mask in pulseaudio is int therefore usually 32-bit. Switch to uint64_t instead to match internal representation in gstreamer. Fixes pulseaudio crash on ARM 32-bit when pulseaudio is compiled with gstreamer and either LDAC or aptX support is available. Part-of: --- src/modules/bluetooth/a2dp-codec-gst.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/bluetooth/a2dp-codec-gst.c b/src/modules/bluetooth/a2dp-codec-gst.c index 8ef74be9c..11839c580 100644 --- a/src/modules/bluetooth/a2dp-codec-gst.c +++ b/src/modules/bluetooth/a2dp-codec-gst.c @@ -22,6 +22,7 @@ #endif #include +#include #include #include @@ -82,7 +83,7 @@ fail: static GstCaps *gst_create_caps_from_sample_spec(const pa_sample_spec *ss) { gchar *sample_format; GstCaps *caps; - int channel_mask; + uint64_t channel_mask; switch (ss->format) { case PA_SAMPLE_S16LE: From 82bbf2260c21b3a7f58340d39aff08f7eaebbc9d Mon Sep 17 00:00:00 2001 From: Seong-ho Cho Date: Sat, 11 Jun 2022 14:15:26 +0000 Subject: [PATCH 009/260] Translated using Weblate (Korean) Currently translated at 100.0% (572 of 572 strings) Translation: pulseaudio/pulseaudio Translate-URL: https://translate.fedoraproject.org/projects/pulseaudio/pulseaudio/ko/ Part-of: --- po/ko.po | 105 ++++++++++++++++++++++++++----------------------------- 1 file changed, 50 insertions(+), 55 deletions(-) diff --git a/po/ko.po b/po/ko.po index b3de4c7ae..d4c0a4722 100644 --- a/po/ko.po +++ b/po/ko.po @@ -7,8 +7,8 @@ msgstr "" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" "POT-Creation-Date: 2022-05-16 23:56+0300\n" -"PO-Revision-Date: 2022-05-20 18:18+0000\n" -"Last-Translator: 김인수 \n" +"PO-Revision-Date: 2022-06-12 14:19+0000\n" +"Last-Translator: Seong-ho Cho \n" "Language-Team: Korean \n" "Language: ko\n" @@ -94,14 +94,14 @@ msgstr "" "명령:\n" " -h, --help 도움말을 표시\n" " --version 버전을 표시\n" -" --dump-conf 기본 구성을 덤프\n" -" --dump-modules 사용 가능한 모듈의 목록을 덤프\n" +" --dump-conf 기본 구성 덤프\n" +" --dump-modules 사용 가능한 모듈의 목록 덤프\n" " --dump-resample-methods 사용 가능한 재표본 방식으로 덤프\n" " --cleanup-shm 오래된 공유 메모리 세그멘트 정리\n" " --start 만약 실행되지 않았으면 데몬을 시작\n" " -k --kill 실행 중인 데몬을 제거\n" -" --check 동작 중인 데몬을 위한 점검 (종료 " -"코드만 반환)\n" +" --check 동작 중인 데몬 점검 (종료 코드만 " +"반환)\n" "\n" "OPTIONS:\n" " --system[=BOOL] 시스템-전반의 인스턴스로 실행\n" @@ -110,7 +110,7 @@ msgstr "" " --high-priority[=BOOL] 높은 수준으로 설정을 시도\n" " (root로만 사용 가능, SUID 또는\n" " 높은 RLIMIT_NICE일 때에)\n" -" --realtime[=BOOL] Try to enable realtime scheduling\n" +" --realtime[=BOOL] 실시간 스케쥴링 활성 시도\n" " (root로만 사용 가능, SUID 또는\n" " 높은 RLIMIT_RTPRIO일 때에)\n" " --disallow-module-loading[=BOOL] 시작 후 사용자가 요청 모듈을\n" @@ -121,7 +121,7 @@ msgstr "" " --exit-idle-time=SECS 유휴 상태이고 시간이 경과하면\n" " 데몬을 종료함\n" " --scache-idle-time=SECS 유휴 상태이고 시간이 경과하면\n" -" 자동 적재된 표뵨을 내려 놓음\n" +" 자동 적재된 표본을 내려 놓음\n" " --log-level[=LEVEL] 자세한 표시 수준을 높이거나 설정\n" " -v --verbose 자세한 표시 수준을 높임\n" " --log-target={auto,syslog,stderr,file:PATH,newfile:PATH}\n" @@ -132,11 +132,11 @@ msgstr "" " -p, --dl-search-path=PATH 동적 공유 객체(플러그인)을 위한\n" " 검색 경로를 설정\n" " --resample-method=METHOD 지정한 재표본 방식을 사용\n" -" (사용 가능한 값을 위해 --dump-" -"resample-methods을\n" +" (사용 가능한 값은 --dump-resample-" +"methods 옵션을\n" " 참조)\n" " --use-pid-file[=BOOL] PID 파일을 생성\n" -" --no-cpu-limit[=BOOL] 이를 지원하는 CPU 적재 제한기를\n" +" --no-cpu-limit[=BOOL] 이를 지원하는 CPU 부하 제한기를\n" " 설치하지 않음.\n" " --disable-shm[=BOOL] 공유 메모리 지원을 비활성화.\n" " --enable-memfd[=BOOL] memfd 공유 메모리 지원을 활성화.\n" @@ -145,7 +145,7 @@ msgstr "" " -L, --load=\"MODULE ARGUMENTS\" 지정된 인수와 함께 지정된 " "플러그인\n" " 모듈을 적재\n" -" -F, --file=FILENAME 지정된 스크립트를 실행\n" +" -F, --file=FILENAME 지정 스크립트 실행\n" " -C 시작 후에 동작 중인 TTY에서\n" " 명령 줄을 엽니다\n" "\n" @@ -153,39 +153,39 @@ msgstr "" #: src/daemon/cmdline.c:246 msgid "--daemonize expects boolean argument" -msgstr "--daemonize 에는 부울 인수가 필요합니다" +msgstr "--daemonize 에는 부울 인자 값이 필요합니다" #: src/daemon/cmdline.c:254 msgid "--fail expects boolean argument" -msgstr "--fail 에는 부울 인수가 필요합니다" +msgstr "--fail 에는 부울 인자 값이 필요합니다" #: src/daemon/cmdline.c:265 msgid "" "--log-level expects log level argument (either numeric in range 0..4 or one " "of error, warn, notice, info, debug)." msgstr "" -"--log-level 에는 로그 수준 인수가 필요합니다 (0~4 숫자 범위 또는 오류, 경고, " -"알림, 정보, 디버그 중 하나 )." +"--log-level 에는 로그 수준 인자 값이 필요합니다 (0~4 숫자 범위 또는 오류, " +"경고, 알림, 정보, 디버그 중 하나)." #: src/daemon/cmdline.c:277 msgid "--high-priority expects boolean argument" -msgstr "--high-priority 에는 부울 인수가 필요합니다" +msgstr "--high-priority 에는 부울 인자 값이 필요합니다" #: src/daemon/cmdline.c:285 msgid "--realtime expects boolean argument" -msgstr "--realtime 에는 부울 인수가 필요합니다" +msgstr "--realtime 에는 부울 인자 값이 필요합니다" #: src/daemon/cmdline.c:293 msgid "--disallow-module-loading expects boolean argument" -msgstr "--disallow-module-loading 에는 부울 인수가 필요합니다" +msgstr "--disallow-module-loading 에는 부울 인자 값이 필요합니다" #: src/daemon/cmdline.c:301 msgid "--disallow-exit expects boolean argument" -msgstr "--disallow-exit 에는 부울 인수가 필요합니다" +msgstr "--disallow-exit 에는 부울 인자 값이 필요합니다" #: src/daemon/cmdline.c:309 msgid "--use-pid-file expects boolean argument" -msgstr "--use-pid-file 부울 인수가 필요합니다" +msgstr "--use-pid-file 부울 인자 값이 필요합니다" #: src/daemon/cmdline.c:328 msgid "" @@ -205,32 +205,32 @@ msgstr "" #: src/daemon/cmdline.c:338 msgid "--log-time expects boolean argument" -msgstr "--log-time 에는 부울 인수가 필요합니다" +msgstr "--log-time 에는 부울 인자 값이 필요합니다" #: src/daemon/cmdline.c:346 msgid "--log-meta expects boolean argument" -msgstr "--log-meta 에는 부울 인수가 필요합니다" +msgstr "--log-meta 에는 부울 인자 값이 필요합니다" #: src/daemon/cmdline.c:366 #, c-format msgid "Invalid resample method '%s'." -msgstr "잘못된 리샘플링 방법 '%s'." +msgstr "잘못된 리샘플링 방식 '%s'." #: src/daemon/cmdline.c:373 msgid "--system expects boolean argument" -msgstr "--system 에는 부울 인수가 필요합니다" +msgstr "--system 에는 부울 인자 값이 필요합니다" #: src/daemon/cmdline.c:381 msgid "--no-cpu-limit expects boolean argument" -msgstr "--no-cpu-limit 에는 부울 인수가 필요합니다" +msgstr "--no-cpu-limit 에는 부울 인자 값이 필요합니다" #: src/daemon/cmdline.c:389 msgid "--disable-shm expects boolean argument" -msgstr "--disable-shm 에는 부울 인수가 필요합니다" +msgstr "--disable-shm 에는 부울 인자 값이 필요합니다" #: src/daemon/cmdline.c:397 msgid "--enable-memfd expects boolean argument" -msgstr "--enable-memfd는 부울 인수가 예상됩니다" +msgstr "--enable-memfd는 부울 인자 값이 필요합니다" #: src/daemon/daemon-conf.c:270 #, c-format @@ -301,8 +301,7 @@ msgstr "설정 파일 열기 실패: %s" msgid "" "The specified default channel map has a different number of channels than " "the specified default number of channels." -msgstr "" -"지정된 기본 채널 맵은 지정된 기본 채널 수와는 다른 채널 수를 가지고 있습니다." +msgstr "지정 기본 채널 맵은 지정 기본 채널 수와는 다른 채널 수를 가지고 있습니다." #: src/daemon/daemon-conf.c:788 #, c-format @@ -365,7 +364,7 @@ msgstr "기존 lt_dlopen 로더를 찾는데 실패했습니다." #: src/daemon/ltdl-bind-now.c:131 msgid "Failed to allocate new dl loader." -msgstr "새 dl 로더를 할당하는데 실패했습니다." +msgstr "새 dl 로더 할당에 실패했습니다." #: src/daemon/ltdl-bind-now.c:144 msgid "Failed to add bind-now-loader." @@ -374,22 +373,22 @@ msgstr "bind-now-loader를 추가하는데 실패했습니다." #: src/daemon/main.c:265 #, c-format msgid "Failed to find user '%s'." -msgstr "사용자 '%s'를 찾을 수 없습니다." +msgstr "'%s' 사용자를 찾을 수 없습니다." #: src/daemon/main.c:270 #, c-format msgid "Failed to find group '%s'." -msgstr "그룹 '%s'를 찾을 수 없습니다." +msgstr "'%s' 그룹을 찾을 수 없습니다." #: src/daemon/main.c:279 #, c-format msgid "GID of user '%s' and of group '%s' don't match." -msgstr "사용자 '%s'의 GID와 그룹 '%s'가 일치하지 않습니다." +msgstr "'%s' 사용자의 GID와 '%s' 그룹 정보가 일치하지 않습니다." #: src/daemon/main.c:284 #, c-format msgid "Home directory of user '%s' is not '%s', ignoring." -msgstr "사용자 '%s'의 홈 디렉토리가 '%s'가 아닙니다, 무시됨." +msgstr "'%s' 사용자의 홈 디렉터리가 '%s' 경로가 아닙니다, 무시함." #: src/daemon/main.c:287 src/daemon/main.c:292 #, c-format @@ -413,7 +412,7 @@ msgstr "UID 변경 실패: %s" #: src/daemon/main.c:360 msgid "System wide mode unsupported on this platform." -msgstr "시스템 전역 모드는 이 플랫폼에서 지원되지 않습니다." +msgstr "시스템 전역 모드는 이 플랫폼에서 지원하지 않습니다." #: src/daemon/main.c:650 msgid "Failed to parse command line." @@ -423,8 +422,7 @@ msgstr "명령어 행 분석 실패." msgid "" "System mode refused for non-root user. Only starting the D-Bus server lookup " "service." -msgstr "" -"비 root 사용자에 대해 시스템 모드는 거부되었습니다. D-Bus 서버 검색 서비스만 " +msgstr "비 루트 사용자의 시스템 모드 전환을 거부했습니다. D-Bus 서버 검색 서비스만 " "시작합니다." #: src/daemon/main.c:788 @@ -436,12 +434,12 @@ msgstr "데몬 종료 실패: %s" msgid "" "This program is not intended to be run as root (unless --system is " "specified)." -msgstr "" -"프로그램이 root로 실행되지 않습니다. (실행하려면 --system을 명기하십시오)." +msgstr "이 프로그램은 루트 계정으로 실행하도록 만들지 않았습니다. (실행하려면 --" +"system을 명기하십시오)." #: src/daemon/main.c:820 msgid "Root privileges required." -msgstr "Root 권한이 필요합니다." +msgstr "루트 권한이 필요합니다." #: src/daemon/main.c:827 msgid "--start not supported for system instances." @@ -460,14 +458,12 @@ msgstr "%s에 사용자가 설정한 서버, 이는 로컬에 있습니다. 상 #: src/daemon/main.c:878 msgid "Running in system mode, but --disallow-exit not set." -msgstr "" -"시스템 모드에서 실행중입니다. 하지만 --disallow-exit가 설정되지 않았습니다." +msgstr "시스템 모드에서 실행 중입니다. 하지만 --disallow-exit을 설정하지 않았습니다." #: src/daemon/main.c:881 msgid "Running in system mode, but --disallow-module-loading not set." -msgstr "" -"시스템 모드에서 실행 중입니다. 하지만 --disallow-module-loading이 설정되어 있" -"지 않습니다." +msgstr "시스템 모드에서 실행 중입니다. 하지만 --disallow-module-loading을 설정하지 " +"않았습니다." #: src/daemon/main.c:884 msgid "Running in system mode, forcibly disabling SHM mode." @@ -863,7 +859,7 @@ msgstr "스테레오 듀플렉스" #: src/modules/alsa/alsa-mixer.c:4739 msgid "Mono Chat + 7.1 Surround" -msgstr "모노 Chat + 7.1 Surround" +msgstr "모노 대화 + 7.1 서라운드" #: src/modules/alsa/alsa-mixer.c:4740 src/modules/alsa/module-alsa-card.c:197 #: src/modules/bluetooth/module-bluez5-device.c:2263 @@ -1478,9 +1474,9 @@ msgid "" "e.g. happen if you try to connect to a non-root PulseAudio as a root user, " "over the native protocol. Don't do that.)" msgstr "" -"XDG_RUNTIME_DIR (%s)는 우리(uid %d)가 아니라 uid %d가 소유합니다! (기본적인 " -"통신규약을 통해 비-root가 PluseAudio에 root 사용자로 연결을 시도할 때에 예를 " -"들어 발생 할 수 있습니다. 그렇게 하지 않습니다.)" +"XDG_RUNTIME_DIR (%s)은 우리(uid %d)가 아니라 uid %d가 소유합니다! (자체 " +"프로토콜로 비 루트 펄스오디오 사용자가 루트 사용자 권한으로 연결할 때 이 " +"문제가 일어납니다. 그렇게 하지 마십시오.)" #: src/pulsecore/core-util.h:97 msgid "yes" @@ -1589,7 +1585,7 @@ msgstr "자료 없음" #: src/pulse/error.c:55 msgid "Incompatible protocol version" -msgstr "호환되지 않는 통신규약 버전" +msgstr "호환되지 않는 프로토콜 버전" #: src/pulse/error.c:56 msgid "Too large" @@ -3135,9 +3131,8 @@ msgstr "최소한 객체 경로와 메시지 이름을 지정해야만 합니다 msgid "" "Excess arguments given, they will be ignored. Note that all message " "parameters must be given as a single string." -msgstr "" -"초과 인수가 주어지면, 이들은 무시될 것입니다. 모든 메시지 변수는 단일 문자열" -"로 주어져야 합니다." +msgstr "초과 인자 값을 부여하면 무시합니다. 모든 메시지 변수는 단일 문자열로 " +"주어져야 합니다." #: src/utils/pactl.c:3182 msgid "" @@ -3211,7 +3206,7 @@ msgid "" "to\n" "\n" msgstr "" -"%s [옵션] -- 프로그램 -[ 인수 ...]\n" +"%s [옵션] -- 프로그램 -[ 인자 ...]\n" "\n" "프로그램이 동작 할 때에 일시적으로 PulseAudio를 중지합니다.\n" "\n" From 089287caf1ab024e35c39381bd6f600af68f074b Mon Sep 17 00:00:00 2001 From: Tanu Kaskinen Date: Sat, 18 Jun 2022 09:52:36 +0300 Subject: [PATCH 010/260] i18n: Update .pot and .po files Part-of: --- po/af.po | 18 +- po/as.po | 18 +- po/be.po | 18 +- po/bg.po | 18 +- po/bn_IN.po | 18 +- po/ca.po | 18 +- po/cs.po | 18 +- po/da.po | 18 +- po/de.po | 18 +- po/de_CH.po | 18 +- po/el.po | 18 +- po/eo.po | 18 +- po/es.po | 18 +- po/fi.po | 26 +-- po/fr.po | 18 +- po/gl.po | 18 +- po/gu.po | 18 +- po/he.po | 18 +- po/hi.po | 18 +- po/hr.po | 18 +- po/hu.po | 18 +- po/id.po | 18 +- po/it.po | 18 +- po/ja.po | 18 +- po/ka.po | 18 +- po/kk.po | 18 +- po/kn.po | 18 +- po/ko.po | 114 ++++++------ po/lt.po | 18 +- po/ml.po | 18 +- po/mr.po | 18 +- po/nl.po | 18 +- po/nn.po | 46 ++--- po/oc.po | 18 +- po/or.po | 18 +- po/pa.po | 18 +- po/pl.po | 18 +- po/pt.po | 18 +- po/pt_BR.po | 18 +- po/pulseaudio.pot | 12 +- po/ru.po | 440 ++++++++++++++++++++++------------------------ po/si.po | 18 +- po/sk.po | 18 +- po/sr.po | 18 +- po/sr@latin.po | 18 +- po/sv.po | 18 +- po/ta.po | 18 +- po/te.po | 18 +- po/tr.po | 26 +-- po/uk.po | 18 +- po/zh_CN.po | 18 +- po/zh_TW.po | 18 +- 52 files changed, 742 insertions(+), 750 deletions(-) diff --git a/po/af.po b/po/af.po index 41d455ccc..37c4bb1ad 100644 --- a/po/af.po +++ b/po/af.po @@ -6,7 +6,7 @@ msgstr "" "Project-Id-Version: master\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2019-01-09 12:17+0200\n" "Last-Translator: F Wolff \n" "Language-Team: translate-discuss-af@lists.sourceforge.net\n" @@ -988,8 +988,8 @@ msgid "" "this module is being loaded automatically> use_volume_sharing= " msgstr "" -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "FFT-gebaseerde effenaar op %s" @@ -1046,14 +1046,14 @@ msgstr "Klank op @HOSTNAME@" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "Tonnel vir %s@%s" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "Tonnel na %s/%s" @@ -1390,11 +1390,11 @@ msgstr "" msgid "Invalid log target." msgstr "" -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Ingeboude oudio" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "Modem" diff --git a/po/as.po b/po/as.po index 872f9e41d..66d439589 100644 --- a/po/as.po +++ b/po/as.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: pulseaudio.master-tx.as\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2012-01-30 09:52+0000\n" "Last-Translator: Amitakhya Phukan \n" "Language-Team: Assamese <>\n" @@ -1142,8 +1142,8 @@ msgstr "" "plugin name> label= control=" -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "" @@ -1206,14 +1206,14 @@ msgstr "@HOSTNAME@ ত অ'ডিঅ'" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "" @@ -1564,11 +1564,11 @@ msgstr "" msgid "Invalid log target." msgstr "[%s:%u] লগ লক্ষ্য '%s' বৈধ নহয় ।" -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "আভ্যন্তৰীণ অ'ডিঅ'" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "মোডেম" diff --git a/po/be.po b/po/be.po index 541de8fab..9b11b0e7a 100644 --- a/po/be.po +++ b/po/be.po @@ -9,7 +9,7 @@ msgstr "" "Project-Id-Version: PulseAudio\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2016-07-19 11:06+0300\n" "Last-Translator: Viktar Vaŭčkievič \n" "Language-Team: Belarusian <>\n" @@ -1177,8 +1177,8 @@ msgstr "" "autoloaded=<зададзены, калі гэты модуль загружаны аўтаматычна> " "use_volume_sharing= " -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "" @@ -1243,14 +1243,14 @@ msgstr "Аўдыя на @HOSTNAME@" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "Тунэль для %s@%s" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "Тунэль да %s/%s" @@ -1597,11 +1597,11 @@ msgstr "Не атрымалася адкрыць файлы журнала «%s msgid "Invalid log target." msgstr "Некарэктны журнал." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Убудаванае аўдыя" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "Мадэм" diff --git a/po/bg.po b/po/bg.po index b9048a038..4f925c9e6 100644 --- a/po/bg.po +++ b/po/bg.po @@ -4,7 +4,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2020-10-15 21:30+0000\n" "Last-Translator: Emanuil Novachev \n" "Language-Team: Bulgarian use_volume_sharing= " msgstr "" -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "" @@ -1104,14 +1104,14 @@ msgstr "" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "" @@ -1448,11 +1448,11 @@ msgstr "" msgid "Invalid log target." msgstr "" -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "" diff --git a/po/bn_IN.po b/po/bn_IN.po index d2878c5a4..adfd8001e 100644 --- a/po/bn_IN.po +++ b/po/bn_IN.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: pulseaudio.master-tx.bn_IN\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2012-01-30 09:52+0000\n" "Last-Translator: Runa Bhattacharjee \n" "Language-Team: Bengali INDIA \n" @@ -1157,8 +1157,8 @@ msgstr "" "plugin name> label= control=" -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "" @@ -1221,14 +1221,14 @@ msgstr "@HOSTNAME@-র মধ্যে অডিও" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "" @@ -1579,11 +1579,11 @@ msgstr "" msgid "Invalid log target." msgstr "[%s:%u] লগ টার্গেট '%s' বৈধ নয়।" -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "অভ্যন্তরীণ অডিও" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "মোডেম" diff --git a/po/ca.po b/po/ca.po index cfa7283e9..fa5a53b6e 100644 --- a/po/ca.po +++ b/po/ca.po @@ -28,7 +28,7 @@ msgstr "" "Project-Id-Version: pulseaudio\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2012-01-30 09:52+0000\n" "Last-Translator: Josep Torné Llavall \n" "Language-Team: Catalan \n" @@ -1175,8 +1175,8 @@ msgstr "" "pulgin= label= " "control=" -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "" @@ -1239,14 +1239,14 @@ msgstr "Àudio a @HOSTNAME@" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "Túnel per %s@%s" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "" @@ -1590,11 +1590,11 @@ msgstr "" msgid "Invalid log target." msgstr "" -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Àudio intern" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "Mòdem" diff --git a/po/cs.po b/po/cs.po index ad4d2ae62..fbb056988 100644 --- a/po/cs.po +++ b/po/cs.po @@ -10,7 +10,7 @@ msgstr "" "Project-Id-Version: pulseaudio.master-tx\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2018-09-30 17:34+0200\n" "Last-Translator: Marek Černocký \n" "Language-Team: čeština \n" @@ -1158,8 +1158,8 @@ msgstr "" "channels= channel_map= autoloaded= use_volume_sharing=" -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "Ekvalizér používající FFT na %s" @@ -1225,14 +1225,14 @@ msgstr "Zvuk na @HOSTNAME@" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "Tunel pro %s@%s" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "Tunel do %s/%s" @@ -1582,11 +1582,11 @@ msgstr "" msgid "Invalid log target." msgstr "Neplatný cíl pro záznam." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Vnitřní zvukový systém" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "Modem" diff --git a/po/da.po b/po/da.po index 049efcaee..37ce4d1c2 100644 --- a/po/da.po +++ b/po/da.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: PulseAudio master\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2021-05-21 23:01+0000\n" "Last-Translator: scootergrisen \n" "Language-Team: Danish autoloaded= use_volume_sharing= " -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "FFT-baseret equalizer på %s" @@ -1200,14 +1200,14 @@ msgstr "Lyd på @HOSTNAME@" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "Tunnel for %s@%s" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "Tunnel til %s/%s" @@ -1556,11 +1556,11 @@ msgstr "" msgid "Invalid log target." msgstr "Ugyldigt logmål." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Indbygget lyd" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "Modem" diff --git a/po/de.po b/po/de.po index b59d40d53..c510f5904 100644 --- a/po/de.po +++ b/po/de.po @@ -14,7 +14,7 @@ msgstr "" "Project-Id-Version: pulseaudio.master-tx.de\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2021-12-05 21:16+0000\n" "Last-Translator: Ettore Atalan \n" "Language-Team: German " "use_volume_sharing= " -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "" @@ -1220,14 +1220,14 @@ msgstr "Audio auf @HOSTNAME@" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "Tunnel für %s@%s" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "Tunnel zu %s/%s" @@ -1576,11 +1576,11 @@ msgstr "" msgid "Invalid log target." msgstr "Ungültiges Protokollziel." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Internes Audio" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "Modem" diff --git a/po/de_CH.po b/po/de_CH.po index 8f675a8c8..bd89109d8 100644 --- a/po/de_CH.po +++ b/po/de_CH.po @@ -10,7 +10,7 @@ msgstr "" "Project-Id-Version: pulseaudio\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2012-01-30 09:53+0000\n" "Last-Translator: Fabian Affolter \n" "Language-Team: German \n" @@ -1130,8 +1130,8 @@ msgid "" "this module is being loaded automatically> use_volume_sharing= " msgstr "" -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "" @@ -1191,14 +1191,14 @@ msgstr "" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "" @@ -1543,11 +1543,11 @@ msgstr "" msgid "Invalid log target." msgstr "[%s:%u] Ungültiges Log-Ziel '%s'." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Internes Audio" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "Modem" diff --git a/po/el.po b/po/el.po index 273910c72..18538962c 100644 --- a/po/el.po +++ b/po/el.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: el\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2014-05-08 09:53+0300\n" "Last-Translator: Dimitris Spingos (Δημήτρης Σπίγγος) \n" "Language-Team: team@lists.gnome.gr\n" @@ -1173,8 +1173,8 @@ msgstr "" "autoloaded=<πρίστε αν αυτή η ενότητα θα φορτώνεται αυτόματα> " "use_volume_sharing=<ναι ή όχι> " -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "" @@ -1240,14 +1240,14 @@ msgstr "Ήχος στο @HOSTNAME@" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "Διόδευση για %s@%s" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "Διόδευση για %s/%s" @@ -1597,11 +1597,11 @@ msgstr "" msgid "Invalid log target." msgstr "Άκυρος προορισμός καταγραφής." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Εσωτερικός ήχος" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "Μόντεμ" diff --git a/po/eo.po b/po/eo.po index 8e0bb5981..0e35e26c8 100644 --- a/po/eo.po +++ b/po/eo.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: pulseaudio\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2021-02-05 01:40+0000\n" "Last-Translator: Carmen Bianca Bakker \n" "Language-Team: Esperanto use_volume_sharing= " msgstr "" -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "" @@ -1042,14 +1042,14 @@ msgstr "Sono sur @HOSTNAME@" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "Tunelo por %s@%s" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "Tunelo al %s/%s" @@ -1386,11 +1386,11 @@ msgstr "" msgid "Invalid log target." msgstr "" -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Integrita sono" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "" diff --git a/po/es.po b/po/es.po index 3d205caef..701014014 100644 --- a/po/es.po +++ b/po/es.po @@ -13,7 +13,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2022-01-11 06:16+0000\n" "Last-Translator: Daniel Hernandez \n" "Language-Team: Spanish autoloaded= use_volume_sharing= " -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "Ecualizador basado en FFT en %s" @@ -1216,14 +1216,14 @@ msgstr "Audio en @HOSTNAME@" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "Túnel para %s@%s" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "Túnel a %s/%s" @@ -1571,11 +1571,11 @@ msgstr "" msgid "Invalid log target." msgstr "El destino de registro no es válido." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Audio Interno" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "Módem" diff --git a/po/fi.po b/po/fi.po index edb760b05..4d590877e 100644 --- a/po/fi.po +++ b/po/fi.po @@ -9,7 +9,7 @@ msgstr "" "Project-Id-Version: git trunk\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2022-05-20 18:18+0000\n" "Last-Translator: Jan Kuparinen \n" "Language-Team: Finnish control= " -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "FFT-pohjainen taajuuskorjain %s:lla" @@ -1209,14 +1209,14 @@ msgstr "Ääni koneella @HOSTNAME@" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "Tunneli %s@%s:ta varten" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "Tunneli %s/%s:een" @@ -1566,11 +1566,11 @@ msgstr "" msgid "Invalid log target." msgstr "Virheellinen lokikirjoituksen kohde." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Sisäinen äänentoisto" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "Modeemi" @@ -1972,8 +1972,8 @@ msgstr "" "palvelimella\n" " --volume=ÄÄNENVOIMAKKUUS Määritä (lineaarinen) " "aloitusäänenvoimakkuus väliltä 0...65536\n" -" --rate=NÄYTTEENOTTOTAAJUUS Näytteenottotaajuus hertseinä(oletus:" -" 44100)\n" +" --rate=NÄYTTEENOTTOTAAJUUS Näytteenottotaajuus " +"hertseinä(oletus: 44100)\n" " --format=NÄYTEMUOTO Näytteen tyyppi, yksi seuraavista:" "s16le, s16be, u8, float32le,\n" " float32be, ulaw, alaw, s32le, s32be\n" @@ -1993,8 +1993,8 @@ msgstr "" " --no-remix Älä yli- tai alimiksaa kanavia.\n" " --no-remap Kartoita kanavat indeksin mukaan, " "älä nimen mukaan.\n" -" --latency=TAVUA Pyydä määritettyä latenssia tavuissa." -"\n" +" --latency=TAVUA Pyydä määritettyä latenssia " +"tavuissa.\n" " --process-time=TAVUA Pyydä määritettyä prosessiaikaa " "pyyntöä kohti tavuissa.\n" " --property=ASETUS=ARVO Anna määritetylle asetukselle " diff --git a/po/fr.po b/po/fr.po index 7ec22c68f..c0a9b2f4f 100644 --- a/po/fr.po +++ b/po/fr.po @@ -16,7 +16,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2020-12-13 17:35+0000\n" "Last-Translator: Julien Humbert \n" "Language-Team: French " "use_volume_sharing= " -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "" @@ -1249,14 +1249,14 @@ msgstr "Audio sur @HOSTNAME@" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "Tunnel pour %s@%s" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "Tunnel vers %s/%s" @@ -1606,11 +1606,11 @@ msgstr "" msgid "Invalid log target." msgstr "Cible du journal non valide." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Audio interne" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "Modem" diff --git a/po/gl.po b/po/gl.po index 50afcf945..679da3f59 100644 --- a/po/gl.po +++ b/po/gl.po @@ -11,7 +11,7 @@ msgstr "" "Project-Id-Version: PulseAudio\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2021-09-01 12:04+0000\n" "Last-Translator: Fran Diéguez \n" "Language-Team: Galician autoloaded= " "use_volume_sharing= " -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "Ecualizador baseado en FFT en %s" @@ -1219,14 +1219,14 @@ msgstr "Son en @HOSTNAME@" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "Túnel para %s@%s" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "Túnel a %s/%s" @@ -1576,11 +1576,11 @@ msgstr "" msgid "Invalid log target." msgstr "Obxectivo do rexistro incorrecto." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Audio interno" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "Módem" diff --git a/po/gu.po b/po/gu.po index 77031b60f..e65889f17 100644 --- a/po/gu.po +++ b/po/gu.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: PulseAudio\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2012-01-30 09:53+0000\n" "Last-Translator: Sweta Kothari \n" "Language-Team: Gujarati\n" @@ -1147,8 +1147,8 @@ msgstr "" "plugin name> label= control=" -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "" @@ -1211,14 +1211,14 @@ msgstr "@HOSTNAME@ પર ઓડિયો" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "" @@ -1569,11 +1569,11 @@ msgstr "" msgid "Invalid log target." msgstr "[%s:%u] અયોગ્ય લોગ લક્ષ્ય '%s'." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "આંતરિક ઓડિયો" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "મોડેમ" diff --git a/po/he.po b/po/he.po index f6ff8d57e..5352d73b1 100644 --- a/po/he.po +++ b/po/he.po @@ -6,7 +6,7 @@ msgstr "" "Project-Id-Version: pulseaudio\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2021-05-12 11:02+0000\n" "Last-Translator: Yaron Shahrabani \n" "Language-Team: Hebrew use_volume_sharing= " msgstr "" -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "" @@ -1038,14 +1038,14 @@ msgstr "" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "" @@ -1382,11 +1382,11 @@ msgstr "" msgid "Invalid log target." msgstr "" -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "צליל פנימי" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "מודם" diff --git a/po/hi.po b/po/hi.po index 5de89fd17..b145da8e5 100644 --- a/po/hi.po +++ b/po/hi.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: pulseaudio.master-tx\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2012-01-30 09:54+0000\n" "Last-Translator: Rajesh Ranjan \n" "Language-Team: Hindi \n" @@ -1151,8 +1151,8 @@ msgstr "" "plugin name> label= control=" -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "" @@ -1215,14 +1215,14 @@ msgstr "@HOSTNAME@ पर ऑडियो" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "" @@ -1573,11 +1573,11 @@ msgstr "" msgid "Invalid log target." msgstr "[%s:%u] अवैध लॉग लक्ष्य '%s'." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "आंतरिक ऑडियो" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "मॉडेम" diff --git a/po/hr.po b/po/hr.po index 35ca2be40..7401e1a36 100644 --- a/po/hr.po +++ b/po/hr.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: pulseaudio\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2022-03-28 19:10+0000\n" "Last-Translator: Gogo Gogsi \n" "Language-Team: Croatian " "use_volume_sharing= " -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "FFT temeljen ekvalizator na %s" @@ -1227,14 +1227,14 @@ msgstr "Zvuk na @NAZIVRAČUNALA@" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "Tunel za %s@%s" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "Tunel do %s/%s" @@ -1583,11 +1583,11 @@ msgstr "" msgid "Invalid log target." msgstr "Neispravno odredište zapisa." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Ugrađeni zvuk" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "Modem" diff --git a/po/hu.po b/po/hu.po index 2b0ee6da8..925262a64 100644 --- a/po/hu.po +++ b/po/hu.po @@ -10,7 +10,7 @@ msgstr "" "Project-Id-Version: PulseAudio master\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2021-11-21 13:16+0000\n" "Last-Translator: . Ovari \n" "Language-Team: Hungarian autoloaded= use_volume_sharing= " -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "FFT alapú hangszínszabályzó ezen: %s" @@ -1230,14 +1230,14 @@ msgstr "Hangok ezen a számítógépen: @HOSTNAME@" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "Alagút ennek: %s@%s" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "Alagút ehhez: %s/%s" @@ -1586,11 +1586,11 @@ msgstr "" msgid "Invalid log target." msgstr "Érvénytelen naplózási cél." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Belső hangforrás" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "Modem" diff --git a/po/id.po b/po/id.po index b5a663f82..d4967aade 100644 --- a/po/id.po +++ b/po/id.po @@ -9,7 +9,7 @@ msgstr "" "Project-Id-Version: PulseAudio master\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2021-09-24 12:05+0000\n" "Last-Translator: Andika Triwidada \n" "Language-Team: Indonesian channel_map= autoloaded= use_volume_sharing= " -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "Ekualiser berbasis FFT pada %s" @@ -1200,14 +1200,14 @@ msgstr "Audio pada @HOSTNAME@" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "Tunnel untuk %s@%s" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "Tunnel ke %s/%s" @@ -1557,11 +1557,11 @@ msgstr "" msgid "Invalid log target." msgstr "Target log tidak valid." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Audio Bawaan" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "Modem" diff --git a/po/it.po b/po/it.po index be34abdaf..47a5ad662 100644 --- a/po/it.po +++ b/po/it.po @@ -11,7 +11,7 @@ msgstr "" "Project-Id-Version: pulseaudio\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2021-04-19 20:02+0000\n" "Last-Translator: Milo Casagrande \n" "Language-Team: Italian autoloaded= use_volume_sharing= " -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "Equalizzatore basato su FFT su %s" @@ -1230,14 +1230,14 @@ msgstr "Audio su @HOSTNAME@" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "Tunnel per %s@%s" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "Tunnel verso %s/%s" @@ -1590,11 +1590,11 @@ msgstr "" msgid "Invalid log target." msgstr "Destinazione di registrazione non valida." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Audio interno" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "Modem" diff --git a/po/ja.po b/po/ja.po index b1abbc29a..3b85b70ea 100644 --- a/po/ja.po +++ b/po/ja.po @@ -13,7 +13,7 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2022-02-20 03:16+0000\n" "Last-Translator: Takuro Onoue \n" "Language-Team: Japanese channel_map=<チャンネルマップ> autoloaded=<このモジュールが自動でロード" "されている場合にセット> use_volume_sharing= " -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "" @@ -1205,14 +1205,14 @@ msgstr "@HOSTNAME@ 上のオーディオ" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "%s@%s のトンネル" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "%s/%s へのトンネル" @@ -1560,11 +1560,11 @@ msgstr "" msgid "Invalid log target." msgstr "無効なログターゲット。" -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "内部オーディオ" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "モデム" diff --git a/po/ka.po b/po/ka.po index 6639b6438..d9a89546f 100644 --- a/po/ka.po +++ b/po/ka.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: pulseaudio\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" @@ -978,8 +978,8 @@ msgid "" "this module is being loaded automatically> use_volume_sharing= " msgstr "" -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "" @@ -1036,14 +1036,14 @@ msgstr "" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "" @@ -1380,11 +1380,11 @@ msgstr "" msgid "Invalid log target." msgstr "" -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "" diff --git a/po/kk.po b/po/kk.po index b9b6692d6..d5a8959da 100644 --- a/po/kk.po +++ b/po/kk.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2020-06-30 08:04+0500\n" "Last-Translator: Baurzhan Muftakhidinov \n" "Language-Team: \n" @@ -989,8 +989,8 @@ msgid "" "this module is being loaded automatically> use_volume_sharing= " msgstr "" -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "" @@ -1047,14 +1047,14 @@ msgstr "" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "" @@ -1391,11 +1391,11 @@ msgstr "" msgid "Invalid log target." msgstr "Журнал мақсаты дұрыс емес." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Құрамындағы аудио" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "Модем" diff --git a/po/kn.po b/po/kn.po index 89105bc1c..ed3c6a309 100644 --- a/po/kn.po +++ b/po/kn.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: pulseaudio.master-tx.kn\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2012-01-30 09:54+0000\n" "Last-Translator: Shankar Prasad \n" "Language-Team: Kannada \n" @@ -1153,8 +1153,8 @@ msgstr "" "label= control=<ವಿರಾಮ ಚಿಹ್ನೆಗಳನ್ನು ಹೊಂದಿರುವ ಇನ್‌ಪುಟ್ ನಿಯಂತ್ರಣ " "ಮೌಲ್ಯಗಳ ಪಟ್ಟಿ>" -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "" @@ -1217,14 +1217,14 @@ msgstr "@HOSTNAME@ ನಲ್ಲಿನ ಆಡಿಯೊ" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "" @@ -1575,11 +1575,11 @@ msgstr "" msgid "Invalid log target." msgstr "[%s:%u] ಅಮಾನ್ಯವಾದ ದಾಖಲೆ ಗುರಿ '%s'." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "ಆಂತರಿಕ ಆಡಿಯೊ" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "ಮಾಡೆಮ್" diff --git a/po/ko.po b/po/ko.po index d4c0a4722..0693dc631 100644 --- a/po/ko.po +++ b/po/ko.po @@ -6,7 +6,7 @@ msgstr "" "Project-Id-Version: pulseaudio\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2022-06-12 14:19+0000\n" "Last-Translator: Seong-ho Cho \n" "Language-Team: Korean autoloaded=<이 모듈이 자동으로 로드된다면 설정하십시오" "> use_volume_sharing= " -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "고속퓨리에변환 기반 이퀄라이저 동작 %s" @@ -1153,14 +1158,14 @@ msgstr "호스트 @HOSTNAME@의 오디오" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "%s@%s 위한 터널" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "%s/%s가는 터널" @@ -1474,9 +1479,9 @@ msgid "" "e.g. happen if you try to connect to a non-root PulseAudio as a root user, " "over the native protocol. Don't do that.)" msgstr "" -"XDG_RUNTIME_DIR (%s)은 우리(uid %d)가 아니라 uid %d가 소유합니다! (자체 " -"프로토콜로 비 루트 펄스오디오 사용자가 루트 사용자 권한으로 연결할 때 이 " -"문제가 일어납니다. 그렇게 하지 마십시오.)" +"XDG_RUNTIME_DIR (%s)은 우리(uid %d)가 아니라 uid %d가 소유합니다! (자체 프로" +"토콜로 비 루트 펄스오디오 사용자가 루트 사용자 권한으로 연결할 때 이 문제가 " +"일어납니다. 그렇게 하지 마십시오.)" #: src/pulsecore/core-util.h:97 msgid "yes" @@ -1507,11 +1512,11 @@ msgstr "" msgid "Invalid log target." msgstr "잘못된 기록 대상." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "내장 오디오" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "모뎀" @@ -1904,11 +1909,11 @@ msgstr "" " -v, --verbose 자세한 작업 활성화합니다\n" "\n" " -s, --server=SERVER 연결하고자 하는 서버의 이름\n" -" -d, --device=DEVICE 연결하고자 하는 싱크/원천의 이름. " -"특별한 이름 @DEFAULT_SINK@, @DEFAULT_SOURCE@과 @DEFAULT_MONITOR@는 각기 기본 " -"싱크, 원천과 관리를 지정하는데 사용 될 수 있습니다.\n" -" -n, --client-name=NAME 서버에서 이와 같은 클라이언트를 " -"호출하는 방법\n" +" -d, --device=DEVICE 연결하고자 하는 싱크/원천의 이름. 특" +"별한 이름 @DEFAULT_SINK@, @DEFAULT_SOURCE@과 @DEFAULT_MONITOR@는 각기 기본 싱" +"크, 원천과 관리를 지정하는데 사용 될 수 있습니다.\n" +" -n, --client-name=NAME 서버에서 이와 같은 클라이언트를 호출" +"하는 방법\n" " --stream-name=NAME 서버에서 이와 같은 스트림을 호출하는 " "방법\n" " --volume=VOLUME 범위 0...65536에서 초기(선형) 소리를 " @@ -1921,29 +1926,29 @@ msgstr "" " --channels=CHANNELS 채널의 수, 모노 1, 스테레오 2\n" " (기본값 2)\n" " --channel-map=CHANNELMAP 기본값 대신에 사용하려는 채널맵\n" -" --fix-format 스트림이 연결되고 있는 싱크/" -"원천에서\n" +" --fix-format 스트림이 연결되고 있는 싱크/원천에" +"서\n" " 샘플 형식을 가져옵니다.\n" -" --fix-rate 스트림이 연결되고 있는 싱크/" -"원천에서\n" +" --fix-rate 스트림이 연결되고 있는 싱크/원천에" +"서\n" " 샘플 비율을 가져옵니다.\n" -" --fix-channels 스트림이 연결되고 있는 싱크/" -"원천에서\n" +" --fix-channels 스트림이 연결되고 있는 싱크/원천에" +"서\n" " 채널 수와 채널맵을 가져옵니다.\n" -" --no-remix 채널을 언믹스하거나 다운믹스 하지 " -"않습니다.\n" -" --no-remap 이름 대신에 색인으로 채널을 " -"맵핑합니다.\n" -" --latency=BYTES 바이트 단위로 지정된 지연시간을 " -"요청합니다.\n" -" --process-time=BYTES 바이트 단위로 요청당 지정된 " -"처리시간을 요청합니다.\n" -" --latency-msec=MSEC msec 단위로 지정된 지연시간을 " -"요청합니다.\n" +" --no-remix 채널을 언믹스하거나 다운믹스 하지 않" +"습니다.\n" +" --no-remap 이름 대신에 색인으로 채널을 맵핑합니" +"다.\n" +" --latency=BYTES 바이트 단위로 지정된 지연시간을 요청" +"합니다.\n" +" --process-time=BYTES 바이트 단위로 요청당 지정된 처리시간" +"을 요청합니다.\n" +" --latency-msec=MSEC msec 단위로 지정된 지연시간을 요청합" +"니다.\n" " --process-time-msec=MSEC msec 단위로 요청당 지정된 처리시간을 " "요청합니다.\n" -" --property=PROPERTY=VALUE 지정된 속성을 지정된 값으로 " -"설정합니다.\n" +" --property=PROPERTY=VALUE 지정된 속성을 지정된 값으로 설정합니" +"다.\n" " --raw raw PCM 자료를 기록하거나/재생.\n" " --passthrough 통과 자료.\n" " --file-format[=FFORMAT] 형식화된 PCM 자료 기록/재생.\n" @@ -3131,8 +3136,9 @@ msgstr "최소한 객체 경로와 메시지 이름을 지정해야만 합니다 msgid "" "Excess arguments given, they will be ignored. Note that all message " "parameters must be given as a single string." -msgstr "초과 인자 값을 부여하면 무시합니다. 모든 메시지 변수는 단일 문자열로 " -"주어져야 합니다." +msgstr "" +"초과 인자 값을 부여하면 무시합니다. 모든 메시지 변수는 단일 문자열로 주어져" +"야 합니다." #: src/utils/pactl.c:3182 msgid "" diff --git a/po/lt.po b/po/lt.po index 52bc6c8a3..1fd71c5c9 100644 --- a/po/lt.po +++ b/po/lt.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2019-09-01 16:15+0300\n" "Last-Translator: Moo\n" "Language-Team: \n" @@ -1176,8 +1176,8 @@ msgstr "" "schema> autoloaded= " "use_volume_sharing= " -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "FFT pagrįstas glodintuvas ties %s" @@ -1245,14 +1245,14 @@ msgstr "Garsas ties @HOSTNAME@" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "Tunelis, skirtas %s@%s" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "Tunelis į %s/%s" @@ -1603,11 +1603,11 @@ msgstr "" msgid "Invalid log target." msgstr "Neteisinga žurnalo paskirtis." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Įtaisytas garsas" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "Modemas" diff --git a/po/ml.po b/po/ml.po index f69808218..643bc006d 100644 --- a/po/ml.po +++ b/po/ml.po @@ -6,7 +6,7 @@ msgstr "" "Project-Id-Version: pulseaudio.master-tx.ml\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2012-01-30 09:41+0000\n" "Last-Translator: \n" "Language-Team: \n" @@ -1133,8 +1133,8 @@ msgstr "" "plugin name> label= control=" -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "" @@ -1197,14 +1197,14 @@ msgstr "@HOSTNAME@-ലുള്ള ഓഡിയോ" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "" @@ -1555,11 +1555,11 @@ msgstr "" msgid "Invalid log target." msgstr "[%s:%u] തെറ്റായ ലോഗ് ടാര്‍ഗറ്റ് '%s'." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "ഇന്റേര്‍ണല്‍ ഓഡിയോ" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "മോഡം" diff --git a/po/mr.po b/po/mr.po index ceb33bd68..035c5ad0c 100644 --- a/po/mr.po +++ b/po/mr.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: pulseaudio.master-tx\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2012-01-30 09:54+0000\n" "Last-Translator: Sandeep Shedmake \n" "Language-Team: Marathi \n" @@ -1139,8 +1139,8 @@ msgstr "" "नाव> label= control=<इंपुट कंट्रोल मुल्यांची स्वल्पविराम विभाजीत " "सूची>" -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "" @@ -1203,14 +1203,14 @@ msgstr "@HOSTNAME@ वरील ऑडिओ" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "" @@ -1561,11 +1561,11 @@ msgstr "" msgid "Invalid log target." msgstr "[%s:%u] अवैध लॉग लक्ष्य '%s'." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "आंतरीक ऑडिओ" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "मोडेम" diff --git a/po/nl.po b/po/nl.po index f4ee2c89e..b300a641d 100644 --- a/po/nl.po +++ b/po/nl.po @@ -9,7 +9,7 @@ msgstr "" "Project-Id-Version: pulseaudio.master-tx\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2021-03-30 23:01+0000\n" "Last-Translator: Pjotr Vertaalt \n" "Language-Team: Dutch autoloaded= use_volume_sharing= " -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "FFT-gebaseerd mengpaneel op %s" @@ -1190,14 +1190,14 @@ msgstr "Geluid op @HOSTNAME@" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "Tunnel voor %s@%s" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "Tunnel naar %s/%s" @@ -1546,11 +1546,11 @@ msgstr "" msgid "Invalid log target." msgstr "Ongeldig logboekdoel." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Ingebouwde audio" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "Modem" diff --git a/po/nn.po b/po/nn.po index ec69c5456..c088352d5 100644 --- a/po/nn.po +++ b/po/nn.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2022-05-23 11:18+0000\n" "Last-Translator: Karl Ove Hufthammer \n" "Language-Team: Norwegian Nynorsk channel_map= autoloaded= use_volume_sharing= " -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "FFT-basert lydbalanse­kontroll på %s" @@ -1190,14 +1190,14 @@ msgstr "Lyd på @HOSTNAME@" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "Tunell for %s@%s" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "Tunell til %s/%s" @@ -1548,11 +1548,11 @@ msgstr "" msgid "Invalid log target." msgstr "Ugyldig loggmål." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Innebygd lyd" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "Modem" @@ -1946,8 +1946,8 @@ msgstr "" " --version Vis versjonsinformasjon.\n" "\n" " -r, --record Opprett tilkopling for lydopptak.\n" -" -p, --playback Opprett tilkopling for lydavspeling." -"\n" +" -p, --playback Opprett tilkopling for " +"lydavspeling.\n" "\n" " -v, --verbose Vis meir detaljerte meldingar.\n" "\n" @@ -1955,14 +1955,14 @@ msgstr "" " -d, --device=EINING Namnet på sluket/kjelda å kopla til. " "Du kan bruka namna @DEFAULT_SINK@, @DEFAULT_SOURCE@ og @DEFAULT_MONITOR@ for " "å velja standard sluk/kjelde/avlyttar.\n" -" -n, --client-name=NAMN Kva klienten skal kallast på tenaren." -"\n" -" --stream-name=NAMN Kva straumen skal kallast på tenaren." -"\n" -" --volume=LYDSTYRKE Vel startlydstyrke (lineær). Verdiar:" -" 0–65536.\n" -" --rate=SAMPLINGSRATE Samplingsrate i Hz (standard: 44100)." -"\n" +" -n, --client-name=NAMN Kva klienten skal kallast på " +"tenaren.\n" +" --stream-name=NAMN Kva straumen skal kallast på " +"tenaren.\n" +" --volume=LYDSTYRKE Vel startlydstyrke (lineær). " +"Verdiar: 0–65536.\n" +" --rate=SAMPLINGSRATE Samplingsrate i Hz (standard: " +"44100).\n" " --format=SAMPLEFORMAT Samplingsformat. Sjå\n" " https://www.freedesktop.org/wiki/" "Software/PulseAudio/Documentation/User/SupportedAudioFormats/\n" @@ -1983,8 +1983,8 @@ msgstr "" "frå\n" " sluket/kjelda som straumen vert " "kopla til.\n" -" --no-remix Ikkje oppmiks eller nedmiks kanalar." -"\n" +" --no-remix Ikkje oppmiks eller nedmiks " +"kanalar.\n" " --no-remap Definer kanalar etter indeks, ikkje " "etter namn.\n" " --latency=BYTE Be om valt latenstid, målt i byte.\n" @@ -1998,8 +1998,8 @@ msgstr "" "verdi.\n" " --raw Ta opp / spel av rå PCM-data.\n" " --passthrough Vidaresend lyddata.\n" -" --file-format[=FFORMAT] Ta opp / spel av formatert PCM-data." -"\n" +" --file-format[=FFORMAT] Ta opp / spel av formatert PCM-" +"data.\n" " --list-file-formats Vis tilgjengelege filformat.\n" " --monitor-stream=INDEKS Ta opp frå sluk-inndata med indeksen " "INDEKS.\n" diff --git a/po/oc.po b/po/oc.po index 9da35d004..db97a2a10 100644 --- a/po/oc.po +++ b/po/oc.po @@ -13,7 +13,7 @@ msgstr "" "Project-Id-Version: pulseaudio trunk\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2016-10-12 22:20+0200\n" "Last-Translator: Cédric Valmary (totenoc.eu) \n" "Language-Team: Tot En Òc\n" @@ -1051,8 +1051,8 @@ msgid "" "this module is being loaded automatically> use_volume_sharing= " msgstr "" -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "" @@ -1119,14 +1119,14 @@ msgstr "Audio sus @HOSTNAME@" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "" @@ -1474,11 +1474,11 @@ msgstr "" msgid "Invalid log target." msgstr "" -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Àudio integrat" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "Modèm" diff --git a/po/or.po b/po/or.po index 3b89de797..a57b339c9 100644 --- a/po/or.po +++ b/po/or.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: pulseaudio.master-tx.or\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2012-01-30 09:55+0000\n" "Last-Translator: Manoj Kumar Giri \n" "Language-Team: Oriya \n" @@ -1164,8 +1164,8 @@ msgstr "" "channel_map=<ଚ୍ୟାନେଲ ମ୍ୟାପ> plugin= label= control=<କମା ଦ୍ୱାରା ପୃଥକ ନିବେଶ ନିୟନ୍ତ୍ରଣ ମୂଲ୍ୟ ତାଲିକା>" -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "" @@ -1227,14 +1227,14 @@ msgstr "@HOSTNAME@ ରେ ଧ୍ୱନି" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "" @@ -1584,11 +1584,11 @@ msgstr "" msgid "Invalid log target." msgstr "[%s:%u] ଅବୈଧ ଲଗ ଲକ୍ଷ୍ଯସ୍ଥଳ '%s'।" -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "ଆଭ୍ୟନ୍ତରୀଣ ଧ୍ୱନି" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "ମଡେମ" diff --git a/po/pa.po b/po/pa.po index 55d07be37..c861f250a 100644 --- a/po/pa.po +++ b/po/pa.po @@ -11,7 +11,7 @@ msgstr "" "Project-Id-Version: pulseaudio.master-tx.pa\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2012-01-30 09:55+0000\n" "Last-Translator: Jaswinder Singh \n" "Language-Team: Punjabi/Panjabi \n" @@ -1135,8 +1135,8 @@ msgstr "" "plugin name> label= control=" -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "" @@ -1199,14 +1199,14 @@ msgstr "@HOSTNAME@ ਉੱਪਰ ਆਡੀਓ" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "" @@ -1557,11 +1557,11 @@ msgstr "" msgid "Invalid log target." msgstr "[%s:%u] ਗਲਤ ਲਾਗ ਟਾਰਗੇਟ '%s'।" -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "ਅੰਦਰੂਨੀ ਆਡੀਓ" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "ਮਾਡਮ" diff --git a/po/pl.po b/po/pl.po index b99af3403..afa812abe 100644 --- a/po/pl.po +++ b/po/pl.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: pulseaudio\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2022-05-21 10:06+0000\n" "Last-Translator: Piotr Drąg \n" "Language-Team: Polish autoloaded= use_volume_sharing= " -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "Korektor graficzny na podstawie FFT na %s" @@ -1219,14 +1219,14 @@ msgstr "Dźwięk na @HOSTNAME@" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "Tunel dla %s@%s" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "Tunel do %s/%s" @@ -1576,11 +1576,11 @@ msgstr "" msgid "Invalid log target." msgstr "Nieprawidłowy dziennik docelowy." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Wbudowany dźwięk" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "Modem" diff --git a/po/pt.po b/po/pt.po index 76f94231f..50f3c0ac0 100644 --- a/po/pt.po +++ b/po/pt.po @@ -9,7 +9,7 @@ msgstr "" "Project-Id-Version: pulseaudio\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2020-09-19 04:27+0100\n" "Last-Translator: Juliano de Souza Camargo \n" "Language-Team: Portuguese <>\n" @@ -1172,8 +1172,8 @@ msgstr "" "cargado automaticamente> use_volume_sharing= " "force_flat_volume= " -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "" @@ -1237,14 +1237,14 @@ msgstr "Áudio no @HOSTNAME@" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "" @@ -1595,11 +1595,11 @@ msgstr "" msgid "Invalid log target." msgstr "[%s:%u] ficheiro registo de destino inválido '%s'." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Áudio Interno" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "Modem" diff --git a/po/pt_BR.po b/po/pt_BR.po index befbebd58..62ad3680d 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -10,7 +10,7 @@ msgstr "" "Project-Id-Version: pulseaudio\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2021-08-04 08:04+0000\n" "Last-Translator: Rafael Fontenelle \n" "Language-Team: Portuguese (Brazil) autoloaded= use_volume_sharing= " -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "Equalizador baseado em FFT em %s" @@ -1230,14 +1230,14 @@ msgstr "Áudio em @HOSTNAME@" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "Túnel para %s@%s" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "Túnel para %s/%s" @@ -1587,11 +1587,11 @@ msgstr "" msgid "Invalid log target." msgstr "Alvo do log inválido." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Áudio interno" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "Modem" diff --git a/po/pulseaudio.pot b/po/pulseaudio.pot index c4655b9fa..b4b8552b1 100644 --- a/po/pulseaudio.pot +++ b/po/pulseaudio.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: pulseaudio\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -954,7 +954,7 @@ msgid "" "is being loaded automatically> use_volume_sharing= " msgstr "" -#: src/modules/module-equalizer-sink.c:1094 src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "" @@ -1008,12 +1008,12 @@ msgstr "" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "" -#: src/modules/module-tunnel-sink-new.c:697 src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "" @@ -1348,11 +1348,11 @@ msgstr "" msgid "Invalid log target." msgstr "" -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "" diff --git a/po/ru.po b/po/ru.po index 865980ecb..5286405c3 100644 --- a/po/ru.po +++ b/po/ru.po @@ -9,7 +9,7 @@ msgstr "" "Project-Id-Version: pulseaudio\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2022-05-23 11:18+0000\n" "Last-Translator: Sergey A. \n" "Language-Team: Russian use_volume_sharing=<использовать общий уровень " "громкости (yes или no)> " -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "Эквалайзер на основе БПФ на %s" @@ -1238,18 +1238,14 @@ msgstr "Аудио на @HOSTNAME@" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 -#: src/modules/module-tunnel-sink-new.c:320 -#: src/modules/module-tunnel-source-new.c:305 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "Туннель для %s@%s" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 -#: src/modules/module-tunnel-sink-new.c:564 -#: src/modules/module-tunnel-source-new.c:540 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "Туннель к %s/%s" @@ -1272,10 +1268,9 @@ msgstr "" "приёмника для фильтрации> sink_master=<имя приёмника для фильтрации> " "format=<формат отсчётов> rate=<частота дискретизации> channels=<число " "каналов> channel_map=<схема каналов> use_volume_sharing=<использовать общий " -"уровень (yes или no)> force_flat_volume= hrir=/path/to/" -"left_hrir.wav hrir_left=/path/to/left_hrir.wav hrir_right=/path/to/optional/" -"right_hrir.wav autoloaded=<установлено, если этот модуль загружается " -"автоматически> " +"уровень (yes или no)> force_flat_volume= hrir=/path/to/left_hrir." +"wav hrir_left=/path/to/left_hrir.wav hrir_right=/path/to/optional/right_hrir." +"wav autoloaded=<установлено, если этот модуль загружается автоматически> " #: src/modules/raop/module-raop-discover.c:295 msgid "Unknown device model" @@ -1602,11 +1597,11 @@ msgstr "" msgid "Invalid log target." msgstr "Недопустимый журнал." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Встроенное аудио" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "Модем" @@ -2042,8 +2037,8 @@ msgstr "" "байтах.\n" " --process-time=BYTES Запросить указанное время процесса " "на запрос в байтах.\n" -" --latency-msec=MSEC Запросить указанную задержку в мсек." -"\n" +" --latency-msec=MSEC Запросить указанную задержку в " +"мсек.\n" " --process-time-msec=MSEC Запросить указанное время процесса " "на запрос в мсек.\n" " --property=PROPERTY=VALUE Установить для указанного свойства " @@ -2095,7 +2090,7 @@ msgstr "" "Скомпилировано с libpulse %s\n" "Скомпоновано с libpulse %s\n" -#: src/utils/pacat.c:852 src/utils/pactl.c:2731 src/utils/pactl.c:2720 +#: src/utils/pacat.c:852 src/utils/pactl.c:2731 #, c-format msgid "Invalid client name '%s'" msgstr "Недопустимое имя клиента «%s»" @@ -2168,7 +2163,7 @@ msgstr "" "Предупреждение: указанная спецификация отсчётов будет заменена спецификацией " "из файла." -#: src/utils/pacat.c:1091 src/utils/pactl.c:2806 src/utils/pactl.c:2794 +#: src/utils/pacat.c:1091 src/utils/pactl.c:2806 msgid "Failed to determine sample specification from file." msgstr "Не удалось определить спецификацию отсчётов из файла." @@ -2204,7 +2199,7 @@ msgstr "воспроизведения" msgid "Failed to set media name." msgstr "Не удалось установить имя потока." -#: src/utils/pacat.c:1172 src/utils/pactl.c:3218 src/utils/pactl.c:3206 +#: src/utils/pacat.c:1172 src/utils/pactl.c:3218 msgid "pa_mainloop_new() failed." msgstr "Произошла ошибка при выполнении pa_mainloop_new()." @@ -2212,11 +2207,11 @@ msgstr "Произошла ошибка при выполнении pa_mainloop_ msgid "io_new() failed." msgstr "Произошла ошибка при выполнении io_new()." -#: src/utils/pacat.c:1202 src/utils/pactl.c:3230 src/utils/pactl.c:3218 +#: src/utils/pacat.c:1202 src/utils/pactl.c:3230 msgid "pa_context_new() failed." msgstr "Произошла ошибка при выполнении pa_context_new()." -#: src/utils/pacat.c:1210 src/utils/pactl.c:3236 src/utils/pactl.c:3224 +#: src/utils/pacat.c:1210 src/utils/pactl.c:3236 #, c-format msgid "pa_context_connect() failed: %s" msgstr "Произошла ошибка при выполнении pa_context_connect(): %s" @@ -2225,22 +2220,21 @@ msgstr "Произошла ошибка при выполнении pa_context_c msgid "pa_context_rttime_new() failed." msgstr "Произошла ошибка при выполнении pa_context_rttime_new()." -#: src/utils/pacat.c:1223 src/utils/pactl.c:3241 src/utils/pactl.c:3229 +#: src/utils/pacat.c:1223 src/utils/pactl.c:3241 msgid "pa_mainloop_run() failed." msgstr "Произошла ошибка при выполнении pa_mainloop_run()." -#: src/utils/pacmd.c:51 src/utils/pactl.c:2643 src/utils/pactl.c:2632 +#: src/utils/pacmd.c:51 src/utils/pactl.c:2643 msgid "NAME [ARGS ...]" msgstr "ИМЯ [АРГУМЕНТЫ ...]" #: src/utils/pacmd.c:52 src/utils/pacmd.c:60 src/utils/pactl.c:2644 -#: src/utils/pactl.c:2651 src/utils/pactl.c:2652 src/utils/pactl.c:2633 -#: src/utils/pactl.c:2640 src/utils/pactl.c:2641 +#: src/utils/pactl.c:2651 src/utils/pactl.c:2652 msgid "NAME|#N" msgstr "ИМЯ|№" #: src/utils/pacmd.c:53 src/utils/pacmd.c:63 src/utils/pactl.c:2642 -#: src/utils/pactl.c:2649 src/utils/pactl.c:2631 src/utils/pactl.c:2638 +#: src/utils/pactl.c:2649 msgid "NAME" msgstr "ИМЯ" @@ -2253,7 +2247,6 @@ msgid "#N VOLUME" msgstr "№ ГРОМКОСТЬ" #: src/utils/pacmd.c:56 src/utils/pacmd.c:70 src/utils/pactl.c:2646 -#: src/utils/pactl.c:2635 msgid "NAME|#N 1|0" msgstr "ИМЯ|№ 1|0" @@ -2289,7 +2282,7 @@ msgstr "ПУТЬ" msgid "FILENAME SINK|#N" msgstr "ИМЯ_ФАЙЛА АУДИОПРИЁМНИК|№" -#: src/utils/pacmd.c:69 src/utils/pactl.c:2645 src/utils/pactl.c:2634 +#: src/utils/pacmd.c:69 src/utils/pactl.c:2645 msgid "#N SINK|SOURCE" msgstr "№ АУДИОПРИЁМНИК|ИСТОЧНИК" @@ -2297,15 +2290,15 @@ msgstr "№ АУДИОПРИЁМНИК|ИСТОЧНИК" msgid "1|0" msgstr "1|0" -#: src/utils/pacmd.c:72 src/utils/pactl.c:2647 src/utils/pactl.c:2636 +#: src/utils/pacmd.c:72 src/utils/pactl.c:2647 msgid "CARD PROFILE" msgstr "ПЛАТА ПРОФИЛЬ" -#: src/utils/pacmd.c:73 src/utils/pactl.c:2650 src/utils/pactl.c:2639 +#: src/utils/pacmd.c:73 src/utils/pactl.c:2650 msgid "NAME|#N PORT" msgstr "ИМЯ|№ ПОРТ" -#: src/utils/pacmd.c:74 src/utils/pactl.c:2658 src/utils/pactl.c:2647 +#: src/utils/pacmd.c:74 src/utils/pactl.c:2658 msgid "CARD-NAME|CARD-#N PORT OFFSET" msgstr "ИМЯ_ПЛАТЫ|№_ПЛАТЫ ПОРТ ЗАДЕРЖКА" @@ -2321,7 +2314,7 @@ msgstr "ЧИСЛОВОЙ-УРОВЕНЬ" msgid "FRAMES" msgstr "КАДРОВ" -#: src/utils/pacmd.c:80 src/utils/pactl.c:2659 src/utils/pactl.c:2648 +#: src/utils/pacmd.c:80 src/utils/pactl.c:2659 msgid "RECIPIENT MESSAGE [MESSAGE_PARAMETERS]" msgstr "СООБЩЕНИЕ ПОЛУЧАТЕЛЯ [ПАРАМЕТРЫ_СООБЩЕНИЯ]" @@ -3019,15 +3012,15 @@ msgstr "Получен сигнал для остановки (SIGINT), выхо msgid "Invalid volume specification" msgstr "Недопустимое значение громкости" -#: src/utils/pactl.c:2581 src/utils/pactl.c:2570 +#: src/utils/pactl.c:2581 msgid "Volume outside permissible range.\n" msgstr "Указанная громкость выходит за границы разрешённого диапазона.\n" -#: src/utils/pactl.c:2594 src/utils/pactl.c:2583 +#: src/utils/pactl.c:2594 msgid "Invalid number of volume specifications.\n" msgstr "Недопустимое количество значений громкости.\n" -#: src/utils/pactl.c:2606 src/utils/pactl.c:2595 +#: src/utils/pactl.c:2606 msgid "Inconsistent volume specification.\n" msgstr "Несогласованные способы указания значений громкости.\n" @@ -3039,46 +3032,43 @@ msgstr "Несогласованные способы указания знач #: src/utils/pactl.c:2651 src/utils/pactl.c:2652 src/utils/pactl.c:2653 #: src/utils/pactl.c:2654 src/utils/pactl.c:2655 src/utils/pactl.c:2656 #: src/utils/pactl.c:2657 src/utils/pactl.c:2658 src/utils/pactl.c:2659 -#: src/utils/pactl.c:2660 src/utils/pactl.c:2625 src/utils/pactl.c:2626 -#: src/utils/pactl.c:2627 src/utils/pactl.c:2628 src/utils/pactl.c:2629 -#: src/utils/pactl.c:2630 src/utils/pactl.c:2631 src/utils/pactl.c:2632 -#: src/utils/pactl.c:2633 src/utils/pactl.c:2634 src/utils/pactl.c:2635 +#: src/utils/pactl.c:2660 msgid "[options]" msgstr "[параметры]" -#: src/utils/pactl.c:2638 src/utils/pactl.c:2627 +#: src/utils/pactl.c:2638 msgid "[TYPE]" msgstr "[ТИП]" -#: src/utils/pactl.c:2640 src/utils/pactl.c:2629 +#: src/utils/pactl.c:2640 msgid "FILENAME [NAME]" msgstr "ИМЯ_ФАЙЛА [ИМЯ]" -#: src/utils/pactl.c:2641 src/utils/pactl.c:2630 +#: src/utils/pactl.c:2641 msgid "NAME [SINK]" msgstr "ИМЯ [АУДИОПРИЁМНИК]" -#: src/utils/pactl.c:2653 src/utils/pactl.c:2642 +#: src/utils/pactl.c:2653 msgid "NAME|#N VOLUME [VOLUME ...]" msgstr "ИМЯ|№ ГРОМКОСТЬ [ГРОМКОСТЬ ...]" -#: src/utils/pactl.c:2654 src/utils/pactl.c:2643 +#: src/utils/pactl.c:2654 msgid "#N VOLUME [VOLUME ...]" msgstr "№ ГРОМКОСТЬ [ГРОМКОСТЬ ...]" -#: src/utils/pactl.c:2655 src/utils/pactl.c:2644 +#: src/utils/pactl.c:2655 msgid "NAME|#N 1|0|toggle" msgstr "ИМЯ|№ 1|0|toggle" -#: src/utils/pactl.c:2656 src/utils/pactl.c:2645 +#: src/utils/pactl.c:2656 msgid "#N 1|0|toggle" msgstr "№ 1|0|toggle" -#: src/utils/pactl.c:2657 src/utils/pactl.c:2646 +#: src/utils/pactl.c:2657 msgid "#N FORMATS" msgstr "№ ФОРМАТЫ" -#: src/utils/pactl.c:2661 src/utils/pactl.c:2650 +#: src/utils/pactl.c:2661 #, c-format msgid "" "\n" @@ -3090,7 +3080,7 @@ msgstr "" "можно использовать для указания аудиоприёмника, источника и монитора, " "используемых по умолчанию.\n" -#: src/utils/pactl.c:2664 src/utils/pactl.c:2653 +#: src/utils/pactl.c:2664 #, c-format msgid "" "\n" @@ -3113,7 +3103,7 @@ msgstr "" " -s, --server=СЕРВЕР Имя сервера для подключения\n" " -n, --client-name=ИМЯ Имя этого клиента на сервере\n" -#: src/utils/pactl.c:2707 src/utils/pactl.c:2696 +#: src/utils/pactl.c:2707 #, c-format msgid "" "pactl %s\n" @@ -3124,66 +3114,65 @@ msgstr "" "Скомпилировано с libpulse %s\n" "Скомпоновано с libpulse %s\n" -#: src/utils/pactl.c:2751 src/utils/pactl.c:2739 +#: src/utils/pactl.c:2751 #, c-format msgid "Invalid format value '%s'" msgstr "Недопустимое значение формата «%s»" -#: src/utils/pactl.c:2778 src/utils/pactl.c:2766 +#: src/utils/pactl.c:2778 #, c-format msgid "Specify nothing, or one of: %s" msgstr "Не указывайте ничего либо укажите одно из: %s" -#: src/utils/pactl.c:2788 src/utils/pactl.c:2776 +#: src/utils/pactl.c:2788 msgid "Please specify a sample file to load" msgstr "Необходимо указать файл, из которого будет загружен сэмпл" -#: src/utils/pactl.c:2801 src/utils/pactl.c:2789 +#: src/utils/pactl.c:2801 msgid "Failed to open sound file." msgstr "Не удалось открыть аудиофайл." -#: src/utils/pactl.c:2813 src/utils/pactl.c:2801 +#: src/utils/pactl.c:2813 msgid "Warning: Failed to determine sample specification from file." msgstr "Предупреждение: не удалось определить спецификацию отсчётов из файла." -#: src/utils/pactl.c:2823 src/utils/pactl.c:2811 +#: src/utils/pactl.c:2823 msgid "You have to specify a sample name to play" msgstr "Необходимо указать имя сэмпла для воспроизведения" -#: src/utils/pactl.c:2835 src/utils/pactl.c:2823 +#: src/utils/pactl.c:2835 msgid "You have to specify a sample name to remove" msgstr "Необходимо указать имя сэмпла для удаления" -#: src/utils/pactl.c:2844 src/utils/pactl.c:2832 +#: src/utils/pactl.c:2844 msgid "You have to specify a sink input index and a sink" msgstr "Необходимо указать номер входа аудиоприёмника и аудиоприёмник" -#: src/utils/pactl.c:2854 src/utils/pactl.c:2842 +#: src/utils/pactl.c:2854 msgid "You have to specify a source output index and a source" msgstr "Необходимо указать номер выхода источника и источник" -#: src/utils/pactl.c:2869 src/utils/pactl.c:2857 +#: src/utils/pactl.c:2869 msgid "You have to specify a module name and arguments." msgstr "Необходимо указать имя модуля и аргументы." -#: src/utils/pactl.c:2889 src/utils/pactl.c:2877 +#: src/utils/pactl.c:2889 msgid "You have to specify a module index or name" msgstr "Необходимо указать номер или имя модуля" -#: src/utils/pactl.c:2902 src/utils/pactl.c:2890 +#: src/utils/pactl.c:2902 msgid "" "You may not specify more than one sink. You have to specify a boolean value." msgstr "" "Нельзя указывать больше одного аудиоприёмника. Необходимо указать логическое " "значение." -#: src/utils/pactl.c:2907 src/utils/pactl.c:2927 src/utils/pactl.c:2895 -#: src/utils/pactl.c:2915 +#: src/utils/pactl.c:2907 src/utils/pactl.c:2927 msgid "Invalid suspend specification." msgstr "" "Недопустимое значение операции приостановки, ожидалось логическое значение." -#: src/utils/pactl.c:2922 src/utils/pactl.c:2910 +#: src/utils/pactl.c:2922 msgid "" "You may not specify more than one source. You have to specify a boolean " "value." @@ -3191,61 +3180,59 @@ msgstr "" "Нельзя указывать больше одного источника. Необходимо указать логическое " "значение." -#: src/utils/pactl.c:2939 src/utils/pactl.c:2927 +#: src/utils/pactl.c:2939 msgid "You have to specify a card name/index and a profile name" msgstr "Необходимо указать имя или номер звуковой платы и имя профиля" -#: src/utils/pactl.c:2950 src/utils/pactl.c:2938 +#: src/utils/pactl.c:2950 msgid "You have to specify a sink name/index and a port name" msgstr "Необходимо указать имя или номер аудиоприёмника и имя порта" -#: src/utils/pactl.c:2961 src/utils/pactl.c:2949 +#: src/utils/pactl.c:2961 msgid "You have to specify a sink name" msgstr "Необходимо указать имя аудиоприёмника" -#: src/utils/pactl.c:2974 src/utils/pactl.c:2962 +#: src/utils/pactl.c:2974 msgid "You have to specify a source name/index and a port name" msgstr "Необходимо указать имя или номер источника и имя порта" -#: src/utils/pactl.c:2985 src/utils/pactl.c:2973 +#: src/utils/pactl.c:2985 msgid "You have to specify a source name" msgstr "Необходимо указать имя источника" -#: src/utils/pactl.c:2998 src/utils/pactl.c:3076 src/utils/pactl.c:2986 -#: src/utils/pactl.c:3064 +#: src/utils/pactl.c:2998 src/utils/pactl.c:3076 msgid "You have to specify a sink name/index" msgstr "Необходимо указать имя или номер аудиоприёмника" -#: src/utils/pactl.c:3008 src/utils/pactl.c:2996 +#: src/utils/pactl.c:3008 msgid "You have to specify a sink name/index and a volume" msgstr "Необходимо указать имя или номер аудиоприёмника и громкость" -#: src/utils/pactl.c:3021 src/utils/pactl.c:3101 src/utils/pactl.c:3009 -#: src/utils/pactl.c:3089 +#: src/utils/pactl.c:3021 src/utils/pactl.c:3101 msgid "You have to specify a source name/index" msgstr "Необходимо указать имя или номер источника" -#: src/utils/pactl.c:3031 src/utils/pactl.c:3019 +#: src/utils/pactl.c:3031 msgid "You have to specify a source name/index and a volume" msgstr "Необходимо указать имя или номер источника и громкость" -#: src/utils/pactl.c:3044 src/utils/pactl.c:3032 +#: src/utils/pactl.c:3044 msgid "You have to specify a sink input index and a volume" msgstr "Необходимо указать номер входа аудиоприёмника и громкость" -#: src/utils/pactl.c:3049 src/utils/pactl.c:3037 +#: src/utils/pactl.c:3049 msgid "Invalid sink input index" msgstr "Недопустимый номер входа аудиоприёмника" -#: src/utils/pactl.c:3060 src/utils/pactl.c:3048 +#: src/utils/pactl.c:3060 msgid "You have to specify a source output index and a volume" msgstr "Необходимо указать номер выхода источника и громкость" -#: src/utils/pactl.c:3065 src/utils/pactl.c:3053 +#: src/utils/pactl.c:3065 msgid "Invalid source output index" msgstr "Недопустимый номер выхода источника" -#: src/utils/pactl.c:3086 src/utils/pactl.c:3074 +#: src/utils/pactl.c:3086 msgid "" "You have to specify a sink name/index and a mute action (0, 1, or 'toggle')" msgstr "" @@ -3253,30 +3240,29 @@ msgstr "" "выключения звука (0, 1 или «toggle»)" #: src/utils/pactl.c:3091 src/utils/pactl.c:3116 src/utils/pactl.c:3136 -#: src/utils/pactl.c:3154 src/utils/pactl.c:3079 src/utils/pactl.c:3104 -#: src/utils/pactl.c:3124 src/utils/pactl.c:3142 +#: src/utils/pactl.c:3154 msgid "Invalid mute specification" msgstr "Недопустимое логическое значение выключения звука" -#: src/utils/pactl.c:3111 src/utils/pactl.c:3099 +#: src/utils/pactl.c:3111 msgid "" "You have to specify a source name/index and a mute action (0, 1, or 'toggle')" msgstr "" "Необходимо указать имя или номер источника и логическое значение выключения " "звука (0, 1 или «toggle»)" -#: src/utils/pactl.c:3126 src/utils/pactl.c:3114 +#: src/utils/pactl.c:3126 msgid "" "You have to specify a sink input index and a mute action (0, 1, or 'toggle')" msgstr "" "Необходимо указать номер входа аудиоприёмника и логическое значение " "выключения звука (0, 1 или «toggle»)" -#: src/utils/pactl.c:3131 src/utils/pactl.c:3119 +#: src/utils/pactl.c:3131 msgid "Invalid sink input index specification" msgstr "Недопустимый номер входа аудиоприёмника" -#: src/utils/pactl.c:3144 src/utils/pactl.c:3132 +#: src/utils/pactl.c:3144 msgid "" "You have to specify a source output index and a mute action (0, 1, or " "'toggle')" @@ -3284,15 +3270,15 @@ msgstr "" "Необходимо указать номер выхода источника и логическое значение выключения " "звука (0, 1 или «toggle»)" -#: src/utils/pactl.c:3149 src/utils/pactl.c:3137 +#: src/utils/pactl.c:3149 msgid "Invalid source output index specification" msgstr "Недопустимый номер выхода источника" -#: src/utils/pactl.c:3162 src/utils/pactl.c:3150 +#: src/utils/pactl.c:3162 msgid "You have to specify at least an object path and a message name" msgstr "Вы должны указать как минимум путь к объекту и имя сообщения" -#: src/utils/pactl.c:3160 +#: src/utils/pactl.c:3172 msgid "" "Excess arguments given, they will be ignored. Note that all message " "parameters must be given as a single string." @@ -3300,7 +3286,7 @@ msgstr "" "Даны лишние аргументы, они будут проигнорированы. Обратите внимание, что все " "параметры сообщения должны быть предоставлены в виде одной строки." -#: src/utils/pactl.c:3182 src/utils/pactl.c:3170 +#: src/utils/pactl.c:3182 msgid "" "You have to specify a sink index and a semicolon-separated list of supported " "formats" @@ -3308,15 +3294,15 @@ msgstr "" "Необходимо указать номер аудиоприёмника и разделённый запятыми список " "поддерживаемых форматов" -#: src/utils/pactl.c:3194 src/utils/pactl.c:3182 +#: src/utils/pactl.c:3194 msgid "You have to specify a card name/index, a port name and a latency offset" msgstr "Необходимо указать имя или номер звуковой платы, имя порта и задержку" -#: src/utils/pactl.c:3201 src/utils/pactl.c:3189 +#: src/utils/pactl.c:3201 msgid "Could not parse latency offset" msgstr "Недопустимое значение задержки" -#: src/utils/pactl.c:3213 src/utils/pactl.c:3201 +#: src/utils/pactl.c:3213 msgid "No valid command specified." msgstr "Имя команды не указано или не распознано." @@ -3480,134 +3466,134 @@ msgstr "Не удалось загрузить данные cookie.\n" msgid "Not yet implemented.\n" msgstr "Не реализовано.\n" -#: src/utils/pacat.c:676 -#, c-format -msgid "" -"%s [options]\n" -"%s\n" -"\n" -" -h, --help Show this help\n" -" --version Show version\n" -"\n" -" -r, --record Create a connection for recording\n" -" -p, --playback Create a connection for playback\n" -"\n" -" -v, --verbose Enable verbose operations\n" -"\n" -" -s, --server=SERVER The name of the server to connect " -"to\n" -" -d, --device=DEVICE The name of the sink/source to " -"connect to\n" -" -n, --client-name=NAME How to call this client on the " -"server\n" -" --stream-name=NAME How to call this stream on the " -"server\n" -" --volume=VOLUME Specify the initial (linear) volume " -"in range 0...65536\n" -" --rate=SAMPLERATE The sample rate in Hz (defaults to " -"44100)\n" -" --format=SAMPLEFORMAT The sample format, see\n" -" https://www.freedesktop.org/wiki/" -"Software/PulseAudio/Documentation/User/SupportedAudioFormats/\n" -" for possible values (defaults to " -"s16ne)\n" -" --channels=CHANNELS The number of channels, 1 for mono, " -"2 for stereo\n" -" (defaults to 2)\n" -" --channel-map=CHANNELMAP Channel map to use instead of the " -"default\n" -" --fix-format Take the sample format from the sink/" -"source the stream is\n" -" being connected to.\n" -" --fix-rate Take the sampling rate from the sink/" -"source the stream is\n" -" being connected to.\n" -" --fix-channels Take the number of channels and the " -"channel map\n" -" from the sink/source the stream is " -"being connected to.\n" -" --no-remix Don't upmix or downmix channels.\n" -" --no-remap Map channels by index instead of " -"name.\n" -" --latency=BYTES Request the specified latency in " -"bytes.\n" -" --process-time=BYTES Request the specified process time " -"per request in bytes.\n" -" --latency-msec=MSEC Request the specified latency in " -"msec.\n" -" --process-time-msec=MSEC Request the specified process time " -"per request in msec.\n" -" --property=PROPERTY=VALUE Set the specified property to the " -"specified value.\n" -" --raw Record/play raw PCM data.\n" -" --passthrough Passthrough data.\n" -" --file-format[=FFORMAT] Record/play formatted PCM data.\n" -" --list-file-formats List available file formats.\n" -" --monitor-stream=INDEX Record from the sink input with " -"index INDEX.\n" -msgstr "" -"%s [параметры]\n" -"%s\n" -"\n" -" -h, --help Показать эту справку\n" -" --version Показать сведения о версии\n" -"\n" -" -r, --record Создать соединение для записи\n" -" -p, --playback Создать соединение для " -"воспроизведения\n" -"\n" -" -v, --verbose Включить подробные операции\n" -"\n" -" -s, --server=СЕРВЕР Имя сервера для подключения\n" -" -d, --device=УСТРОЙСТВО Имя приёмника/источника для " -"подключения\n" -" -n, --client-name=ИМЯ Имя этого клиента на сервере\n" -" --stream-name=ИМЯ Имя этого потока на сервере\n" -" --volume=VOLUME Указать начальную (линейную) " -"громкость в диапазоне 0...65536\n" -" --rate=SAMPLERATE Частота дискретизации в Гц (по " -"умолчанию 44100)\n" -" --format=SAMPLEFORMAT Формат выборки, смотрите\n" -" https://www.freedesktop.org/wiki/" -"Software/PulseAudio/Documentation/User/SupportedAudioFormats/\n" -" возможные значения (по умолчанию " -"s16ne)\n" -" --channels=КАНАЛЫ Количество каналов, 1 для моно, 2 " -"для стерео\n" -" (по умолчанию 2)\n" -" --channel-map=CHANNELMAP Карта каналов для использования " -"вместо установленной по умолчанию\n" -" --fix-format Взять образец формата из приёмника/" -"источника, к которому\n" -" подключен поток.\n" -" --fix-rate Взять частоту дискретизации из " -"приёмника/источника, к которому\n" -" подключен поток.\n" -" --fix-channels Взять количество каналов и карту " -"каналов\n" -" из приёмника/источника, к которому " -"подключен поток.\n" -" --no-remix Не менять число каналов.\n" -" --no-remap Сопоставлять каналы по индексу, а не " -"по имени.\n" -" --latency=BYTES Запросить указанную задержку в " -"байтах.\n" -" --process-time=BYTES Запросить указанное время процесса " -"на запрос в байтах.\n" -" --latency-msec=MSEC Запросить указанную задержку в мсек." -"\n" -" --process-time-msec=MSEC Запросить указанное время процесса " -"на запрос в мсек.\n" -" --property=PROPERTY=VALUE Установить для указанного свойства " -"указанное значение.\n" -" --raw Запись/воспроизведение " -"необработанных данных PCM.\n" -" --passthrough Пропускать данные.\n" -" --file-format[=FFORMAT] Запись/воспроизведение " -"форматированных данных PCM.\n" -" --list-file-formats Список доступных форматов файлов.\n" -" --monitor-stream=INDEX Запись с входа приёмника с индексом " -"INDEX.\n" +#~ msgid "" +#~ "%s [options]\n" +#~ "%s\n" +#~ "\n" +#~ " -h, --help Show this help\n" +#~ " --version Show version\n" +#~ "\n" +#~ " -r, --record Create a connection for " +#~ "recording\n" +#~ " -p, --playback Create a connection for playback\n" +#~ "\n" +#~ " -v, --verbose Enable verbose operations\n" +#~ "\n" +#~ " -s, --server=SERVER The name of the server to connect " +#~ "to\n" +#~ " -d, --device=DEVICE The name of the sink/source to " +#~ "connect to\n" +#~ " -n, --client-name=NAME How to call this client on the " +#~ "server\n" +#~ " --stream-name=NAME How to call this stream on the " +#~ "server\n" +#~ " --volume=VOLUME Specify the initial (linear) " +#~ "volume in range 0...65536\n" +#~ " --rate=SAMPLERATE The sample rate in Hz (defaults " +#~ "to 44100)\n" +#~ " --format=SAMPLEFORMAT The sample format, see\n" +#~ " https://www.freedesktop.org/wiki/" +#~ "Software/PulseAudio/Documentation/User/SupportedAudioFormats/\n" +#~ " for possible values (defaults to " +#~ "s16ne)\n" +#~ " --channels=CHANNELS The number of channels, 1 for " +#~ "mono, 2 for stereo\n" +#~ " (defaults to 2)\n" +#~ " --channel-map=CHANNELMAP Channel map to use instead of the " +#~ "default\n" +#~ " --fix-format Take the sample format from the " +#~ "sink/source the stream is\n" +#~ " being connected to.\n" +#~ " --fix-rate Take the sampling rate from the " +#~ "sink/source the stream is\n" +#~ " being connected to.\n" +#~ " --fix-channels Take the number of channels and " +#~ "the channel map\n" +#~ " from the sink/source the stream " +#~ "is being connected to.\n" +#~ " --no-remix Don't upmix or downmix channels.\n" +#~ " --no-remap Map channels by index instead of " +#~ "name.\n" +#~ " --latency=BYTES Request the specified latency in " +#~ "bytes.\n" +#~ " --process-time=BYTES Request the specified process " +#~ "time per request in bytes.\n" +#~ " --latency-msec=MSEC Request the specified latency in " +#~ "msec.\n" +#~ " --process-time-msec=MSEC Request the specified process " +#~ "time per request in msec.\n" +#~ " --property=PROPERTY=VALUE Set the specified property to the " +#~ "specified value.\n" +#~ " --raw Record/play raw PCM data.\n" +#~ " --passthrough Passthrough data.\n" +#~ " --file-format[=FFORMAT] Record/play formatted PCM data.\n" +#~ " --list-file-formats List available file formats.\n" +#~ " --monitor-stream=INDEX Record from the sink input with " +#~ "index INDEX.\n" +#~ msgstr "" +#~ "%s [параметры]\n" +#~ "%s\n" +#~ "\n" +#~ " -h, --help Показать эту справку\n" +#~ " --version Показать сведения о версии\n" +#~ "\n" +#~ " -r, --record Создать соединение для записи\n" +#~ " -p, --playback Создать соединение для " +#~ "воспроизведения\n" +#~ "\n" +#~ " -v, --verbose Включить подробные операции\n" +#~ "\n" +#~ " -s, --server=СЕРВЕР Имя сервера для подключения\n" +#~ " -d, --device=УСТРОЙСТВО Имя приёмника/источника для " +#~ "подключения\n" +#~ " -n, --client-name=ИМЯ Имя этого клиента на сервере\n" +#~ " --stream-name=ИМЯ Имя этого потока на сервере\n" +#~ " --volume=VOLUME Указать начальную (линейную) " +#~ "громкость в диапазоне 0...65536\n" +#~ " --rate=SAMPLERATE Частота дискретизации в Гц (по " +#~ "умолчанию 44100)\n" +#~ " --format=SAMPLEFORMAT Формат выборки, смотрите\n" +#~ " https://www.freedesktop.org/wiki/" +#~ "Software/PulseAudio/Documentation/User/SupportedAudioFormats/\n" +#~ " возможные значения (по умолчанию " +#~ "s16ne)\n" +#~ " --channels=КАНАЛЫ Количество каналов, 1 для моно, 2 " +#~ "для стерео\n" +#~ " (по умолчанию 2)\n" +#~ " --channel-map=CHANNELMAP Карта каналов для использования " +#~ "вместо установленной по умолчанию\n" +#~ " --fix-format Взять образец формата из " +#~ "приёмника/источника, к которому\n" +#~ " подключен поток.\n" +#~ " --fix-rate Взять частоту дискретизации из " +#~ "приёмника/источника, к которому\n" +#~ " подключен поток.\n" +#~ " --fix-channels Взять количество каналов и карту " +#~ "каналов\n" +#~ " из приёмника/источника, к " +#~ "которому подключен поток.\n" +#~ " --no-remix Не менять число каналов.\n" +#~ " --no-remap Сопоставлять каналы по индексу, а " +#~ "не по имени.\n" +#~ " --latency=BYTES Запросить указанную задержку в " +#~ "байтах.\n" +#~ " --process-time=BYTES Запросить указанное время " +#~ "процесса на запрос в байтах.\n" +#~ " --latency-msec=MSEC Запросить указанную задержку в " +#~ "мсек.\n" +#~ " --process-time-msec=MSEC Запросить указанное время " +#~ "процесса на запрос в мсек.\n" +#~ " --property=PROPERTY=VALUE Установить для указанного " +#~ "свойства указанное значение.\n" +#~ " --raw Запись/воспроизведение " +#~ "необработанных данных PCM.\n" +#~ " --passthrough Пропускать данные.\n" +#~ " --file-format[=FFORMAT] Запись/воспроизведение " +#~ "форматированных данных PCM.\n" +#~ " --list-file-formats Список доступных форматов " +#~ "файлов.\n" +#~ " --monitor-stream=INDEX Запись с входа приёмника с " +#~ "индексом INDEX.\n" #~ msgid "Failed to initialize daemon." #~ msgstr "Не удалось инициализировать демон." diff --git a/po/si.po b/po/si.po index a1e5cd1ec..8d2cd1787 100644 --- a/po/si.po +++ b/po/si.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: pulseaudio\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2021-08-19 21:04+0000\n" "Last-Translator: Hela Basa \n" "Language-Team: Sinhala use_volume_sharing= " msgstr "" -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "" @@ -1038,14 +1038,14 @@ msgstr "" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "" @@ -1382,11 +1382,11 @@ msgstr "" msgid "Invalid log target." msgstr "" -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "" diff --git a/po/sk.po b/po/sk.po index 727dbd370..bb59a6dc2 100644 --- a/po/sk.po +++ b/po/sk.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: PulseAudio master\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2020-11-25 08:35+0000\n" "Last-Translator: Dusan Kazik \n" "Language-Team: Slovak use_volume_sharing= " msgstr "" -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "" @@ -1060,14 +1060,14 @@ msgstr "Zvuk na @HOSTNAME@" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "Tunel pre %s@%s" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "Tunel do %s/%s" @@ -1405,11 +1405,11 @@ msgstr "" msgid "Invalid log target." msgstr "Neplatný cieľ záznamu." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Vstavaný zvuk" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "Modem" diff --git a/po/sr.po b/po/sr.po index f0d76dfa9..246194fa9 100644 --- a/po/sr.po +++ b/po/sr.po @@ -9,7 +9,7 @@ msgstr "" "Project-Id-Version: pulseaudio\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2012-01-30 09:55+0000\n" "Last-Translator: Miloš Komarčević \n" "Language-Team: Serbian (sr) \n" @@ -1181,8 +1181,8 @@ msgstr "" "ladspa додатка> label=<ознака ladspa додатка> control=<списак улазних " "контролних вредности раздвојених зарезом>" -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "" @@ -1245,14 +1245,14 @@ msgstr "Аудио на @HOSTNAME@" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "" @@ -1603,11 +1603,11 @@ msgstr "" msgid "Invalid log target." msgstr "[%s:%u] Неисправан циљни дневник „%s“." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Унутрашњи звук" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "Модем" diff --git a/po/sr@latin.po b/po/sr@latin.po index 41814d1e6..414dac424 100644 --- a/po/sr@latin.po +++ b/po/sr@latin.po @@ -9,7 +9,7 @@ msgstr "" "Project-Id-Version: pulseaudio\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2012-01-30 09:55+0000\n" "Last-Translator: Miloš Komarčević \n" "Language-Team: Serbian (sr) \n" @@ -1182,8 +1182,8 @@ msgstr "" "ladspa dodatka> label= control=" -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "" @@ -1246,14 +1246,14 @@ msgstr "Audio na @HOSTNAME@" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "" @@ -1604,11 +1604,11 @@ msgstr "" msgid "Invalid log target." msgstr "[%s:%u] Neispravan ciljni dnevnik „%s“." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Unutrašnji zvuk" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "Modem" diff --git a/po/sv.po b/po/sv.po index 27c5241bb..fdb8e36bd 100644 --- a/po/sv.po +++ b/po/sv.po @@ -19,7 +19,7 @@ msgstr "" "Project-Id-Version: pulseaudio\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2022-05-18 22:27+0000\n" "Last-Translator: Anders Jonsson \n" "Language-Team: Swedish autoloaded= " "use_volume_sharing= " -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "FFT-baserad equalizer på %s" @@ -1208,14 +1208,14 @@ msgstr "Ljud på @HOSTNAME@" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "Tunnel för %s@%s" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "Tunnel till %s/%s" @@ -1563,11 +1563,11 @@ msgstr "" msgid "Invalid log target." msgstr "Ogiltigt mål för logg." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Inbyggt ljud" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "Modem" diff --git a/po/ta.po b/po/ta.po index 05b18e5f2..6025d3563 100644 --- a/po/ta.po +++ b/po/ta.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: pulseaudio.master-tx.ta\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2012-01-30 09:56+0000\n" "Last-Translator: I. Felix \n" "Language-Team: Tamil \n" @@ -1173,8 +1173,8 @@ msgstr "" "plugin name> label= control=" -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "" @@ -1237,14 +1237,14 @@ msgstr "@HOSTNAME@இல் ஆடியோ" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "" @@ -1595,11 +1595,11 @@ msgstr "" msgid "Invalid log target." msgstr "[%s:%u] தவறான பதிவு இலக்கு '%s'." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "உட்புற ஆடியோ" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "மாதிரி" diff --git a/po/te.po b/po/te.po index cebabc1ac..8bec442b0 100644 --- a/po/te.po +++ b/po/te.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: pulseaudio.master-tx.te\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2012-01-30 09:56+0000\n" "Last-Translator: Krishna Babu K \n" "Language-Team: Telugu \n" @@ -1143,8 +1143,8 @@ msgstr "" "channel_map=<చానల్ మాప్> plugin= label= " "control=<ఇన్పుట్ నియంత్రణ విలువలయొక్క జాబితా>" -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "" @@ -1206,14 +1206,14 @@ msgstr "@HOSTNAME@ పై ఆడియో" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "" @@ -1563,11 +1563,11 @@ msgstr "" msgid "Invalid log target." msgstr "[%s:%u] చెల్లని లాగ్ లక్ష్యము '%s'." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "అంతర్గత ఆడియో" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "మోడెమ్" diff --git a/po/tr.po b/po/tr.po index bc878a39d..979651b4e 100644 --- a/po/tr.po +++ b/po/tr.po @@ -10,7 +10,7 @@ msgstr "" "Project-Id-Version: PulseAudio master\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2022-05-18 22:27+0000\n" "Last-Translator: Oğuz Ersen \n" "Language-Team: Turkish " "ses_paylaşım_kullan= " -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "%s üzerinde FFT tabanlı dengeleyici" @@ -1199,14 +1199,14 @@ msgstr "@HOSTNAME@ üzerindeki SES" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "%s@%s için tünel" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "%s/%s tünel" @@ -1556,11 +1556,11 @@ msgstr "" msgid "Invalid log target." msgstr "Geçersiz günlük hedefi." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Dahili Ses" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "Modem" @@ -1967,8 +1967,8 @@ msgstr "" " --format=ÖRNEKLEMEBİÇİMİ Örnekleme biçimi, olası değerler için\n" " https://www.freedesktop.org/wiki/" "Software/PulseAudio/Documentation/User/SupportedAudioFormats/\n" -" adresine bakın (öntanımlı değer: s16ne)" -"\n" +" adresine bakın (öntanımlı değer: " +"s16ne)\n" " --channels=KANALLAR Kanal sayısı, mono için 1, stereo için " "2\n" " (öntanımlı değer: 2)\n" @@ -1981,8 +1981,8 @@ msgstr "" " --fix-channels Kanal eşlemesini ve kanal sayısını " "akışın bağlı olduğu\n" " alıcı/kaynaktan alır.\n" -" --no-remix Kanalları indirgemez ya da çoğaltamaz." -"\n" +" --no-remix Kanalları indirgemez ya da " +"çoğaltamaz.\n" " --no-remap Ad yerine dizin ile kanalları eşler.\n" " --latency=BAYT Bayt cinsinden belirtilen gecikmeyi " "ister.\n" diff --git a/po/uk.po b/po/uk.po index 80af5db2d..df0412545 100644 --- a/po/uk.po +++ b/po/uk.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: pulseaudio\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2022-05-18 22:27+0000\n" "Last-Translator: Yuri Chornoivan \n" "Language-Team: Ukrainian autoloaded=<визначити, чи слід завантажувати цей " "модуль у автоматичному режимі> use_volume_sharing= " -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "Еквалайзер на основі ШПФ на %s" @@ -1242,14 +1242,14 @@ msgstr "Звук на @НАЗВАВУЗЛА@" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "Тунель для %s@%s" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "Тунель до %s/%s" @@ -1601,11 +1601,11 @@ msgstr "" msgid "Invalid log target." msgstr "Некоректна адреса файла журналу." -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "Вбудоване аудіо" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "Модем" diff --git a/po/zh_CN.po b/po/zh_CN.po index 80735649e..cd3abf407 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -12,7 +12,7 @@ msgstr "" "Project-Id-Version: pulseaudio.master-tx\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2021-12-04 09:16+0000\n" "Last-Translator: Lv Genggeng \n" "Language-Team: Chinese (Simplified) rate=<采样率> channels=<声道数> channel_map=<声道映射> " "autoloaded=<若为自动加载则会设置> use_volume_sharing= " -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "基于快速傅里叶变换的均衡器%s" @@ -1147,14 +1147,14 @@ msgstr "@HOSTNAME@ 中的音频" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "%s@%s 的通道" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "到远程信宿 %s/%s 的通道" @@ -1498,11 +1498,11 @@ msgstr "尝试打开目标文件 '%s','%s.1','%s.2'…'%s.%d',但均失败 msgid "Invalid log target." msgstr "无效的日志目标。" -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "内置音频" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "调制解调器" diff --git a/po/zh_TW.po b/po/zh_TW.po index 023f1a5fe..3bcb6d677 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -9,7 +9,7 @@ msgstr "" "Project-Id-Version: PulseAudio Volume Control\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" -"POT-Creation-Date: 2022-05-16 23:56+0300\n" +"POT-Creation-Date: 2022-06-18 09:49+0300\n" "PO-Revision-Date: 2020-01-11 13:49+0800\n" "Last-Translator: pan93412 \n" "Language-Team: Chinese \n" @@ -1083,8 +1083,8 @@ msgstr "" "sink> format=<取樣格式> rate=<取樣率> channels=<聲道數> channel_map=<聲道對應" "表> autoloaded=<設定此模組是否正被自動載入> use_volume_sharing= " -#: src/modules/module-equalizer-sink.c:1094 -#: src/modules/module-equalizer-sink.c:1217 +#: src/modules/module-equalizer-sink.c:1097 +#: src/modules/module-equalizer-sink.c:1220 #, c-format msgid "FFT based equalizer on %s" msgstr "FFT 基礎等化器於 %s" @@ -1148,14 +1148,14 @@ msgstr "音效位於 @HOSTNAME@" #. TODO: old tunnel put here the remote sink_name into stream name e.g. 'Null Output for lynxis@lazus' #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' -#: src/modules/module-tunnel-sink-new.c:356 -#: src/modules/module-tunnel-source-new.c:342 +#: src/modules/module-tunnel-sink-new.c:370 +#: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" msgstr "%s@%s 的穿隧道" -#: src/modules/module-tunnel-sink-new.c:697 -#: src/modules/module-tunnel-source-new.c:668 +#: src/modules/module-tunnel-sink-new.c:715 +#: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" msgstr "前往 %s/%s 的穿隧道" @@ -1501,11 +1501,11 @@ msgstr "試圖開啟目標檔「%s」、「%s.1」、「%s.2」...「%s.%d」, msgid "Invalid log target." msgstr "無效的紀錄目標。" -#: src/pulsecore/sink.c:3600 +#: src/pulsecore/sink.c:3609 msgid "Built-in Audio" msgstr "內部音效" -#: src/pulsecore/sink.c:3605 +#: src/pulsecore/sink.c:3614 msgid "Modem" msgstr "數據機" From 2270081fcaf00f616247700ae0b6cba039f2e084 Mon Sep 17 00:00:00 2001 From: Tanu Kaskinen Date: Tue, 21 Jun 2022 13:37:19 +0300 Subject: [PATCH 011/260] Update NEWS for 16.1 Part-of: --- NEWS | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/NEWS b/NEWS index 847caf8be..1283eed24 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,22 @@ +PulseAudio 16.1 + +A bug fix release. + + * Fix parsing of percentage volumes with decimal points in pactl + * Fix crash with the "pacmd play-file" command when reads from the disk aren't frame-aligned + * Fix module-rtp-recv sometimes thinking it's receiving an Opus stream when it's not + * Fix frequent crashing in module-combine-sink, regression in 16.0 + * Fix crashing on 32-bit architectures when using the GStreamer codecs for LDAC and AptX + +Contributors + +Georg Chini +Igor V. Kovalenko +Jaechul Lee +Jan Palus +Sean Greenslade + + PulseAudio 16.0 Changes at a glance: From ffd7a60767b699c8e20e797328df5d8a857d0261 Mon Sep 17 00:00:00 2001 From: peijiankang Date: Tue, 21 Jun 2022 02:42:58 +0000 Subject: [PATCH 012/260] fix translation error of pulseaudio Part-of: --- src/modules/alsa/alsa-mixer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c index 7b755ce97..49c39687c 100644 --- a/src/modules/alsa/alsa-mixer.c +++ b/src/modules/alsa/alsa-mixer.c @@ -2838,7 +2838,7 @@ static int path_verify(pa_alsa_path *p) { if (p->device_port_type == PA_DEVICE_PORT_TYPE_UNKNOWN) p->device_port_type = map->type; if (!p->description) - p->description = pa_xstrdup(map->description); + p->description = pa_xstrdup(_(map->description)); } if (!p->description) { From 4bdf4c99662f3da0e58d6c04bafff95d84362922 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Mon, 27 Jun 2022 10:09:52 +0900 Subject: [PATCH 013/260] alsa-mixer: avoid assertion at alsa-lib mixer API when element removal PulseAudio v5.99 or later hits assertion at alsa-lib mixer API due to wrong handling of removal event for mixer element. pulseaudio: mixer.c:149: hctl_elem_event_handler: Assertion `bag_empty(bag)' failed. The removal event is defined as '~0U', thus it's not distinguished from the other type of event just by bitwise operator. At the removal event, class implementator for mixer API should detach mixer element from hcontrol element in callback handler since alsa-lib has assertion to check the list of mixer elements for a hcontrol element is empty or not after calling all of handlers. In detail, please refer to MR to alsa-lib: * https://github.com/alsa-project/alsa-lib/pull/244 This commit fixes the above two issues. The issue can be regenerated by `samples/ctl` Python 3 script of alsa-gobject. * https://github.com/alsa-project/alsa-gobject/ It adds some user-defined elements into sound card 0. When terminated by SIGINT signal, it removes the elements. Then PulseAudio dies due to the assertion. Fixes: 1fd8848e64cf ("alsa-util: Add functions for accessing mixer elements through mixer class") Part-of: --- src/modules/alsa/alsa-util.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c index 7dc373fa0..f4e838d37 100644 --- a/src/modules/alsa/alsa-util.c +++ b/src/modules/alsa/alsa-util.c @@ -1654,7 +1654,13 @@ static int mixer_class_event(snd_mixer_class_t *class, unsigned int mask, { int err; const char *name = snd_hctl_elem_get_name(helem); - if (mask & SND_CTL_EVENT_MASK_ADD) { + /* NOTE: The remove event is defined as '~0U`. */ + if (mask == SND_CTL_EVENT_MASK_REMOVE) { + /* NOTE: Unless we remove the pointer to melem from the linked-list at + * private_data of helem, an assertion will be hit in alsa-lib since + * the list is not empty. */ + snd_mixer_elem_detach(melem, helem); + } else if (mask & SND_CTL_EVENT_MASK_ADD) { snd_ctl_elem_iface_t iface = snd_hctl_elem_get_interface(helem); if (iface == SND_CTL_ELEM_IFACE_CARD || iface == SND_CTL_ELEM_IFACE_PCM) { snd_mixer_elem_t *new_melem; From def8eb074eb4a80836c39fa320c33fe89bce38d9 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 27 Jun 2022 10:32:07 +0200 Subject: [PATCH 014/260] alsa-mixer: allow to re-attach the mixer control element It may be possible that the ALSA control element appears again. Allow this combination by checking, if the pulseaudio mixer element already exists. Do not create the duplicate mixer element in this case. Signed-off-by: Jaroslav Kysela Part-of: --- src/modules/alsa/alsa-util.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c index f4e838d37..81dc77cc3 100644 --- a/src/modules/alsa/alsa-util.c +++ b/src/modules/alsa/alsa-util.c @@ -1663,12 +1663,20 @@ static int mixer_class_event(snd_mixer_class_t *class, unsigned int mask, } else if (mask & SND_CTL_EVENT_MASK_ADD) { snd_ctl_elem_iface_t iface = snd_hctl_elem_get_interface(helem); if (iface == SND_CTL_ELEM_IFACE_CARD || iface == SND_CTL_ELEM_IFACE_PCM) { + snd_mixer_t *mixer = snd_mixer_class_get_mixer(class); + snd_ctl_elem_iface_t iface = snd_hctl_elem_get_interface(helem); + const char *name = snd_hctl_elem_get_name(helem); + const int index = snd_hctl_elem_get_index(helem); + const int device = snd_hctl_elem_get_device(helem); snd_mixer_elem_t *new_melem; - - /* Put the hctl pointer as our private data - it will be useful for callbacks */ - if ((err = snd_mixer_elem_new(&new_melem, SND_MIXER_ELEM_PULSEAUDIO, 0, helem, NULL)) < 0) { - pa_log_warn("snd_mixer_elem_new failed: %s", pa_alsa_strerror(err)); - return 0; + + new_melem = pa_alsa_mixer_find(mixer, iface, name, index, device); + if (!new_melem) { + /* Put the hctl pointer as our private data - it will be useful for callbacks */ + if ((err = snd_mixer_elem_new(&new_melem, SND_MIXER_ELEM_PULSEAUDIO, 0, helem, NULL)) < 0) { + pa_log_warn("snd_mixer_elem_new failed: %s", pa_alsa_strerror(err)); + return 0; + } } if ((err = snd_mixer_elem_attach(new_melem, helem)) < 0) { From fb63e589310fab20e60c46bb40c7b7acab5eeac9 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Sat, 26 Jun 2021 12:05:17 +0300 Subject: [PATCH 015/260] idxset: Add set contains() function This is functionally equivalent to get_by_data(s, p, NULL) == p, but with a more obvious name and form because some existing code is instead manually iterating through idxsets to check for existence of an item. Signed-off-by: Alper Nebi Yasak Part-of: --- src/pulsecore/idxset.c | 14 ++++++++++++++ src/pulsecore/idxset.h | 3 +++ 2 files changed, 17 insertions(+) diff --git a/src/pulsecore/idxset.c b/src/pulsecore/idxset.c index 5175ca217..91ac6a015 100644 --- a/src/pulsecore/idxset.c +++ b/src/pulsecore/idxset.c @@ -258,6 +258,20 @@ void* pa_idxset_get_by_data(pa_idxset*s, const void *p, uint32_t *idx) { return e->data; } +bool pa_idxset_contains(pa_idxset *s, const void *p) { + unsigned hash; + struct idxset_entry *e; + + pa_assert(s); + + hash = s->hash_func(p) % NBUCKETS; + + if (!(e = data_scan(s, hash, p))) + return false; + + return e->data == p; +} + void* pa_idxset_remove_by_index(pa_idxset*s, uint32_t idx) { struct idxset_entry *e; unsigned hash; diff --git a/src/pulsecore/idxset.h b/src/pulsecore/idxset.h index 7acb202ff..6797852b7 100644 --- a/src/pulsecore/idxset.h +++ b/src/pulsecore/idxset.h @@ -66,6 +66,9 @@ void* pa_idxset_get_by_index(pa_idxset*s, uint32_t idx); /* Get the entry by its data. The index is returned in *idx */ void* pa_idxset_get_by_data(pa_idxset*s, const void *p, uint32_t *idx); +/* Return true if item is in idxset */ +bool pa_idxset_contains(pa_idxset *s, const void *p); + /* Similar to pa_idxset_get_by_index(), but removes the entry from the idxset. */ void* pa_idxset_remove_by_index(pa_idxset*s, uint32_t idx); From ec668ac44bc6e666123f22f2696745dcdce98fed Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 23 Jun 2021 17:50:50 +0300 Subject: [PATCH 016/260] idxset: Add set comparison operations Add isdisjoint(), issubset(), issuperset() and equals() functions that element-wise compare two idxsets. Signed-off-by: Alper Nebi Yasak Part-of: --- src/pulsecore/idxset.c | 34 ++++++++++++++++++++++++++++++++++ src/pulsecore/idxset.h | 12 ++++++++++++ 2 files changed, 46 insertions(+) diff --git a/src/pulsecore/idxset.c b/src/pulsecore/idxset.c index 91ac6a015..b5dd9b3e1 100644 --- a/src/pulsecore/idxset.c +++ b/src/pulsecore/idxset.c @@ -470,6 +470,40 @@ bool pa_idxset_isempty(pa_idxset *s) { return s->n_entries == 0; } +bool pa_idxset_isdisjoint(pa_idxset *s, pa_idxset *t) { + struct idxset_entry *i; + + pa_assert(s); + pa_assert(t); + + for (i = s->iterate_list_head; i; i = i->iterate_next) + if (pa_idxset_contains(t, i->data)) + return false; + + return true; +} + +bool pa_idxset_issubset(pa_idxset *s, pa_idxset *t) { + struct idxset_entry *i; + + pa_assert(s); + pa_assert(t); + + for (i = s->iterate_list_head; i; i = i->iterate_next) + if (!pa_idxset_contains(t, i->data)) + return false; + + return true; +} + +bool pa_idxset_issuperset(pa_idxset *s, pa_idxset *t) { + return pa_idxset_issubset(t, s); +} + +bool pa_idxset_equals(pa_idxset *s, pa_idxset *t) { + return pa_idxset_issubset(s, t) && pa_idxset_issuperset(s, t); +} + pa_idxset *pa_idxset_copy(pa_idxset *s, pa_copy_func_t copy_func) { pa_idxset *copy; struct idxset_entry *i; diff --git a/src/pulsecore/idxset.h b/src/pulsecore/idxset.h index 6797852b7..ee530bf2b 100644 --- a/src/pulsecore/idxset.h +++ b/src/pulsecore/idxset.h @@ -107,6 +107,18 @@ unsigned pa_idxset_size(pa_idxset*s); /* Return true of the idxset is empty */ bool pa_idxset_isempty(pa_idxset *s); +/* Return true if s and t have no entries in common */ +bool pa_idxset_isdisjoint(pa_idxset *s, pa_idxset *t); + +/* Return true if all entries in s are also in t */ +bool pa_idxset_issubset(pa_idxset *s, pa_idxset *t); + +/* Return true if all entries in t are also in s */ +bool pa_idxset_issuperset(pa_idxset *s, pa_idxset *t); + +/* Return true if s and t have all entries in common */ +bool pa_idxset_equals(pa_idxset *s, pa_idxset *t); + /* Duplicate the idxset. This will not copy the actual indexes. If copy_func is * set, each entry is copied using the provided function, otherwise a shallow * copy will be made. */ From 97d9c28579c7c7400969fd93f911e7745fb483ef Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 23 Jun 2021 17:58:37 +0300 Subject: [PATCH 017/260] idxset: Add reverse iteration functions Add complementary functions to the existing idxset iterate(), steal_first(), first(), next() functions that work in the reverse direction: reverse_iterate(), steal_last(), last() and previous(). Signed-off-by: Alper Nebi Yasak Part-of: --- src/pulsecore/idxset.c | 110 +++++++++++++++++++++++++++++++++++++++++ src/pulsecore/idxset.h | 19 ++++--- 2 files changed, 123 insertions(+), 6 deletions(-) diff --git a/src/pulsecore/idxset.c b/src/pulsecore/idxset.c index b5dd9b3e1..324894d01 100644 --- a/src/pulsecore/idxset.c +++ b/src/pulsecore/idxset.c @@ -381,6 +381,39 @@ at_end: return NULL; } +void *pa_idxset_reverse_iterate(pa_idxset *s, void **state, uint32_t *idx) { + struct idxset_entry *e; + + pa_assert(s); + pa_assert(state); + + if (*state == (void*) -1) + goto at_end; + + if ((!*state && !s->iterate_list_tail)) + goto at_end; + + e = *state ? *state : s->iterate_list_tail; + + if (e->iterate_previous) + *state = e->iterate_previous; + else + *state = (void*) -1; + + if (idx) + *idx = e->idx; + + return e->data; + +at_end: + *state = (void *) -1; + + if (idx) + *idx = PA_IDXSET_INVALID; + + return NULL; +} + void* pa_idxset_steal_first(pa_idxset *s, uint32_t *idx) { void *data; @@ -399,6 +432,24 @@ void* pa_idxset_steal_first(pa_idxset *s, uint32_t *idx) { return data; } +void* pa_idxset_steal_last(pa_idxset *s, uint32_t *idx) { + void *data; + + pa_assert(s); + + if (!s->iterate_list_tail) + return NULL; + + data = s->iterate_list_tail->data; + + if (idx) + *idx = s->iterate_list_tail->idx; + + remove_entry(s, s->iterate_list_tail); + + return data; +} + void* pa_idxset_first(pa_idxset *s, uint32_t *idx) { pa_assert(s); @@ -414,6 +465,21 @@ void* pa_idxset_first(pa_idxset *s, uint32_t *idx) { return s->iterate_list_head->data; } +void* pa_idxset_last(pa_idxset *s, uint32_t *idx) { + pa_assert(s); + + if (!s->iterate_list_tail) { + if (idx) + *idx = PA_IDXSET_INVALID; + return NULL; + } + + if (idx) + *idx = s->iterate_list_tail->idx; + + return s->iterate_list_tail->data; +} + void *pa_idxset_next(pa_idxset *s, uint32_t *idx) { struct idxset_entry *e; unsigned hash; @@ -458,6 +524,50 @@ void *pa_idxset_next(pa_idxset *s, uint32_t *idx) { } } +void *pa_idxset_previous(pa_idxset *s, uint32_t *idx) { + struct idxset_entry *e; + unsigned hash; + + pa_assert(s); + pa_assert(idx); + + if (*idx == PA_IDXSET_INVALID) + return NULL; + + hash = *idx % NBUCKETS; + + if ((e = index_scan(s, hash, *idx))) { + + e = e->iterate_previous; + + if (e) { + *idx = e->idx; + return e->data; + } else { + *idx = PA_IDXSET_INVALID; + return NULL; + } + + } else { + + /* If the entry passed doesn't exist anymore we try to find + * the preceding one. */ + + for ((*idx)--; *idx < s->current_index; (*idx)--) { + + hash = *idx % NBUCKETS; + + if ((e = index_scan(s, hash, *idx))) { + *idx = e->idx; + return e->data; + } + } + + *idx = PA_IDXSET_INVALID; + return NULL; + } +} + unsigned pa_idxset_size(pa_idxset*s) { pa_assert(s); diff --git a/src/pulsecore/idxset.h b/src/pulsecore/idxset.h index ee530bf2b..dbc4187d9 100644 --- a/src/pulsecore/idxset.h +++ b/src/pulsecore/idxset.h @@ -88,18 +88,25 @@ void* pa_idxset_rrobin(pa_idxset *s, uint32_t *idx); /* Iterate through the idxset. At first iteration state should be NULL */ void *pa_idxset_iterate(pa_idxset *s, void **state, uint32_t *idx); +void *pa_idxset_reverse_iterate(pa_idxset *s, void **state, uint32_t *idx); -/* Return the oldest entry in the idxset and remove it. If idx is not NULL fill in its index in *idx */ +/* Return the oldest or newest entry in the idxset and remove it. + * If idx is not NULL fill in its index in *idx */ void* pa_idxset_steal_first(pa_idxset *s, uint32_t *idx); +void* pa_idxset_steal_last(pa_idxset *s, uint32_t *idx); -/* Return the oldest entry in the idxset. Fill in its index in *idx. */ +/* Return the oldest or newest entry in the idxset. + * Fill in its index in *idx. */ void* pa_idxset_first(pa_idxset *s, uint32_t *idx); +void* pa_idxset_last(pa_idxset *s, uint32_t *idx); -/* Return the entry following the entry indexed by *idx. After the - * call *index contains the index of the returned - * object. pa_idxset_first() and pa_idxset_next() may be used to - * iterate through the set.*/ +/* Return the entry following or preceding the entry indexed by *idx. + * After the call *index contains the index of the returned object. + * pa_idxset_first() and pa_idxset_next() may be used to iterate through + * the set. pa_idxset_last() and pa_idxset_previous() may be used to + * iterate through the set in reverse. */ void *pa_idxset_next(pa_idxset *s, uint32_t *idx); +void *pa_idxset_previous(pa_idxset *s, uint32_t *idx); /* Return the current number of entries in the idxset */ unsigned pa_idxset_size(pa_idxset*s); From d8c89de24dbe261cadb76f9715e25215af3a6faa Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Thu, 24 Jun 2021 08:32:19 +0300 Subject: [PATCH 018/260] alsa-ucm: Always create device conflicting/supported device idxsets This is intended to make the current and upcoming code a bit clearer, as we won't need to constantly check for the existence of these idxsets before using or operating on them. Signed-off-by: Alper Nebi Yasak Part-of: --- src/modules/alsa/alsa-ucm.c | 64 ++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 37 deletions(-) diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c index 08e36b571..3e23bc416 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -523,10 +523,10 @@ static int ucm_get_device_property( n_confdev = snd_use_case_get_list(uc_mgr, id, &devices); pa_xfree(id); + device->conflicting_devices = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); if (n_confdev <= 0) pa_log_debug("No %s for device %s", "_conflictingdevs", device_name); else { - device->conflicting_devices = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); ucm_add_devices_to_idxset(device->conflicting_devices, device, verb->devices, devices, n_confdev); snd_use_case_free_list(devices, n_confdev); } @@ -535,10 +535,10 @@ static int ucm_get_device_property( n_suppdev = snd_use_case_get_list(uc_mgr, id, &devices); pa_xfree(id); + device->supported_devices = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); if (n_suppdev <= 0) pa_log_debug("No %s for device %s", "_supporteddevs", device_name); else { - device->supported_devices = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); ucm_add_devices_to_idxset(device->supported_devices, device, verb->devices, devices, n_suppdev); snd_use_case_free_list(devices, n_suppdev); } @@ -730,29 +730,17 @@ static void append_lost_relationship(pa_alsa_ucm_device *dev) { uint32_t idx; pa_alsa_ucm_device *d; - if (dev->conflicting_devices) { - PA_IDXSET_FOREACH(d, dev->conflicting_devices, idx) { - if (!d->conflicting_devices) - d->conflicting_devices = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); + PA_IDXSET_FOREACH(d, dev->conflicting_devices, idx) + if (pa_idxset_put(d->conflicting_devices, dev, NULL) == 0) + pa_log_warn("Add lost conflicting device %s to %s", + pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME), + pa_proplist_gets(d->proplist, PA_ALSA_PROP_UCM_NAME)); - if (pa_idxset_put(d->conflicting_devices, dev, NULL) == 0) - pa_log_warn("Add lost conflicting device %s to %s", - pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME), - pa_proplist_gets(d->proplist, PA_ALSA_PROP_UCM_NAME)); - } - } - - if (dev->supported_devices) { - PA_IDXSET_FOREACH(d, dev->supported_devices, idx) { - if (!d->supported_devices) - d->supported_devices = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); - - if (pa_idxset_put(d->supported_devices, dev, NULL) == 0) - pa_log_warn("Add lost supported device %s to %s", - pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME), - pa_proplist_gets(d->proplist, PA_ALSA_PROP_UCM_NAME)); - } - } + PA_IDXSET_FOREACH(d, dev->supported_devices, idx) + if (pa_idxset_put(d->supported_devices, dev, NULL) == 0) + pa_log_warn("Add lost supported device %s to %s", + pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME), + pa_proplist_gets(d->proplist, PA_ALSA_PROP_UCM_NAME)); } int pa_alsa_ucm_query_profiles(pa_alsa_ucm_config *ucm, int card_index) { @@ -1199,23 +1187,27 @@ static int ucm_check_conformance( return 1; } - if (dev->conflicting_devices) { /* the device defines conflicting devices */ - PA_IDXSET_FOREACH(d, dev->conflicting_devices, idx) { - for (i = 0; i < dev_num; i++) { - if (pdevices[i] == d) { - pa_log_debug("Conflicting device found"); - return 0; - } + PA_IDXSET_FOREACH(d, dev->conflicting_devices, idx) { + /* No conflicting device must already be selected */ + for (i = 0; i < dev_num; i++) { + if (pdevices[i] == d) { + pa_log_debug("Conflicting device found"); + return 0; } } - } else if (dev->supported_devices) { /* the device defines supported devices */ + } + + if (!pa_idxset_isempty(dev->supported_devices)) { + /* No already selected device must be unsupported */ for (i = 0; i < dev_num; i++) { if (!ucm_device_exists(dev->supported_devices, pdevices[i])) { pa_log_debug("Supported device not found"); return 0; } } - } else { /* not support any other devices */ + } + + if (pa_idxset_isempty(dev->conflicting_devices) && pa_idxset_isempty(dev->supported_devices)) { pa_log_debug("Not support any other devices"); return 0; } @@ -2113,10 +2105,8 @@ static void free_verb(pa_alsa_ucm_verb *verb) { pa_proplist_free(di->proplist); - if (di->conflicting_devices) - pa_idxset_free(di->conflicting_devices, NULL); - if (di->supported_devices) - pa_idxset_free(di->supported_devices, NULL); + pa_idxset_free(di->conflicting_devices, NULL); + pa_idxset_free(di->supported_devices, NULL); pa_xfree(di->eld_mixer_device_name); From 9b06e8fef43b161b85bf860e39a73492cd02bfb5 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Thu, 24 Jun 2021 08:40:03 +0300 Subject: [PATCH 019/260] alsa-ucm: Make modifiers track conflicting/supported devices as idxsets Modifiers currently keep their conflicting and supported devices's names, and these names are resolved to devices every time we need to use them. Instead, resolve these device names while creating the modifier struct and keep track of the resulting device structs in idxsets, same as how device structs keep track of their support relations. Signed-off-by: Alper Nebi Yasak Part-of: --- src/modules/alsa/alsa-ucm.c | 71 +++++++++++++++++++++---------------- src/modules/alsa/alsa-ucm.h | 7 ++-- 2 files changed, 42 insertions(+), 36 deletions(-) diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c index 3e23bc416..858aa011a 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -547,10 +547,16 @@ static int ucm_get_device_property( }; /* Create a property list for this ucm modifier */ -static int ucm_get_modifier_property(pa_alsa_ucm_modifier *modifier, snd_use_case_mgr_t *uc_mgr, const char *modifier_name) { +static int ucm_get_modifier_property( + pa_alsa_ucm_modifier *modifier, + snd_use_case_mgr_t *uc_mgr, + pa_alsa_ucm_verb *verb, + const char *modifier_name) { const char *value; char *id; int i; + const char **devices; + int n_confdev, n_suppdev; for (i = 0; item[i].id; i++) { int err; @@ -567,16 +573,28 @@ static int ucm_get_modifier_property(pa_alsa_ucm_modifier *modifier, snd_use_cas } id = pa_sprintf_malloc("%s/%s", "_conflictingdevs", modifier_name); - modifier->n_confdev = snd_use_case_get_list(uc_mgr, id, &modifier->conflicting_devices); + n_confdev = snd_use_case_get_list(uc_mgr, id, &devices); pa_xfree(id); - if (modifier->n_confdev < 0) + + modifier->conflicting_devices = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); + if (n_confdev <= 0) pa_log_debug("No %s for modifier %s", "_conflictingdevs", modifier_name); + else { + ucm_add_devices_to_idxset(modifier->conflicting_devices, NULL, verb->devices, devices, n_confdev); + snd_use_case_free_list(devices, n_confdev); + } id = pa_sprintf_malloc("%s/%s", "_supporteddevs", modifier_name); - modifier->n_suppdev = snd_use_case_get_list(uc_mgr, id, &modifier->supported_devices); + n_suppdev = snd_use_case_get_list(uc_mgr, id, &devices); pa_xfree(id); - if (modifier->n_suppdev < 0) + + modifier->supported_devices = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); + if (n_suppdev <= 0) pa_log_debug("No %s for modifier %s", "_supporteddevs", modifier_name); + else { + ucm_add_devices_to_idxset(modifier->supported_devices, NULL, verb->devices, devices, n_suppdev); + snd_use_case_free_list(devices, n_suppdev); + } return 0; }; @@ -659,23 +677,15 @@ static void add_role_to_device(pa_alsa_ucm_device *dev, const char *dev_name, co role_name)); } -static void add_media_role(const char *name, pa_alsa_ucm_device *list, const char *role_name, const char *role, bool is_sink) { - pa_alsa_ucm_device *d; +static void add_media_role(pa_alsa_ucm_device *dev, const char *role_name, const char *role, bool is_sink) { + const char *dev_name = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME); + const char *sink = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_SINK); + const char *source = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_SOURCE); - PA_LLIST_FOREACH(d, list) { - const char *dev_name = pa_proplist_gets(d->proplist, PA_ALSA_PROP_UCM_NAME); - - if (pa_streq(dev_name, name)) { - const char *sink = pa_proplist_gets(d->proplist, PA_ALSA_PROP_UCM_SINK); - const char *source = pa_proplist_gets(d->proplist, PA_ALSA_PROP_UCM_SOURCE); - - if (is_sink && sink) - add_role_to_device(d, dev_name, role_name, role); - else if (!is_sink && source) - add_role_to_device(d, dev_name, role_name, role); - break; - } - } + if (is_sink && sink) + add_role_to_device(dev, dev_name, role_name, role); + else if (!is_sink && source) + add_role_to_device(dev, dev_name, role_name, role); } static char *modifier_name_to_role(const char *mod_name, bool *is_sink) { @@ -704,11 +714,12 @@ static char *modifier_name_to_role(const char *mod_name, bool *is_sink) { return sub; } -static void ucm_set_media_roles(pa_alsa_ucm_modifier *modifier, pa_alsa_ucm_device *list, const char *mod_name) { - int i; +static void ucm_set_media_roles(pa_alsa_ucm_modifier *modifier, const char *mod_name) { + pa_alsa_ucm_device *dev; bool is_sink = false; char *sub = NULL; const char *role_name; + uint32_t idx; sub = modifier_name_to_role(mod_name, &is_sink); if (!sub) @@ -718,11 +729,11 @@ static void ucm_set_media_roles(pa_alsa_ucm_modifier *modifier, pa_alsa_ucm_devi modifier->media_role = sub; role_name = is_sink ? PA_ALSA_PROP_UCM_PLAYBACK_ROLES : PA_ALSA_PROP_UCM_CAPTURE_ROLES; - for (i = 0; i < modifier->n_suppdev; i++) { + PA_IDXSET_FOREACH(dev, modifier->supported_devices, idx) { /* if modifier has no specific pcm, we add role intent to its supported devices */ if (!pa_proplist_gets(modifier->proplist, PA_ALSA_PROP_UCM_SINK) && !pa_proplist_gets(modifier->proplist, PA_ALSA_PROP_UCM_SOURCE)) - add_media_role(modifier->supported_devices[i], list, role_name, sub, is_sink); + add_media_role(dev, role_name, sub, is_sink); } } @@ -879,11 +890,11 @@ int pa_alsa_ucm_get_verb(snd_use_case_mgr_t *uc_mgr, const char *verb_name, cons const char *mod_name = pa_proplist_gets(mod->proplist, PA_ALSA_PROP_UCM_NAME); /* Modifier properties */ - ucm_get_modifier_property(mod, uc_mgr, mod_name); + ucm_get_modifier_property(mod, uc_mgr, verb, mod_name); /* Set PA_PROP_DEVICE_INTENDED_ROLES property to devices */ pa_log_debug("Set media roles for verb %s, modifier %s", verb_name, mod_name); - ucm_set_media_roles(mod, verb->devices, mod_name); + ucm_set_media_roles(mod, mod_name); } *p_verb = verb; @@ -2116,10 +2127,8 @@ static void free_verb(pa_alsa_ucm_verb *verb) { PA_LLIST_FOREACH_SAFE(mi, mn, verb->modifiers) { PA_LLIST_REMOVE(pa_alsa_ucm_modifier, verb->modifiers, mi); pa_proplist_free(mi->proplist); - if (mi->n_suppdev > 0) - snd_use_case_free_list(mi->supported_devices, mi->n_suppdev); - if (mi->n_confdev > 0) - snd_use_case_free_list(mi->conflicting_devices, mi->n_confdev); + pa_idxset_free(mi->conflicting_devices, NULL); + pa_idxset_free(mi->supported_devices, NULL); pa_xfree(mi->media_role); pa_xfree(mi); } diff --git a/src/modules/alsa/alsa-ucm.h b/src/modules/alsa/alsa-ucm.h index 255bc0d5a..cb72837de 100644 --- a/src/modules/alsa/alsa-ucm.h +++ b/src/modules/alsa/alsa-ucm.h @@ -221,11 +221,8 @@ struct pa_alsa_ucm_modifier { pa_proplist *proplist; - int n_confdev; - int n_suppdev; - - const char **conflicting_devices; - const char **supported_devices; + pa_idxset *conflicting_devices; + pa_idxset *supported_devices; pa_direction_t action_direction; From c83b34516929214876bd2c46b5f346e53a3adcf7 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Thu, 24 Jun 2021 09:11:59 +0300 Subject: [PATCH 020/260] alsa-ucm: Add enable, disable, status helpers for devices Right now manipulating device status is done inline once while setting a port. However, we will need to reuse this code to disable conflicting devices of a device we want to enable. Split it into enable and disable helper functions. There is another issue with the device enable logic, where trying to disabling an already disabled device sometimes fails. To avoid that, implement a status helper and check if the device we want to enable is already enabled/disabled before trying to do so. Signed-off-by: Alper Nebi Yasak Part-of: --- src/modules/alsa/alsa-ucm.c | 81 ++++++++++++++++++++++++++++--------- 1 file changed, 63 insertions(+), 18 deletions(-) diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c index 858aa011a..7b857785d 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -631,6 +631,59 @@ static int ucm_get_devices(pa_alsa_ucm_verb *verb, snd_use_case_mgr_t *uc_mgr) { return 0; }; +static long ucm_device_status(pa_alsa_ucm_config *ucm, pa_alsa_ucm_device *dev) { + const char *dev_name = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME); + char *devstatus; + long status = 0; + + devstatus = pa_sprintf_malloc("_devstatus/%s", dev_name); + if (snd_use_case_geti(ucm->ucm_mgr, devstatus, &status) < 0) { + pa_log_debug("Failed to get status for UCM device %s", dev_name); + status = -1; + } + pa_xfree(devstatus); + + return status; +} + +static int ucm_device_disable(pa_alsa_ucm_config *ucm, pa_alsa_ucm_device *dev) { + const char *dev_name = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME); + + /* If any of dev's conflicting devices is enabled, trying to disable + * dev gives an error despite the fact that it's already disabled. + * Check that dev is enabled to avoid this error. */ + if (ucm_device_status(ucm, dev) == 0) { + pa_log_debug("UCM device %s is already disabled", dev_name); + return 0; + } + + pa_log_debug("Disabling UCM device %s", dev_name); + if (snd_use_case_set(ucm->ucm_mgr, "_disdev", dev_name) < 0) { + pa_log("Failed to disable UCM device %s", dev_name); + return -1; + } + + return 0; +} + +static int ucm_device_enable(pa_alsa_ucm_config *ucm, pa_alsa_ucm_device *dev) { + const char *dev_name = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME); + + /* We don't need to enable devices that are already enabled */ + if (ucm_device_status(ucm, dev) > 0) { + pa_log_debug("UCM device %s is already enabled", dev_name); + return 0; + } + + pa_log_debug("Enabling UCM device %s", dev_name); + if (snd_use_case_set(ucm->ucm_mgr, "_enadev", dev_name) < 0) { + pa_log("Failed to enable UCM device %s", dev_name); + return -1; + } + + return 0; +} + static int ucm_get_modifiers(pa_alsa_ucm_verb *verb, snd_use_case_mgr_t *uc_mgr) { const char **mod_list; int num_mod, i; @@ -1417,7 +1470,7 @@ int pa_alsa_ucm_set_port(pa_alsa_ucm_mapping_context *context, pa_device_port *p int i; int ret = 0; pa_alsa_ucm_config *ucm; - const char **enable_devs; + pa_alsa_ucm_device **enable_devs; int enable_num = 0; uint32_t idx; pa_alsa_ucm_device *dev; @@ -1427,31 +1480,23 @@ int pa_alsa_ucm_set_port(pa_alsa_ucm_mapping_context *context, pa_device_port *p ucm = context->ucm; pa_assert(ucm->ucm_mgr); - enable_devs = pa_xnew(const char *, pa_idxset_size(context->ucm_devices)); + enable_devs = pa_xnew(pa_alsa_ucm_device *, pa_idxset_size(context->ucm_devices)); /* first disable then enable */ PA_IDXSET_FOREACH(dev, context->ucm_devices, idx) { const char *dev_name = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME); if (ucm_port_contains(port->name, dev_name, is_sink)) - enable_devs[enable_num++] = dev_name; - else { - pa_log_debug("Disable ucm device %s", dev_name); - if (snd_use_case_set(ucm->ucm_mgr, "_disdev", dev_name) > 0) { - pa_log("Failed to disable ucm device %s", dev_name); - ret = -1; - break; - } - } + enable_devs[enable_num++] = dev; + else + ret = ucm_device_disable(ucm, dev); + + if (ret < 0) + break; } - for (i = 0; i < enable_num; i++) { - pa_log_debug("Enable ucm device %s", enable_devs[i]); - if (snd_use_case_set(ucm->ucm_mgr, "_enadev", enable_devs[i]) < 0) { - pa_log("Failed to enable ucm device %s", enable_devs[i]); - ret = -1; - break; - } + for (i = 0; i < enable_num && ret == 0; i++) { + ret = ucm_device_enable(ucm, enable_devs[i]); } pa_xfree(enable_devs); From 880ff393f13ddc497dc9f9edff16050a02656fbd Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Sun, 6 Jun 2021 22:06:46 +0300 Subject: [PATCH 021/260] alsa-ucm: Set profiles by their struct instance, not their name While switching profiles, it's possible that we will want to do more work besides switching UCM verbs. The alsa-card module already has our profiles as structs, but passes in only the names instead of the entire struct. Make things work with the struct instead, so we can add other things (like a UCM context) to it and use those here. Co-authored-by: Tanu Kaskinen [Alper: Split into its own commit and integrated Tanu's snippet.] Signed-off-by: Alper Nebi Yasak Part-of: --- src/modules/alsa/alsa-ucm.c | 15 +++++++-------- src/modules/alsa/alsa-ucm.h | 2 +- src/modules/alsa/module-alsa-card.c | 5 ++--- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c index 7b857785d..a40c3d764 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -1430,19 +1430,18 @@ void pa_alsa_ucm_add_ports( } /* Change UCM verb and device to match selected card profile */ -int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, pa_card *card, const char *new_profile, const char *old_profile) { +int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, pa_card *card, pa_alsa_profile *new_profile, pa_alsa_profile *old_profile) { int ret = 0; const char *profile; pa_alsa_ucm_verb *verb; if (new_profile == old_profile) - return ret; - else if (new_profile == NULL || old_profile == NULL) - profile = new_profile ? new_profile : SND_USE_CASE_VERB_INACTIVE; - else if (!pa_streq(new_profile, old_profile)) - profile = new_profile; + return 0; + + if (new_profile == NULL) + profile = SND_USE_CASE_VERB_INACTIVE; else - return ret; + profile = new_profile->name; /* change verb */ pa_log_info("Set UCM verb to %s", profile); @@ -2430,7 +2429,7 @@ pa_alsa_profile_set* pa_alsa_ucm_add_profile_set(pa_alsa_ucm_config *ucm, pa_cha return NULL; } -int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, pa_card *card, const char *new_profile, const char *old_profile) { +int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, pa_card *card, pa_alsa_profile *new_profile, pa_alsa_profile *old_profile) { return -1; } diff --git a/src/modules/alsa/alsa-ucm.h b/src/modules/alsa/alsa-ucm.h index cb72837de..e411a9262 100644 --- a/src/modules/alsa/alsa-ucm.h +++ b/src/modules/alsa/alsa-ucm.h @@ -145,7 +145,7 @@ typedef struct pa_alsa_ucm_volume pa_alsa_ucm_volume; int pa_alsa_ucm_query_profiles(pa_alsa_ucm_config *ucm, int card_index); pa_alsa_profile_set* pa_alsa_ucm_add_profile_set(pa_alsa_ucm_config *ucm, pa_channel_map *default_channel_map); -int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, pa_card *card, const char *new_profile, const char *old_profile); +int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, pa_card *card, pa_alsa_profile *new_profile, pa_alsa_profile *old_profile); int pa_alsa_ucm_get_verb(snd_use_case_mgr_t *uc_mgr, const char *verb_name, const char *verb_desc, pa_alsa_ucm_verb **p_verb); diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c index 0fe8893f4..2efa96a0f 100644 --- a/src/modules/alsa/module-alsa-card.c +++ b/src/modules/alsa/module-alsa-card.c @@ -249,8 +249,7 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) { /* if UCM is available for this card then update the verb */ if (u->use_ucm) { - if (pa_alsa_ucm_set_profile(&u->ucm, c, nd->profile ? nd->profile->name : NULL, - od->profile ? od->profile->name : NULL) < 0) { + if (pa_alsa_ucm_set_profile(&u->ucm, c, nd->profile, od->profile) < 0) { ret = -1; goto finish; } @@ -302,7 +301,7 @@ static void init_profile(struct userdata *u) { if (d->profile && u->use_ucm) { /* Set initial verb */ - if (pa_alsa_ucm_set_profile(ucm, u->card, d->profile->name, NULL) < 0) { + if (pa_alsa_ucm_set_profile(ucm, u->card, d->profile, NULL) < 0) { pa_log("Failed to set ucm profile %s", d->profile->name); return; } From 9fc7064b9a447abd308a8cc260f7f021f5637cd4 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Sun, 6 Jun 2021 23:00:40 +0300 Subject: [PATCH 022/260] alsa-ucm: Let profiles know their associated UCM verb Currently each UCM verb generates one profile named the same as the verb, meaning it's trivial to know which verb the profile belongs to. This will be slightly harder to do when we generate multiple profiles per UCM verb (e.g. to make use of conflicting devices). It would still be possible to parse the profile name to get the UCM verb, but instead let's keep track of the struct instance representing the profile's associated verb. This also lets us remove a block of code searching for the verb by its name. Co-authored-by: Jaroslav Kysela [Alper: Reused Jaroslav's UCM profile context changes for UCM verb instead of combined devices.] Signed-off-by: Alper Nebi Yasak Part-of: --- src/modules/alsa/alsa-mixer.h | 5 ++++- src/modules/alsa/alsa-ucm.c | 20 +++++++------------- src/modules/alsa/alsa-ucm.h | 5 +++++ 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/modules/alsa/alsa-mixer.h b/src/modules/alsa/alsa-mixer.h index 91b0ca017..b56d88113 100644 --- a/src/modules/alsa/alsa-mixer.h +++ b/src/modules/alsa/alsa-mixer.h @@ -318,7 +318,7 @@ struct pa_alsa_mapping { pa_sink *sink; pa_source *source; - /* ucm device context*/ + /* ucm device context */ pa_alsa_ucm_mapping_context ucm_context; }; @@ -342,6 +342,9 @@ struct pa_alsa_profile { pa_idxset *input_mappings; pa_idxset *output_mappings; + + /* ucm device context */ + pa_alsa_ucm_profile_context ucm_context; }; struct pa_alsa_decibel_fix { diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c index a40c3d764..20ddd9f7a 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -1438,10 +1438,13 @@ int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, pa_card *card, pa_alsa_prof if (new_profile == old_profile) return 0; - if (new_profile == NULL) + if (new_profile == NULL) { profile = SND_USE_CASE_VERB_INACTIVE; - else + verb = NULL; + } else { profile = new_profile->name; + verb = new_profile->ucm_context.verb; + } /* change verb */ pa_log_info("Set UCM verb to %s", profile); @@ -1449,17 +1452,7 @@ int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, pa_card *card, pa_alsa_prof pa_log("Failed to set verb %s", profile); ret = -1; } - - /* find active verb */ - ucm->active_verb = NULL; - PA_LLIST_FOREACH(verb, ucm->verbs) { - const char *verb_name; - verb_name = pa_proplist_gets(verb->proplist, PA_ALSA_PROP_UCM_NAME); - if (pa_streq(verb_name, profile)) { - ucm->active_verb = verb; - break; - } - } + ucm->active_verb = verb; update_mixer_paths(card->ports, profile); return ret; @@ -1832,6 +1825,7 @@ static int ucm_create_profile( p->profile_set = ps; p->name = pa_xstrdup(verb_name); p->description = pa_xstrdup(verb_desc); + p->ucm_context.verb = verb; p->output_mappings = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); p->input_mappings = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); diff --git a/src/modules/alsa/alsa-ucm.h b/src/modules/alsa/alsa-ucm.h index e411a9262..1652aff8f 100644 --- a/src/modules/alsa/alsa-ucm.h +++ b/src/modules/alsa/alsa-ucm.h @@ -140,6 +140,7 @@ typedef struct pa_alsa_ucm_modifier pa_alsa_ucm_modifier; typedef struct pa_alsa_ucm_device pa_alsa_ucm_device; typedef struct pa_alsa_ucm_config pa_alsa_ucm_config; typedef struct pa_alsa_ucm_mapping_context pa_alsa_ucm_mapping_context; +typedef struct pa_alsa_ucm_profile_context pa_alsa_ucm_profile_context; typedef struct pa_alsa_ucm_port_data pa_alsa_ucm_port_data; typedef struct pa_alsa_ucm_volume pa_alsa_ucm_volume; @@ -265,6 +266,10 @@ struct pa_alsa_ucm_mapping_context { pa_idxset *ucm_modifiers; }; +struct pa_alsa_ucm_profile_context { + pa_alsa_ucm_verb *verb; +}; + struct pa_alsa_ucm_port_data { pa_alsa_ucm_config *ucm; pa_device_port *core_port; From 45278904167f59a8cec5630cc9f09a9f605e11b7 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 23 Jun 2021 22:10:10 +0300 Subject: [PATCH 023/260] alsa-ucm: Stop conflating profile name with UCM verb name So far each profile had the exact name as their associated UCM verb, which caused the one to be used where the other should have been. Explicitly get and use the verb name where that was intended, and make sure things about profiles aren't named after verbs. Signed-off-by: Alper Nebi Yasak Part-of: --- src/modules/alsa/alsa-ucm.c | 49 ++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c index 20ddd9f7a..dab842a7d 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -991,16 +991,16 @@ static void set_eld_devices(pa_hashmap *hash) } } -static void update_mixer_paths(pa_hashmap *ports, const char *profile) { +static void update_mixer_paths(pa_hashmap *ports, const char *profile_name) { pa_device_port *port; pa_alsa_ucm_port_data *data; void *state; /* select volume controls on ports */ PA_HASHMAP_FOREACH(port, ports, state) { - pa_log_info("Updating mixer path for %s: %s", profile, port->name); + pa_log_info("Updating mixer path for %s: %s", profile_name, port->name); data = PA_DEVICE_PORT_DATA(port); - data->path = pa_hashmap_get(data->paths, profile); + data->path = pa_hashmap_get(data->paths, profile_name); } } @@ -1432,29 +1432,33 @@ void pa_alsa_ucm_add_ports( /* Change UCM verb and device to match selected card profile */ int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, pa_card *card, pa_alsa_profile *new_profile, pa_alsa_profile *old_profile) { int ret = 0; - const char *profile; + const char *verb_name, *profile_name; pa_alsa_ucm_verb *verb; if (new_profile == old_profile) return 0; if (new_profile == NULL) { - profile = SND_USE_CASE_VERB_INACTIVE; verb = NULL; + profile_name = SND_USE_CASE_VERB_INACTIVE; + verb_name = SND_USE_CASE_VERB_INACTIVE; } else { - profile = new_profile->name; verb = new_profile->ucm_context.verb; + profile_name = new_profile->name; + verb_name = pa_proplist_gets(verb->proplist, PA_ALSA_PROP_UCM_NAME); } /* change verb */ - pa_log_info("Set UCM verb to %s", profile); - if ((snd_use_case_set(ucm->ucm_mgr, "_verb", profile)) < 0) { - pa_log("Failed to set verb %s", profile); + pa_log_info("Set profile to %s", profile_name); + pa_log_info("Set UCM verb to %s", verb_name); + if ((snd_use_case_set(ucm->ucm_mgr, "_verb", verb_name)) < 0) { + pa_log("Failed to set verb %s", verb_name); ret = -1; } ucm->active_verb = verb; - update_mixer_paths(card->ports, profile); + update_mixer_paths(card->ports, profile_name); + return ret; } @@ -1804,8 +1808,8 @@ static int ucm_create_profile( pa_alsa_ucm_config *ucm, pa_alsa_profile_set *ps, pa_alsa_ucm_verb *verb, - const char *verb_name, - const char *verb_desc) { + const char *profile_name, + const char *profile_desc) { pa_alsa_profile *p; pa_alsa_ucm_device *dev; @@ -1813,18 +1817,19 @@ static int ucm_create_profile( int i = 0; const char *name, *sink, *source; unsigned int priority; + const char *verb_name = pa_proplist_gets(verb->proplist, PA_ALSA_PROP_UCM_NAME); pa_assert(ps); - if (pa_hashmap_get(ps->profiles, verb_name)) { - pa_log("Verb %s already exists", verb_name); + if (pa_hashmap_get(ps->profiles, profile_name)) { + pa_log("Profile %s already exists", profile_name); return -1; } p = pa_xnew0(pa_alsa_profile, 1); p->profile_set = ps; - p->name = pa_xstrdup(verb_name); - p->description = pa_xstrdup(verb_desc); + p->name = pa_xstrdup(profile_name); + p->description = pa_xstrdup(profile_desc); p->ucm_context.verb = verb; p->output_mappings = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); @@ -2038,14 +2043,18 @@ static void ucm_probe_profile_set(pa_alsa_ucm_config *ucm, pa_alsa_profile_set * void *state; pa_alsa_profile *p; pa_alsa_mapping *m; + const char *verb_name; uint32_t idx; PA_HASHMAP_FOREACH(p, ps->profiles, state) { - /* change verb */ - pa_log_info("Set ucm verb to %s", p->name); + pa_log_info("Probing profile %s", p->name); - if ((snd_use_case_set(ucm->ucm_mgr, "_verb", p->name)) < 0) { - pa_log("Failed to set verb %s", p->name); + /* change verb */ + verb_name = pa_proplist_gets(p->ucm_context.verb->proplist, PA_ALSA_PROP_UCM_NAME); + pa_log_info("Set ucm verb to %s", verb_name); + + if ((snd_use_case_set(ucm->ucm_mgr, "_verb", verb_name)) < 0) { + pa_log("Failed to set verb %s", verb_name); p->supported = false; continue; } From aa5ced3887e2190ebd0fa459ab652fff4be46252 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 9 Jun 2021 15:33:12 +0300 Subject: [PATCH 024/260] alsa-ucm: Make mapping creation independent from indvidual profiles The ucm_create_mapping() function is not idempotent. It looks like it was meant to be called once per device for the devices of a UCM verb and takes a profile argument simply because a verb has generated a single profile so far. Make sure creating mappings per device and adding those mappings to the profiles happens as separate steps to make it easier to split UCM verbs and profiles as concepts. Signed-off-by: Alper Nebi Yasak Part-of: --- src/modules/alsa/alsa-ucm.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c index dab842a7d..16659e6aa 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -1627,7 +1627,6 @@ static pa_alsa_mapping* ucm_alsa_mapping_get(pa_alsa_ucm_config *ucm, pa_alsa_pr static int ucm_create_mapping_direction( pa_alsa_ucm_config *ucm, pa_alsa_profile_set *ps, - pa_alsa_profile *p, pa_alsa_ucm_device *device, const char *verb_name, const char *device_name, @@ -1657,7 +1656,6 @@ static int ucm_create_mapping_direction( m->device_strings[0] = pa_xstrdup(device_str); m->direction = is_sink ? PA_ALSA_DIRECTION_OUTPUT : PA_ALSA_DIRECTION_INPUT; - ucm_add_mapping(p, m); if (rate) m->sample_spec.rate = rate; pa_channel_map_init_extend(&m->channel_map, channels, PA_CHANNEL_MAP_ALSA); @@ -1679,7 +1677,6 @@ static int ucm_create_mapping_direction( static int ucm_create_mapping_for_modifier( pa_alsa_ucm_config *ucm, pa_alsa_profile_set *ps, - pa_alsa_profile *p, pa_alsa_ucm_modifier *modifier, const char *verb_name, const char *mod_name, @@ -1706,8 +1703,6 @@ static int ucm_create_mapping_for_modifier( m->direction = is_sink ? PA_ALSA_DIRECTION_OUTPUT : PA_ALSA_DIRECTION_INPUT; /* Modifier sinks should not be routed to by default */ m->priority = 0; - - ucm_add_mapping(p, m); } else if (!m->ucm_context.ucm_modifiers) /* share pcm with device */ m->ucm_context.ucm_modifiers = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); @@ -1719,7 +1714,6 @@ static int ucm_create_mapping_for_modifier( static int ucm_create_mapping( pa_alsa_ucm_config *ucm, pa_alsa_profile_set *ps, - pa_alsa_profile *p, pa_alsa_ucm_device *device, const char *verb_name, const char *device_name, @@ -1734,9 +1728,9 @@ static int ucm_create_mapping( } if (sink) - ret = ucm_create_mapping_direction(ucm, ps, p, device, verb_name, device_name, sink, true); + ret = ucm_create_mapping_direction(ucm, ps, device, verb_name, device_name, sink, true); if (ret == 0 && source) - ret = ucm_create_mapping_direction(ucm, ps, p, device, verb_name, device_name, source, false); + ret = ucm_create_mapping_direction(ucm, ps, device, verb_name, device_name, source, false); return ret; } @@ -1868,7 +1862,12 @@ static int ucm_create_profile( sink = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_SINK); source = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_SOURCE); - ucm_create_mapping(ucm, ps, p, dev, verb_name, name, sink, source); + ucm_create_mapping(ucm, ps, dev, verb_name, name, sink, source); + + if (dev->playback_mapping) + ucm_add_mapping(p, dev->playback_mapping); + if (dev->capture_mapping) + ucm_add_mapping(p, dev->capture_mapping); jack = ucm_get_jack(ucm, dev); if (jack) @@ -1919,9 +1918,14 @@ static int ucm_create_profile( source = pa_proplist_gets(mod->proplist, PA_ALSA_PROP_UCM_SOURCE); if (sink) - ucm_create_mapping_for_modifier(ucm, ps, p, mod, verb_name, name, sink, true); + ucm_create_mapping_for_modifier(ucm, ps, mod, verb_name, name, sink, true); else if (source) - ucm_create_mapping_for_modifier(ucm, ps, p, mod, verb_name, name, source, false); + ucm_create_mapping_for_modifier(ucm, ps, mod, verb_name, name, source, false); + + if (mod->playback_mapping) + ucm_add_mapping(p, mod->playback_mapping); + if (mod->capture_mapping) + ucm_add_mapping(p, mod->capture_mapping); } pa_alsa_profile_dump(p); From 638574c0b7cafe43149a017cf2090b8eda531826 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 23 Jun 2021 22:43:05 +0300 Subject: [PATCH 025/260] alsa-ucm: Split profile creation into verb and profile parts To support having multiple profiles per UCM verb, split the profile creation into two parts based on whether they should run once for each verb or for each profile (maybe multiple times per verb). Signed-off-by: Alper Nebi Yasak Part-of: --- src/modules/alsa/alsa-ucm.c | 62 +++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c index 16659e6aa..b174ac807 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -1802,16 +1802,14 @@ static int ucm_create_profile( pa_alsa_ucm_config *ucm, pa_alsa_profile_set *ps, pa_alsa_ucm_verb *verb, + pa_idxset *mappings, const char *profile_name, - const char *profile_desc) { + const char *profile_desc, + unsigned int profile_priority) { pa_alsa_profile *p; - pa_alsa_ucm_device *dev; - pa_alsa_ucm_modifier *mod; - int i = 0; - const char *name, *sink, *source; - unsigned int priority; - const char *verb_name = pa_proplist_gets(verb->proplist, PA_ALSA_PROP_UCM_NAME); + pa_alsa_mapping *map; + uint32_t idx; pa_assert(ps); @@ -1824,6 +1822,7 @@ static int ucm_create_profile( p->profile_set = ps; p->name = pa_xstrdup(profile_name); p->description = pa_xstrdup(profile_desc); + p->priority = profile_priority; p->ucm_context.verb = verb; p->output_mappings = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); @@ -1832,10 +1831,33 @@ static int ucm_create_profile( p->supported = true; pa_hashmap_put(ps->profiles, p->name, p); - /* TODO: get profile priority from policy management */ - priority = verb->priority; + PA_IDXSET_FOREACH(map, mappings, idx) + ucm_add_mapping(p, map); - if (priority == 0) { + pa_alsa_profile_dump(p); + + return 0; +} + +static int ucm_create_verb_profiles( + pa_alsa_ucm_config *ucm, + pa_alsa_profile_set *ps, + pa_alsa_ucm_verb *verb, + const char *verb_name, + const char *verb_desc) { + + pa_idxset *mappings; + pa_alsa_ucm_device *dev; + pa_alsa_ucm_modifier *mod; + int i = 0; + int ret = 0; + const char *name, *sink, *source; + unsigned int verb_priority; + + /* TODO: get profile priority from policy management */ + verb_priority = verb->priority; + + if (verb_priority == 0) { char *verb_cmp, *c; c = verb_cmp = pa_xstrdup(verb_name); while (*c) { @@ -1844,14 +1866,14 @@ static int ucm_create_profile( } for (i = 0; verb_info[i].id; i++) { if (strcasecmp(verb_info[i].id, verb_cmp) == 0) { - priority = verb_info[i].priority; + verb_priority = verb_info[i].priority; break; } } pa_xfree(verb_cmp); } - p->priority = priority; + mappings = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); PA_LLIST_FOREACH(dev, verb->devices) { pa_alsa_jack *jack; @@ -1865,9 +1887,9 @@ static int ucm_create_profile( ucm_create_mapping(ucm, ps, dev, verb_name, name, sink, source); if (dev->playback_mapping) - ucm_add_mapping(p, dev->playback_mapping); + pa_idxset_put(mappings, dev->playback_mapping, NULL); if (dev->capture_mapping) - ucm_add_mapping(p, dev->capture_mapping); + pa_idxset_put(mappings, dev->capture_mapping, NULL); jack = ucm_get_jack(ucm, dev); if (jack) @@ -1923,14 +1945,16 @@ static int ucm_create_profile( ucm_create_mapping_for_modifier(ucm, ps, mod, verb_name, name, source, false); if (mod->playback_mapping) - ucm_add_mapping(p, mod->playback_mapping); + pa_idxset_put(mappings, mod->playback_mapping, NULL); if (mod->capture_mapping) - ucm_add_mapping(p, mod->capture_mapping); + pa_idxset_put(mappings, mod->capture_mapping, NULL); } - pa_alsa_profile_dump(p); + ret = ucm_create_profile(ucm, ps, verb, mappings, verb_name, verb_desc, verb_priority); - return 0; + pa_idxset_free(mappings, NULL); + + return ret; } static void mapping_init_eld(pa_alsa_mapping *m, snd_pcm_t *pcm) @@ -2138,7 +2162,7 @@ pa_alsa_profile_set* pa_alsa_ucm_add_profile_set(pa_alsa_ucm_config *ucm, pa_cha continue; } - ucm_create_profile(ucm, ps, verb, verb_name, verb_desc); + ucm_create_verb_profiles(ucm, ps, verb, verb_name, verb_desc); } ucm_probe_profile_set(ucm, ps); From 0f26022843c7d5ba2fde16e2dca4b2ce16d4631d Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Mon, 28 Jun 2021 15:31:38 +0300 Subject: [PATCH 026/260] alsa-ucm: Rewrite conformant device group generation with idxsets The existing code meant to generate device groups for combination ports is tightly coupled to port creation. Similar functionality would be useful to generate nonconflicting device groups for multiple profiles as well, so this tries to rewrite it into a more reusable state. Several things (e.g devices, mapping contexts) use idxsets to store a device selection. This also switches this conformance check and device group generation to using idxsets to make it easier to work with those, with the eventual aim to unify device group representations. Also try to adjust users of these functions to use idxsets these will need/return, without causing too much interference. Signed-off-by: Alper Nebi Yasak Part-of: --- src/modules/alsa/alsa-ucm.c | 156 +++++++++++++++--------------------- 1 file changed, 63 insertions(+), 93 deletions(-) diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c index b174ac807..1936ce2bf 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -187,17 +187,6 @@ static char *ucm_verb_value( return (char *)value; } -static int ucm_device_exists(pa_idxset *idxset, pa_alsa_ucm_device *dev) { - pa_alsa_ucm_device *d; - uint32_t idx; - - PA_IDXSET_FOREACH(d, idxset, idx) - if (d == dev) - return 1; - - return 0; -} - static void ucm_add_devices_to_idxset( pa_idxset *idxset, pa_alsa_ucm_device *me, @@ -1060,14 +1049,15 @@ static void ucm_add_port_combination( pa_hashmap *hash, pa_alsa_ucm_mapping_context *context, bool is_sink, - pa_alsa_ucm_device **pdevices, - int num, + pa_idxset *devices, pa_hashmap *ports, pa_card_profile *cp, pa_core *core) { pa_device_port *port; int i; + int num = pa_idxset_size(devices); + uint32_t idx; unsigned priority; double prio2; char *name, *desc; @@ -1081,8 +1071,11 @@ static void ucm_add_port_combination( pa_device_port_type_t type, type2; void *state; - for (i = 0; i < num; i++) - sorted[i] = pdevices[i]; + i = 0; + PA_IDXSET_FOREACH(dev, devices, idx) { + sorted[i] = dev; + i++; + } /* Sort by alphabetical order so as to have a deterministic naming scheme * for combination ports */ @@ -1157,7 +1150,7 @@ static void ucm_add_port_combination( pa_device_port_new_data_done(&port_data); data = PA_DEVICE_PORT_DATA(port); - ucm_port_data_init(data, context->ucm, port, pdevices, num); + ucm_port_data_init(data, context->ucm, port, sorted, num); port->impl_free = ucm_port_data_free; pa_hashmap_put(ports, port->name, port); @@ -1232,94 +1225,71 @@ static int ucm_port_contains(const char *port_name, const char *dev_name, bool i return ret; } -static int ucm_check_conformance( - pa_alsa_ucm_mapping_context *context, - pa_alsa_ucm_device **pdevices, - int dev_num, - pa_alsa_ucm_device *dev) { - - uint32_t idx; - pa_alsa_ucm_device *d; - int i; - +static bool devset_supports_device(pa_idxset *devices, pa_alsa_ucm_device *dev) { + pa_assert(devices); pa_assert(dev); - pa_log_debug("Check device %s conformance with %d other devices", - pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME), dev_num); - if (dev_num == 0) { - pa_log_debug("First device in combination, number 1"); - return 1; - } + /* Can add anything to empty group */ + if (pa_idxset_isempty(devices)) + return true; - PA_IDXSET_FOREACH(d, dev->conflicting_devices, idx) { - /* No conflicting device must already be selected */ - for (i = 0; i < dev_num; i++) { - if (pdevices[i] == d) { - pa_log_debug("Conflicting device found"); - return 0; - } - } - } + /* No conflicting device must already be selected */ + if (!pa_idxset_isdisjoint(devices, dev->conflicting_devices)) + return false; - if (!pa_idxset_isempty(dev->supported_devices)) { - /* No already selected device must be unsupported */ - for (i = 0; i < dev_num; i++) { - if (!ucm_device_exists(dev->supported_devices, pdevices[i])) { - pa_log_debug("Supported device not found"); - return 0; - } - } - } + /* No already selected device must be unsupported */ + if (!pa_idxset_isempty(dev->supported_devices)) + if (!pa_idxset_issubset(devices, dev->supported_devices)) + return false; if (pa_idxset_isempty(dev->conflicting_devices) && pa_idxset_isempty(dev->supported_devices)) { - pa_log_debug("Not support any other devices"); - return 0; + return false; } - pa_log_debug("Device added to combination, number %d", dev_num + 1); - return 1; + return true; } -static inline pa_alsa_ucm_device *get_next_device(pa_idxset *idxset, uint32_t *idx) { +/* Iterates nonempty subsets of UCM devices that can be simultaneously + * used, including subsets of previously returned subsets. At start, + * *state should be NULL. It's not safe to modify the devices argument + * until iteration ends. The returned idxsets must be freed by the + * caller. */ +static pa_idxset *iterate_device_subsets(pa_idxset *devices, void **state) { + uint32_t idx; pa_alsa_ucm_device *dev; - if (*idx == PA_IDXSET_INVALID) - dev = pa_idxset_first(idxset, idx); - else - dev = pa_idxset_next(idxset, idx); + pa_assert(devices); + pa_assert(state); - return dev; -} + if (*state == NULL) { + /* First iteration, start adding from first device */ + *state = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); + dev = pa_idxset_first(devices, &idx); -static void ucm_add_ports_combination( - pa_hashmap *hash, - pa_alsa_ucm_mapping_context *context, - bool is_sink, - pa_alsa_ucm_device **pdevices, - int dev_num, - uint32_t map_index, - pa_hashmap *ports, - pa_card_profile *cp, - pa_core *core) { - - pa_alsa_ucm_device *dev; - uint32_t idx = map_index; - - if ((dev = get_next_device(context->ucm_devices, &idx)) == NULL) - return; - - /* check if device at map_index can combine with existing devices combination */ - if (ucm_check_conformance(context, pdevices, dev_num, dev)) { - /* add device at map_index to devices combination */ - pdevices[dev_num] = dev; - /* add current devices combination as a new port */ - ucm_add_port_combination(hash, context, is_sink, pdevices, dev_num + 1, ports, cp, core); - /* try more elements combination */ - ucm_add_ports_combination(hash, context, is_sink, pdevices, dev_num + 1, idx, ports, cp, core); + } else { + /* Backtrack the most recent device we added and skip it */ + dev = pa_idxset_steal_last(*state, NULL); + pa_idxset_get_by_data(devices, dev, &idx); + if (dev) + dev = pa_idxset_next(devices, &idx); } - /* try other device with current elements number */ - ucm_add_ports_combination(hash, context, is_sink, pdevices, dev_num, idx, ports, cp, core); + /* Try adding devices we haven't decided on yet */ + for (; dev; dev = pa_idxset_next(devices, &idx)) { + if (devset_supports_device(*state, dev)) + pa_idxset_put(*state, dev, NULL); + } + + if (pa_idxset_isempty(*state)) { + /* No more choices to backtrack on, therefore no more subsets to + * return after this. Don't return the empty set, instead clean + * up and end iteration. */ + pa_idxset_free(*state, NULL); + *state = NULL; + return NULL; + } + + return pa_idxset_copy(*state, NULL); } static char* merge_roles(const char *cur, const char *add) { @@ -1359,14 +1329,14 @@ void pa_alsa_ucm_add_ports_combination( pa_card_profile *cp, pa_core *core) { - pa_alsa_ucm_device **pdevices; + pa_idxset *devices; + void *state = NULL; pa_assert(context->ucm_devices); - if (pa_idxset_size(context->ucm_devices) > 0) { - pdevices = pa_xnew(pa_alsa_ucm_device *, pa_idxset_size(context->ucm_devices)); - ucm_add_ports_combination(p, context, is_sink, pdevices, 0, PA_IDXSET_INVALID, ports, cp, core); - pa_xfree(pdevices); + while ((devices = iterate_device_subsets(context->ucm_devices, &state))) { + ucm_add_port_combination(p, context, is_sink, devices, ports, cp, core); + pa_idxset_free(devices, NULL); } /* ELD devices */ From 5245117781e26978371f74b9460ad90275112074 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Mon, 28 Jun 2021 17:16:08 +0300 Subject: [PATCH 027/260] alsa-ucm: Fix device conformance check Right now this check is rejecting devices whose UCM config specifies neither a conflicting device nor a supported device list, and accepting devices which specify both. However, a device without neither list is actually unrestricted, and a device with both lists is a configuration error. Fix the check to accept the former. Furthermore, this is missing another case where an already selected device might have a supported devices list that doesn't have the candidate device. Make this function also check against that, and also make it accept devices already in the set. Signed-off-by: Alper Nebi Yasak Part-of: --- src/modules/alsa/alsa-ucm.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c index 1936ce2bf..88baf4370 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -1226,6 +1226,9 @@ static int ucm_port_contains(const char *port_name, const char *dev_name, bool i } static bool devset_supports_device(pa_idxset *devices, pa_alsa_ucm_device *dev) { + pa_alsa_ucm_device *d; + uint32_t idx; + pa_assert(devices); pa_assert(dev); @@ -1233,6 +1236,10 @@ static bool devset_supports_device(pa_idxset *devices, pa_alsa_ucm_device *dev) if (pa_idxset_isempty(devices)) return true; + /* Device already selected */ + if (pa_idxset_contains(devices, dev)) + return true; + /* No conflicting device must already be selected */ if (!pa_idxset_isdisjoint(devices, dev->conflicting_devices)) return false; @@ -1242,9 +1249,11 @@ static bool devset_supports_device(pa_idxset *devices, pa_alsa_ucm_device *dev) if (!pa_idxset_issubset(devices, dev->supported_devices)) return false; - if (pa_idxset_isempty(dev->conflicting_devices) && pa_idxset_isempty(dev->supported_devices)) { - return false; - } + /* Must not be unsupported by any selected device */ + PA_IDXSET_FOREACH(d, devices, idx) + if (!pa_idxset_isempty(d->supported_devices)) + if (!pa_idxset_contains(d->supported_devices, dev)) + return false; return true; } From e8e2f4320c28dbf20b5601135ec11c867f6d4342 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Mon, 28 Jun 2021 19:16:37 +0300 Subject: [PATCH 028/260] alsa-ucm: Split out helpers for device set name, description, priority Combination port logic calculates some useful properties for device groups that we could reuse while generating multiple profiles to support conflicting devices. Split them into their own functions. Signed-off-by: Alper Nebi Yasak Part-of: --- src/modules/alsa/alsa-ucm.c | 155 +++++++++++++++++++++++++++--------- 1 file changed, 119 insertions(+), 36 deletions(-) diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c index 88baf4370..eda2c2bf5 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -1045,6 +1045,109 @@ fail: } } +static char *devset_name(pa_idxset *devices, const char *sep) { + int i = 0; + int num = pa_idxset_size(devices); + pa_alsa_ucm_device *sorted[num], *dev; + char *dev_names = NULL; + char *tmp = NULL; + uint32_t idx; + + PA_IDXSET_FOREACH(dev, devices, idx) { + sorted[i] = dev; + i++; + } + + /* Sort by alphabetical order so as to have a deterministic naming scheme */ + qsort(&sorted[0], num, sizeof(pa_alsa_ucm_device *), pa_alsa_ucm_device_cmp); + + for (i = 0; i < num; i++) { + dev = sorted[i]; + const char *dev_name = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME); + + if (!dev_names) { + dev_names = pa_xstrdup(dev_name); + } else { + tmp = pa_sprintf_malloc("%s%s%s", dev_names, sep, dev_name); + pa_xfree(dev_names); + dev_names = tmp; + } + } + + return dev_names; +} + +static char *devset_description(pa_idxset *devices, const char *sep) { + int i = 0; + int num = pa_idxset_size(devices); + pa_alsa_ucm_device *sorted[num], *dev; + char *dev_descs = NULL; + char *tmp = NULL; + uint32_t idx; + + PA_IDXSET_FOREACH(dev, devices, idx) { + sorted[i] = dev; + i++; + } + + /* Sort by alphabetical order to match devset_name() */ + qsort(&sorted[0], num, sizeof(pa_alsa_ucm_device *), pa_alsa_ucm_device_cmp); + + for (i = 0; i < num; i++) { + dev = sorted[i]; + const char *dev_desc = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_DESCRIPTION); + + if (!dev_descs) { + dev_descs = pa_xstrdup(dev_desc); + } else { + tmp = pa_sprintf_malloc("%s%s%s", dev_descs, sep, dev_desc); + pa_xfree(dev_descs); + dev_descs = tmp; + } + } + + return dev_descs; +} + +/* If invert is true, uses the formula 1/p = 1/p1 + 1/p2 + ... 1/pn. + * This way, the result will always be less than the individual components, + * yet higher components will lead to higher result. */ +static unsigned devset_playback_priority(pa_idxset *devices, bool invert) { + pa_alsa_ucm_device *dev; + uint32_t idx; + double priority = 0; + + PA_IDXSET_FOREACH(dev, devices, idx) { + if (dev->playback_priority > 0 && invert) + priority += 1.0 / dev->playback_priority; + else + priority += dev->playback_priority; + } + + if (priority > 0 && invert) + return 1.0 / priority; + + return (unsigned) priority; +} + +static unsigned devset_capture_priority(pa_idxset *devices, bool invert) { + pa_alsa_ucm_device *dev; + uint32_t idx; + double priority = 0; + + PA_IDXSET_FOREACH(dev, devices, idx) { + if (dev->capture_priority > 0 && invert) + priority += 1.0 / dev->capture_priority; + else + priority += dev->capture_priority; + } + + if (priority > 0 && invert) + return 1.0 / priority; + + return (unsigned) priority; +} + static void ucm_add_port_combination( pa_hashmap *hash, pa_alsa_ucm_mapping_context *context, @@ -1059,9 +1162,7 @@ static void ucm_add_port_combination( int num = pa_idxset_size(devices); uint32_t idx; unsigned priority; - double prio2; - char *name, *desc; - const char *dev_name; + char *name, *desc, *tmp; const char *direction; const char *profile; pa_alsa_ucm_device *sorted[num], *dev; @@ -1081,36 +1182,26 @@ static void ucm_add_port_combination( * for combination ports */ qsort(&sorted[0], num, sizeof(pa_alsa_ucm_device *), pa_alsa_ucm_device_cmp); + name = devset_name(devices, "+"); + tmp = pa_sprintf_malloc("%s%s", is_sink ? PA_UCM_PRE_TAG_OUTPUT : PA_UCM_PRE_TAG_INPUT, name); + pa_xfree(name); + name = tmp; + + desc = devset_description(devices, ", "); + if (pa_idxset_size(devices) > 1) { + tmp = pa_sprintf_malloc("Combination port for %s", desc); + pa_xfree(desc); + desc = tmp; + } + + /* Make combination ports always have lower priority */ + priority = is_sink ? devset_playback_priority(devices, true) : devset_capture_priority(devices, true); + dev = sorted[0]; - dev_name = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME); - - name = pa_sprintf_malloc("%s%s", is_sink ? PA_UCM_PRE_TAG_OUTPUT : PA_UCM_PRE_TAG_INPUT, dev_name); - desc = num == 1 ? pa_xstrdup(pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_DESCRIPTION)) - : pa_sprintf_malloc("Combination port for %s", dev_name); - - priority = is_sink ? dev->playback_priority : dev->capture_priority; - prio2 = (priority == 0 ? 0 : 1.0/priority); jack = ucm_get_jack(context->ucm, dev); type = dev->type; for (i = 1; i < num; i++) { - char *tmp; - - dev = sorted[i]; - dev_name = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME); - - tmp = pa_sprintf_malloc("%s+%s", name, dev_name); - pa_xfree(name); - name = tmp; - - tmp = pa_sprintf_malloc("%s,%s", desc, dev_name); - pa_xfree(desc); - desc = tmp; - - priority = is_sink ? dev->playback_priority : dev->capture_priority; - if (priority != 0 && prio2 > 0) - prio2 += 1.0/priority; - jack2 = ucm_get_jack(context->ucm, dev); if (jack2) { if (jack && jack != jack2) @@ -1126,14 +1217,6 @@ static void ucm_add_port_combination( } } - /* Make combination ports always have lower priority, and use the formula - 1/p = 1/p1 + 1/p2 + ... 1/pn. - This way, the result will always be less than the individual components, - yet higher components will lead to higher result. */ - - if (num > 1) - priority = prio2 > 0 ? 1.0/prio2 : 0; - port = pa_hashmap_get(ports, name); if (!port) { pa_device_port_new_data port_data; From a50330a4a5ea7619f4de41c6d907a36a5e5ce022 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Tue, 9 Nov 2021 21:02:03 +0300 Subject: [PATCH 029/260] alsa-ucm: Make one input/output mapping per UCM device PulseAudio combines UCM devices that have the same PlaybackPCM or CapturePCM value into a single mapping with multiple ports. It also creates ports in the same mapping for each valid combination of those UCM devices. Since mappings are the things we put in profiles, we can put in a profile either all devices of a joint mapping or none of them. This causes some complications with device conflicts. For example, a different UCM device might be marked as conflicting with some (but not all) of the devices in a joint mapping. In this case we can do one of three things: - Include all devices in one profile, and hope the conflicting device isn't chosen as the mapping's active port. We shouldn't do this as it puts conflicting devices in the same profile. - Make one profile with the joint group, and one with the other device. This is somewhat acceptable as we have no conflicts, but we sacrifice some compatible combinations of devices. - Do not group the devices into the same mapping, and make one profile for each compatible combination of devices. This appears to be the best option, one where we can always have the maximum number of working devices. This patch chooses the third option and makes one input and/or output mapping per UCM device, by using UCM device names instead of PCM device strings in the mapping names. Signed-off-by: Alper Nebi Yasak Part-of: --- src/modules/alsa/alsa-ucm.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c index eda2c2bf5..f8a2134d2 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -1664,17 +1664,11 @@ static void alsa_mapping_add_ucm_modifier(pa_alsa_mapping *m, pa_alsa_ucm_modifi pa_channel_map_init(&m->channel_map); } -static pa_alsa_mapping* ucm_alsa_mapping_get(pa_alsa_ucm_config *ucm, pa_alsa_profile_set *ps, const char *verb_name, const char *device_str, bool is_sink) { +static pa_alsa_mapping* ucm_alsa_mapping_get(pa_alsa_ucm_config *ucm, pa_alsa_profile_set *ps, const char *verb_name, const char *ucm_name, bool is_sink) { pa_alsa_mapping *m; char *mapping_name; - size_t ucm_alibpref_len = 0; - /* find private alsa-lib's configuration device prefix */ - - if (ucm->alib_prefix && pa_startswith(device_str, ucm->alib_prefix)) - ucm_alibpref_len = strlen(ucm->alib_prefix); - - mapping_name = pa_sprintf_malloc("Mapping %s: %s: %s", verb_name, device_str + ucm_alibpref_len, is_sink ? "sink" : "source"); + mapping_name = pa_sprintf_malloc("Mapping %s: %s: %s", verb_name, ucm_name, is_sink ? "sink" : "source"); m = pa_alsa_mapping_get(ps, mapping_name); @@ -1698,7 +1692,7 @@ static int ucm_create_mapping_direction( pa_alsa_mapping *m; unsigned priority, rate, channels; - m = ucm_alsa_mapping_get(ucm, ps, verb_name, device_str, is_sink); + m = ucm_alsa_mapping_get(ucm, ps, verb_name, device_name, is_sink); if (!m) return -1; @@ -1747,7 +1741,7 @@ static int ucm_create_mapping_for_modifier( pa_alsa_mapping *m; - m = ucm_alsa_mapping_get(ucm, ps, verb_name, device_str, is_sink); + m = ucm_alsa_mapping_get(ucm, ps, verb_name, mod_name, is_sink); if (!m) return -1; From 0789a8fb767abffaf6070b14fe805ef41728c60f Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Tue, 16 Nov 2021 19:24:05 +0300 Subject: [PATCH 030/260] alsa-ucm: Remove combination port generation logic A previous commit makes mapping names depend on the UCM device name. Since UCM device names are unique, this means a mapping will at most have one port and thus no combination ports can be generated. This removes the dead code in the pa_alsa_ucm_add_ports_combination() function, unrolls the remaining code in its helper functions that it used, and renames it to pa_alsa_ucm_add_port() to signal that it no longer generates combinations. Signed-off-by: Alper Nebi Yasak Part-of: --- src/modules/alsa/alsa-ucm.c | 147 +++++++++------------------- src/modules/alsa/alsa-ucm.h | 2 +- src/modules/alsa/module-alsa-card.c | 4 +- 3 files changed, 48 insertions(+), 105 deletions(-) diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c index f8a2134d2..f7450ed74 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -1045,7 +1045,7 @@ fail: } } -static char *devset_name(pa_idxset *devices, const char *sep) { +PA_UNUSED static char *devset_name(pa_idxset *devices, const char *sep) { int i = 0; int num = pa_idxset_size(devices); pa_alsa_ucm_device *sorted[num], *dev; @@ -1077,7 +1077,7 @@ static char *devset_name(pa_idxset *devices, const char *sep) { return dev_names; } -static char *devset_description(pa_idxset *devices, const char *sep) { +PA_UNUSED static char *devset_description(pa_idxset *devices, const char *sep) { int i = 0; int num = pa_idxset_size(devices); pa_alsa_ucm_device *sorted[num], *dev; @@ -1112,7 +1112,7 @@ static char *devset_description(pa_idxset *devices, const char *sep) { /* If invert is true, uses the formula 1/p = 1/p1 + 1/p2 + ... 1/pn. * This way, the result will always be less than the individual components, * yet higher components will lead to higher result. */ -static unsigned devset_playback_priority(pa_idxset *devices, bool invert) { +PA_UNUSED static unsigned devset_playback_priority(pa_idxset *devices, bool invert) { pa_alsa_ucm_device *dev; uint32_t idx; double priority = 0; @@ -1130,7 +1130,7 @@ static unsigned devset_playback_priority(pa_idxset *devices, bool invert) { return (unsigned) priority; } -static unsigned devset_capture_priority(pa_idxset *devices, bool invert) { +PA_UNUSED static unsigned devset_capture_priority(pa_idxset *devices, bool invert) { pa_alsa_ucm_device *dev; uint32_t idx; double priority = 0; @@ -1148,75 +1148,42 @@ static unsigned devset_capture_priority(pa_idxset *devices, bool invert) { return (unsigned) priority; } -static void ucm_add_port_combination( +void pa_alsa_ucm_add_port( pa_hashmap *hash, pa_alsa_ucm_mapping_context *context, bool is_sink, - pa_idxset *devices, pa_hashmap *ports, pa_card_profile *cp, pa_core *core) { pa_device_port *port; - int i; - int num = pa_idxset_size(devices); - uint32_t idx; unsigned priority; - char *name, *desc, *tmp; + char *name, *desc; + const char *dev_name; const char *direction; const char *profile; - pa_alsa_ucm_device *sorted[num], *dev; + pa_alsa_ucm_device *dev; pa_alsa_ucm_port_data *data; pa_alsa_ucm_volume *vol; - pa_alsa_jack *jack, *jack2; - pa_device_port_type_t type, type2; + pa_alsa_jack *jack; + pa_device_port_type_t type; + uint32_t idx; void *state; - i = 0; - PA_IDXSET_FOREACH(dev, devices, idx) { - sorted[i] = dev; - i++; - } + pa_assert(context->ucm_devices); + pa_assert(pa_idxset_size(context->ucm_devices) <= 1); - /* Sort by alphabetical order so as to have a deterministic naming scheme - * for combination ports */ - qsort(&sorted[0], num, sizeof(pa_alsa_ucm_device *), pa_alsa_ucm_device_cmp); + dev = pa_idxset_first(context->ucm_devices, &idx); + if (!dev) + return; - name = devset_name(devices, "+"); - tmp = pa_sprintf_malloc("%s%s", is_sink ? PA_UCM_PRE_TAG_OUTPUT : PA_UCM_PRE_TAG_INPUT, name); - pa_xfree(name); - name = tmp; - - desc = devset_description(devices, ", "); - if (pa_idxset_size(devices) > 1) { - tmp = pa_sprintf_malloc("Combination port for %s", desc); - pa_xfree(desc); - desc = tmp; - } - - /* Make combination ports always have lower priority */ - priority = is_sink ? devset_playback_priority(devices, true) : devset_capture_priority(devices, true); - - dev = sorted[0]; + dev_name = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME); + name = pa_sprintf_malloc("%s%s", is_sink ? PA_UCM_PRE_TAG_OUTPUT : PA_UCM_PRE_TAG_INPUT, dev_name); + desc = pa_xstrdup(pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_DESCRIPTION)); + priority = is_sink ? dev->playback_priority : dev->capture_priority; jack = ucm_get_jack(context->ucm, dev); type = dev->type; - for (i = 1; i < num; i++) { - jack2 = ucm_get_jack(context->ucm, dev); - if (jack2) { - if (jack && jack != jack2) - pa_log_warn("Multiple jacks per combined device '%s': '%s' '%s'", name, jack->name, jack2->name); - jack = jack2; - } - - type2 = dev->type; - if (type2 != PA_DEVICE_PORT_TYPE_UNKNOWN) { - if (type != PA_DEVICE_PORT_TYPE_UNKNOWN && type != type2) - pa_log_warn("Multiple device types per combined device '%s': %d %d", name, type, type2); - type = type2; - } - } - port = pa_hashmap_get(ports, name); if (!port) { pa_device_port_new_data port_data; @@ -1233,37 +1200,32 @@ static void ucm_add_port_combination( pa_device_port_new_data_done(&port_data); data = PA_DEVICE_PORT_DATA(port); - ucm_port_data_init(data, context->ucm, port, sorted, num); + ucm_port_data_init(data, context->ucm, port, &dev, 1); port->impl_free = ucm_port_data_free; pa_hashmap_put(ports, port->name, port); pa_log_debug("Add port %s: %s", port->name, port->description); - if (num == 1) { - /* To keep things simple and not worry about stacking controls, we only support hardware volumes on non-combination - * ports. */ - PA_HASHMAP_FOREACH_KV(profile, vol, is_sink ? dev->playback_volumes : dev->capture_volumes, state) { - pa_alsa_path *path = pa_alsa_path_synthesize(vol->mixer_elem, - is_sink ? PA_ALSA_DIRECTION_OUTPUT : PA_ALSA_DIRECTION_INPUT); + PA_HASHMAP_FOREACH_KV(profile, vol, is_sink ? dev->playback_volumes : dev->capture_volumes, state) { + pa_alsa_path *path = pa_alsa_path_synthesize(vol->mixer_elem, + is_sink ? PA_ALSA_DIRECTION_OUTPUT : PA_ALSA_DIRECTION_INPUT); - if (!path) - pa_log_warn("Failed to set up volume control: %s", vol->mixer_elem); - else { - if (vol->master_elem) { - pa_alsa_element *e = pa_alsa_element_get(path, vol->master_elem, false); - e->switch_use = PA_ALSA_SWITCH_MUTE; - e->volume_use = PA_ALSA_VOLUME_MERGE; - } - - pa_hashmap_put(data->paths, pa_xstrdup(profile), path); - - /* Add path also to already created empty path set */ - dev = sorted[0]; - if (is_sink) - pa_hashmap_put(dev->playback_mapping->output_path_set->paths, pa_xstrdup(vol->mixer_elem), path); - else - pa_hashmap_put(dev->capture_mapping->input_path_set->paths, pa_xstrdup(vol->mixer_elem), path); + if (!path) + pa_log_warn("Failed to set up volume control: %s", vol->mixer_elem); + else { + if (vol->master_elem) { + pa_alsa_element *e = pa_alsa_element_get(path, vol->master_elem, false); + e->switch_use = PA_ALSA_SWITCH_MUTE; + e->volume_use = PA_ALSA_VOLUME_MERGE; } + + pa_hashmap_put(data->paths, pa_xstrdup(profile), path); + + /* Add path also to already created empty path set */ + if (is_sink) + pa_hashmap_put(dev->playback_mapping->output_path_set->paths, pa_xstrdup(vol->mixer_elem), path); + else + pa_hashmap_put(dev->capture_mapping->input_path_set->paths, pa_xstrdup(vol->mixer_elem), path); } } } @@ -1285,6 +1247,9 @@ static void ucm_add_port_combination( pa_hashmap_put(hash, port->name, port); pa_device_port_ref(port); } + + /* ELD devices */ + set_eld_devices(ports); } static int ucm_port_contains(const char *port_name, const char *dev_name, bool is_sink) { @@ -1346,7 +1311,7 @@ static bool devset_supports_device(pa_idxset *devices, pa_alsa_ucm_device *dev) * *state should be NULL. It's not safe to modify the devices argument * until iteration ends. The returned idxsets must be freed by the * caller. */ -static pa_idxset *iterate_device_subsets(pa_idxset *devices, void **state) { +PA_UNUSED static pa_idxset *iterate_device_subsets(pa_idxset *devices, void **state) { uint32_t idx; pa_alsa_ucm_device *dev; @@ -1413,28 +1378,6 @@ static char* merge_roles(const char *cur, const char *add) { return ret; } -void pa_alsa_ucm_add_ports_combination( - pa_hashmap *p, - pa_alsa_ucm_mapping_context *context, - bool is_sink, - pa_hashmap *ports, - pa_card_profile *cp, - pa_core *core) { - - pa_idxset *devices; - void *state = NULL; - - pa_assert(context->ucm_devices); - - while ((devices = iterate_device_subsets(context->ucm_devices, &state))) { - ucm_add_port_combination(p, context, is_sink, devices, ports, cp, core); - pa_idxset_free(devices, NULL); - } - - /* ELD devices */ - set_eld_devices(ports); -} - void pa_alsa_ucm_add_ports( pa_hashmap **p, pa_proplist *proplist, @@ -1455,7 +1398,7 @@ void pa_alsa_ucm_add_ports( pa_assert(*p); /* add ports first */ - pa_alsa_ucm_add_ports_combination(*p, context, is_sink, card->ports, NULL, card->core); + pa_alsa_ucm_add_port(*p, context, is_sink, card->ports, NULL, card->core); /* now set up volume paths if any */ probe_volumes(*p, is_sink, pcm_handle, context->ucm->mixers, ignore_dB); @@ -2534,7 +2477,7 @@ void pa_alsa_ucm_add_ports( bool ignore_dB) { } -void pa_alsa_ucm_add_ports_combination( +void pa_alsa_ucm_add_port( pa_hashmap *hash, pa_alsa_ucm_mapping_context *context, bool is_sink, diff --git a/src/modules/alsa/alsa-ucm.h b/src/modules/alsa/alsa-ucm.h index 1652aff8f..236a2452d 100644 --- a/src/modules/alsa/alsa-ucm.h +++ b/src/modules/alsa/alsa-ucm.h @@ -158,7 +158,7 @@ void pa_alsa_ucm_add_ports( pa_card *card, snd_pcm_t *pcm_handle, bool ignore_dB); -void pa_alsa_ucm_add_ports_combination( +void pa_alsa_ucm_add_port( pa_hashmap *hash, pa_alsa_ucm_mapping_context *context, bool is_sink, diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c index 2efa96a0f..a69fb7acc 100644 --- a/src/modules/alsa/module-alsa-card.c +++ b/src/modules/alsa/module-alsa-card.c @@ -162,7 +162,7 @@ static void add_profiles(struct userdata *u, pa_hashmap *h, pa_hashmap *ports) { PA_IDXSET_FOREACH(m, ap->output_mappings, idx) { if (u->use_ucm) - pa_alsa_ucm_add_ports_combination(NULL, &m->ucm_context, true, ports, cp, u->core); + pa_alsa_ucm_add_port(NULL, &m->ucm_context, true, ports, cp, u->core); else pa_alsa_path_set_add_ports(m->output_path_set, cp, ports, NULL, u->core); if (m->channel_map.channels > cp->max_sink_channels) @@ -175,7 +175,7 @@ static void add_profiles(struct userdata *u, pa_hashmap *h, pa_hashmap *ports) { PA_IDXSET_FOREACH(m, ap->input_mappings, idx) { if (u->use_ucm) - pa_alsa_ucm_add_ports_combination(NULL, &m->ucm_context, false, ports, cp, u->core); + pa_alsa_ucm_add_port(NULL, &m->ucm_context, false, ports, cp, u->core); else pa_alsa_path_set_add_ports(m->input_path_set, cp, ports, NULL, u->core); if (m->channel_map.channels > cp->max_source_channels) From bf1708213b0f28093ea4de6c033f0d5a29dabcbb Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Tue, 16 Nov 2021 20:09:32 +0300 Subject: [PATCH 031/260] alsa-ucm: Make ports store only one device After previous patches, we should be generating no combination ports, so we don't need to store multiple devices per port. Simplify the code based on this. Signed-off-by: Alper Nebi Yasak Part-of: --- src/modules/alsa/alsa-sink.c | 4 +- src/modules/alsa/alsa-source.c | 4 +- src/modules/alsa/alsa-ucm.c | 120 ++++++--------------------------- src/modules/alsa/alsa-ucm.h | 6 +- 4 files changed, 26 insertions(+), 108 deletions(-) diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index ee3266f75..b249df680 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -1721,7 +1721,7 @@ static int sink_set_port_ucm_cb(pa_sink *s, pa_device_port *p) { else sync_mixer(u, p); - return pa_alsa_ucm_set_port(u->ucm_context, p, true); + return pa_alsa_ucm_set_port(u->ucm_context, p); } static int sink_set_port_cb(pa_sink *s, pa_device_port *p) { @@ -2239,7 +2239,7 @@ static int setup_mixer(struct userdata *u, bool ignore_dB) { * will be NULL, but the UCM device enable sequence will still need to be * executed. */ if (u->sink->active_port && u->ucm_context) { - if (pa_alsa_ucm_set_port(u->ucm_context, u->sink->active_port, true) < 0) + if (pa_alsa_ucm_set_port(u->ucm_context, u->sink->active_port) < 0) return -1; } diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c index 67563d0c3..ef8b12c32 100644 --- a/src/modules/alsa/alsa-source.c +++ b/src/modules/alsa/alsa-source.c @@ -1595,7 +1595,7 @@ static int source_set_port_ucm_cb(pa_source *s, pa_device_port *p) { else sync_mixer(u, p); - return pa_alsa_ucm_set_port(u->ucm_context, p, false); + return pa_alsa_ucm_set_port(u->ucm_context, p); } static int source_set_port_cb(pa_source *s, pa_device_port *p) { @@ -1943,7 +1943,7 @@ static int setup_mixer(struct userdata *u, bool ignore_dB) { * will be NULL, but the UCM device enable sequence will still need to be * executed. */ if (u->source->active_port && u->ucm_context) { - if (pa_alsa_ucm_set_port(u->ucm_context, u->source->active_port, false) < 0) + if (pa_alsa_ucm_set_port(u->ucm_context, u->source->active_port) < 0) return -1; } diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c index f7450ed74..da4cba70a 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -89,9 +89,8 @@ static pa_alsa_ucm_device *verb_find_device(pa_alsa_ucm_verb *verb, const char * static void ucm_port_data_init(pa_alsa_ucm_port_data *port, pa_alsa_ucm_config *ucm, pa_device_port *core_port, - pa_alsa_ucm_device **devices, unsigned n_devices); + pa_alsa_ucm_device *device); static void ucm_port_data_free(pa_device_port *port); -static void ucm_port_update_available(pa_alsa_ucm_port_data *port); static struct ucm_type types[] = { {"None", PA_DEVICE_PORT_TYPE_UNKNOWN}, @@ -955,28 +954,13 @@ static void set_eld_devices(pa_hashmap *hash) pa_device_port *port; pa_alsa_ucm_port_data *data; pa_alsa_ucm_device *dev; - const char *eld_mixer_device_name; void *state; - int idx, eld_device; PA_HASHMAP_FOREACH(port, hash, state) { data = PA_DEVICE_PORT_DATA(port); - eld_mixer_device_name = NULL; - eld_device = -1; - PA_DYNARRAY_FOREACH(dev, data->devices, idx) { - if (dev->eld_device >= 0 && dev->eld_mixer_device_name) { - if (eld_device >= 0 && eld_device != dev->eld_device) { - pa_log_error("The ELD device is already set!"); - } else if (eld_mixer_device_name && pa_streq(dev->eld_mixer_device_name, eld_mixer_device_name)) { - pa_log_error("The ELD mixer device is already set (%s, %s)!", dev->eld_mixer_device_name, dev->eld_mixer_device_name); - } else { - eld_mixer_device_name = dev->eld_mixer_device_name; - eld_device = dev->eld_device; - } - } - } - data->eld_device = eld_device; - data->eld_mixer_device_name = pa_xstrdup(eld_mixer_device_name); + dev = data->device; + data->eld_device = dev->eld_device; + data->eld_mixer_device_name = pa_xstrdup(dev->eld_mixer_device_name); } } @@ -999,24 +983,14 @@ static void probe_volumes(pa_hashmap *hash, bool is_sink, snd_pcm_t *pcm_handle, pa_alsa_ucm_port_data *data; pa_alsa_ucm_device *dev; snd_mixer_t *mixer_handle; - const char *profile, *mdev, *mdev2; + const char *profile, *mdev; void *state, *state2; - int idx; PA_HASHMAP_FOREACH(port, hash, state) { data = PA_DEVICE_PORT_DATA(port); - mdev = NULL; - PA_DYNARRAY_FOREACH(dev, data->devices, idx) { - mdev2 = get_mixer_device(dev, is_sink); - if (mdev && mdev2 && !pa_streq(mdev, mdev2)) { - pa_log_error("Two mixer device names found ('%s', '%s'), using s/w volume", mdev, mdev2); - goto fail; - } - if (mdev2) - mdev = mdev2; - } - + dev = data->device; + mdev = get_mixer_device(dev, is_sink); if (mdev == NULL || !(mixer_handle = pa_alsa_open_mixer_by_name(mixers, mdev, true))) { pa_log_error("Failed to find a working mixer device (%s).", mdev); goto fail; @@ -1200,7 +1174,7 @@ void pa_alsa_ucm_add_port( pa_device_port_new_data_done(&port_data); data = PA_DEVICE_PORT_DATA(port); - ucm_port_data_init(data, context->ucm, port, &dev, 1); + ucm_port_data_init(data, context->ucm, port, dev); port->impl_free = ucm_port_data_free; pa_hashmap_put(ports, port->name, port); @@ -1252,27 +1226,6 @@ void pa_alsa_ucm_add_port( set_eld_devices(ports); } -static int ucm_port_contains(const char *port_name, const char *dev_name, bool is_sink) { - int ret = 0; - const char *r; - const char *state = NULL; - size_t len; - - if (!port_name || !dev_name) - return false; - - port_name += is_sink ? strlen(PA_UCM_PRE_TAG_OUTPUT) : strlen(PA_UCM_PRE_TAG_INPUT); - - while ((r = pa_split_in_place(port_name, "+", &len, &state))) { - if (strlen(dev_name) == len && !strncmp(r, dev_name, len)) { - ret = 1; - break; - } - } - - return ret; -} - static bool devset_supports_device(pa_idxset *devices, pa_alsa_ucm_device *dev) { pa_alsa_ucm_device *d; uint32_t idx; @@ -1467,7 +1420,7 @@ int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, pa_card *card, pa_alsa_prof return ret; } -int pa_alsa_ucm_set_port(pa_alsa_ucm_mapping_context *context, pa_device_port *port, bool is_sink) { +int pa_alsa_ucm_set_port(pa_alsa_ucm_mapping_context *context, pa_device_port *port) { int i; int ret = 0; pa_alsa_ucm_config *ucm; @@ -1475,19 +1428,20 @@ int pa_alsa_ucm_set_port(pa_alsa_ucm_mapping_context *context, pa_device_port *p int enable_num = 0; uint32_t idx; pa_alsa_ucm_device *dev; + pa_alsa_ucm_port_data *data; pa_assert(context && context->ucm); ucm = context->ucm; pa_assert(ucm->ucm_mgr); + data = PA_DEVICE_PORT_DATA(port); + enable_devs = pa_xnew(pa_alsa_ucm_device *, pa_idxset_size(context->ucm_devices)); /* first disable then enable */ PA_IDXSET_FOREACH(dev, context->ucm_devices, idx) { - const char *dev_name = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME); - - if (ucm_port_contains(port->name, dev_name, is_sink)) + if (dev == data->device) enable_devs[enable_num++] = dev; else ret = ucm_device_disable(ucm, dev); @@ -2325,13 +2279,6 @@ void pa_alsa_ucm_roled_stream_end(pa_alsa_ucm_config *ucm, const char *role, pa_ } } -static void device_add_ucm_port(pa_alsa_ucm_device *device, pa_alsa_ucm_port_data *port) { - pa_assert(device); - pa_assert(port); - - pa_dynarray_append(device->ucm_ports, port); -} - static void device_set_jack(pa_alsa_ucm_device *device, pa_alsa_jack *jack) { pa_assert(device); pa_assert(jack); @@ -2364,7 +2311,7 @@ static void device_set_available(pa_alsa_ucm_device *device, pa_available_t avai device->available = available; PA_DYNARRAY_FOREACH(port, device->ucm_ports, idx) - ucm_port_update_available(port); + pa_device_port_set_available(port->core_port, port->device->available); } void pa_alsa_ucm_device_update_available(pa_alsa_ucm_device *device) { @@ -2388,27 +2335,22 @@ void pa_alsa_ucm_device_update_available(pa_alsa_ucm_device *device) { } static void ucm_port_data_init(pa_alsa_ucm_port_data *port, pa_alsa_ucm_config *ucm, pa_device_port *core_port, - pa_alsa_ucm_device **devices, unsigned n_devices) { - unsigned i; - + pa_alsa_ucm_device *device) { pa_assert(ucm); pa_assert(core_port); - pa_assert(devices); + pa_assert(device); port->ucm = ucm; port->core_port = core_port; - port->devices = pa_dynarray_new(NULL); port->eld_device = -1; - for (i = 0; i < n_devices; i++) { - pa_dynarray_append(port->devices, devices[i]); - device_add_ucm_port(devices[i], port); - } + port->device = device; + pa_dynarray_append(device->ucm_ports, port); port->paths = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, pa_xfree, (pa_free_cb_t) pa_alsa_path_free); - ucm_port_update_available(port); + pa_device_port_set_available(port->core_port, port->device->available); } static void ucm_port_data_free(pa_device_port *port) { @@ -2418,34 +2360,12 @@ static void ucm_port_data_free(pa_device_port *port) { ucm_port = PA_DEVICE_PORT_DATA(port); - if (ucm_port->devices) - pa_dynarray_free(ucm_port->devices); - if (ucm_port->paths) pa_hashmap_free(ucm_port->paths); pa_xfree(ucm_port->eld_mixer_device_name); } -static void ucm_port_update_available(pa_alsa_ucm_port_data *port) { - pa_alsa_ucm_device *device; - unsigned idx; - pa_available_t available = PA_AVAILABLE_YES; - - pa_assert(port); - - PA_DYNARRAY_FOREACH(device, port->devices, idx) { - if (device->available == PA_AVAILABLE_UNKNOWN) - available = PA_AVAILABLE_UNKNOWN; - else if (device->available == PA_AVAILABLE_NO) { - available = PA_AVAILABLE_NO; - break; - } - } - - pa_device_port_set_available(port->core_port, available); -} - #else /* HAVE_ALSA_UCM */ /* Dummy functions for systems without UCM support */ @@ -2486,7 +2406,7 @@ void pa_alsa_ucm_add_port( pa_core *core) { } -int pa_alsa_ucm_set_port(pa_alsa_ucm_mapping_context *context, pa_device_port *port, bool is_sink) { +int pa_alsa_ucm_set_port(pa_alsa_ucm_mapping_context *context, pa_device_port *port) { return -1; } diff --git a/src/modules/alsa/alsa-ucm.h b/src/modules/alsa/alsa-ucm.h index 236a2452d..735ec944a 100644 --- a/src/modules/alsa/alsa-ucm.h +++ b/src/modules/alsa/alsa-ucm.h @@ -165,7 +165,7 @@ void pa_alsa_ucm_add_port( pa_hashmap *ports, pa_card_profile *cp, pa_core *core); -int pa_alsa_ucm_set_port(pa_alsa_ucm_mapping_context *context, pa_device_port *port, bool is_sink); +int pa_alsa_ucm_set_port(pa_alsa_ucm_mapping_context *context, pa_device_port *port); void pa_alsa_ucm_free(pa_alsa_ucm_config *ucm); void pa_alsa_ucm_mapping_context_free(pa_alsa_ucm_mapping_context *context); @@ -274,9 +274,7 @@ struct pa_alsa_ucm_port_data { pa_alsa_ucm_config *ucm; pa_device_port *core_port; - /* A single port will be associated with multiple devices if it represents - * a combination of devices. */ - pa_dynarray *devices; /* pa_alsa_ucm_device */ + pa_alsa_ucm_device *device; /* profile name -> pa_alsa_path for volume control */ pa_hashmap *paths; From 084d70a1e2c3998b6292de23bf10ee09ebc9c4f2 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Tue, 16 Nov 2021 20:25:23 +0300 Subject: [PATCH 032/260] alsa-ucm: Make mapping UCM contexts have only one device After previous patches, we should be generating no combination ports, so we don't need to store multiple devices per mapping. Simplify the code based on this. Signed-off-by: Alper Nebi Yasak Part-of: --- src/modules/alsa/alsa-ucm.c | 102 ++++++++++++------------------------ src/modules/alsa/alsa-ucm.h | 2 +- 2 files changed, 35 insertions(+), 69 deletions(-) diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c index da4cba70a..a6eab6e4b 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -1141,13 +1141,9 @@ void pa_alsa_ucm_add_port( pa_alsa_ucm_volume *vol; pa_alsa_jack *jack; pa_device_port_type_t type; - uint32_t idx; void *state; - pa_assert(context->ucm_devices); - pa_assert(pa_idxset_size(context->ucm_devices) <= 1); - - dev = pa_idxset_first(context->ucm_devices, &idx); + dev = context->ucm_device; if (!dev) return; @@ -1366,7 +1362,9 @@ void pa_alsa_ucm_add_ports( /* then set property PA_PROP_DEVICE_INTENDED_ROLES */ merged_roles = pa_xstrdup(pa_proplist_gets(proplist, PA_PROP_DEVICE_INTENDED_ROLES)); - PA_IDXSET_FOREACH(dev, context->ucm_devices, idx) { + + dev = context->ucm_device; + if (dev) { const char *roles = pa_proplist_gets(dev->proplist, role_name); tmp = merge_roles(merged_roles, roles); pa_xfree(merged_roles); @@ -1421,12 +1419,7 @@ int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, pa_card *card, pa_alsa_prof } int pa_alsa_ucm_set_port(pa_alsa_ucm_mapping_context *context, pa_device_port *port) { - int i; - int ret = 0; pa_alsa_ucm_config *ucm; - pa_alsa_ucm_device **enable_devs; - int enable_num = 0; - uint32_t idx; pa_alsa_ucm_device *dev; pa_alsa_ucm_port_data *data; @@ -1436,27 +1429,10 @@ int pa_alsa_ucm_set_port(pa_alsa_ucm_mapping_context *context, pa_device_port *p pa_assert(ucm->ucm_mgr); data = PA_DEVICE_PORT_DATA(port); + dev = context->ucm_device; + pa_assert(dev == data->device); - enable_devs = pa_xnew(pa_alsa_ucm_device *, pa_idxset_size(context->ucm_devices)); - - /* first disable then enable */ - PA_IDXSET_FOREACH(dev, context->ucm_devices, idx) { - if (dev == data->device) - enable_devs[enable_num++] = dev; - else - ret = ucm_device_disable(ucm, dev); - - if (ret < 0) - break; - } - - for (i = 0; i < enable_num && ret == 0; i++) { - ret = ucm_device_enable(ucm, enable_devs[i]); - } - - pa_xfree(enable_devs); - - return ret; + return ucm_device_enable(ucm, dev); } static void ucm_add_mapping(pa_alsa_profile *p, pa_alsa_mapping *m) { @@ -1491,7 +1467,7 @@ static void alsa_mapping_add_ucm_device(pa_alsa_mapping *m, pa_alsa_ucm_device * const char *new_desc, *mdev; bool is_sink = m->direction == PA_ALSA_DIRECTION_OUTPUT; - pa_idxset_put(m->ucm_context.ucm_devices, device, NULL); + m->ucm_context.ucm_device = device; new_desc = pa_proplist_gets(device->proplist, PA_ALSA_PROP_UCM_DESCRIPTION); cur_desc = m->description; @@ -1600,8 +1576,7 @@ static int ucm_create_mapping_direction( rate = is_sink ? device->playback_rate : device->capture_rate; channels = is_sink ? device->playback_channels : device->capture_channels; - if (!m->ucm_context.ucm_devices) { /* new mapping */ - m->ucm_context.ucm_devices = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); + if (!m->ucm_context.ucm_device) { /* new mapping */ m->ucm_context.ucm = ucm; m->ucm_context.direction = is_sink ? PA_DIRECTION_OUTPUT : PA_DIRECTION_INPUT; @@ -1645,8 +1620,7 @@ static int ucm_create_mapping_for_modifier( pa_log_info("UCM mapping: %s modifier %s", m->name, mod_name); - if (!m->ucm_context.ucm_devices && !m->ucm_context.ucm_modifiers) { /* new mapping */ - m->ucm_context.ucm_devices = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); + if (!m->ucm_context.ucm_device && !m->ucm_context.ucm_modifiers) { /* new mapping */ m->ucm_context.ucm_modifiers = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); m->ucm_context.ucm = ucm; m->ucm_context.direction = is_sink ? PA_DIRECTION_OUTPUT : PA_DIRECTION_INPUT; @@ -1914,7 +1888,6 @@ static void mapping_init_eld(pa_alsa_mapping *m, snd_pcm_t *pcm) { pa_alsa_ucm_mapping_context *context = &m->ucm_context; pa_alsa_ucm_device *dev; - uint32_t idx; char *mdev, *alib_prefix; snd_pcm_info_t *info; int pcm_card, pcm_device; @@ -1930,13 +1903,12 @@ static void mapping_init_eld(pa_alsa_mapping *m, snd_pcm_t *pcm) alib_prefix = context->ucm->alib_prefix; - PA_IDXSET_FOREACH(dev, context->ucm_devices, idx) { - mdev = pa_sprintf_malloc("%shw:%i", alib_prefix ? alib_prefix : "", pcm_card); - if (mdev == NULL) - continue; - dev->eld_mixer_device_name = mdev; - dev->eld_device = pcm_device; - } + dev = context->ucm_device; + mdev = pa_sprintf_malloc("%shw:%i", alib_prefix ? alib_prefix : "", pcm_card); + if (mdev == NULL) + return; + dev->eld_mixer_device_name = mdev; + dev->eld_device = pcm_device; } static snd_pcm_t* mapping_open_pcm(pa_alsa_ucm_config *ucm, pa_alsa_mapping *m, int mode) { @@ -2000,24 +1972,21 @@ static void ucm_mapping_jack_probe(pa_alsa_mapping *m, pa_hashmap *mixers) { snd_mixer_t *mixer_handle; pa_alsa_ucm_mapping_context *context = &m->ucm_context; pa_alsa_ucm_device *dev; - uint32_t idx; + bool has_control; - PA_IDXSET_FOREACH(dev, context->ucm_devices, idx) { - bool has_control; + dev = context->ucm_device; + if (!dev->jack || !dev->jack->mixer_device_name) + return; - if (!dev->jack || !dev->jack->mixer_device_name) - continue; - - mixer_handle = pa_alsa_open_mixer_by_name(mixers, dev->jack->mixer_device_name, true); - if (!mixer_handle) { - pa_log_error("Unable to determine open mixer device '%s' for jack %s", dev->jack->mixer_device_name, dev->jack->name); - continue; - } - - has_control = pa_alsa_mixer_find_card(mixer_handle, &dev->jack->alsa_id, 0) != NULL; - pa_alsa_jack_set_has_control(dev->jack, has_control); - pa_log_info("UCM jack %s has_control=%d", dev->jack->name, dev->jack->has_control); + mixer_handle = pa_alsa_open_mixer_by_name(mixers, dev->jack->mixer_device_name, true); + if (!mixer_handle) { + pa_log_error("Unable to determine open mixer device '%s' for jack %s", dev->jack->mixer_device_name, dev->jack->name); + return; } + + has_control = pa_alsa_mixer_find_card(mixer_handle, &dev->jack->alsa_id, 0) != NULL; + pa_alsa_jack_set_has_control(dev->jack, has_control); + pa_log_info("UCM jack %s has_control=%d", dev->jack->name, dev->jack->has_control); } static void ucm_probe_profile_set(pa_alsa_ucm_config *ucm, pa_alsa_profile_set *ps) { @@ -2206,16 +2175,13 @@ void pa_alsa_ucm_mapping_context_free(pa_alsa_ucm_mapping_context *context) { pa_alsa_ucm_modifier *mod; uint32_t idx; - if (context->ucm_devices) { + dev = context->ucm_device; + if (dev) { /* clear ucm device pointer to mapping */ - PA_IDXSET_FOREACH(dev, context->ucm_devices, idx) { - if (context->direction == PA_DIRECTION_OUTPUT) - dev->playback_mapping = NULL; - else - dev->capture_mapping = NULL; - } - - pa_idxset_free(context->ucm_devices, NULL); + if (context->direction == PA_DIRECTION_OUTPUT) + dev->playback_mapping = NULL; + else + dev->capture_mapping = NULL; } if (context->ucm_modifiers) { diff --git a/src/modules/alsa/alsa-ucm.h b/src/modules/alsa/alsa-ucm.h index 735ec944a..8bab6fc04 100644 --- a/src/modules/alsa/alsa-ucm.h +++ b/src/modules/alsa/alsa-ucm.h @@ -262,7 +262,7 @@ struct pa_alsa_ucm_mapping_context { pa_alsa_ucm_config *ucm; pa_direction_t direction; - pa_idxset *ucm_devices; + pa_alsa_ucm_device *ucm_device; pa_idxset *ucm_modifiers; }; From 4821a0569ecbcb77d0cad5f02e040643af6a1a6c Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Tue, 16 Nov 2021 20:27:29 +0300 Subject: [PATCH 033/260] alsa-ucm: Make mapping UCM contexts have only one modifier After previous patches, we should be generating no combination ports, so we don't need to store multiple modifiers per mapping. Simplify the code based on this. Signed-off-by: Alper Nebi Yasak Part-of: --- src/modules/alsa/alsa-ucm.c | 37 +++++++++++++++---------------------- src/modules/alsa/alsa-ucm.h | 2 +- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c index a6eab6e4b..2fde322ba 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -1336,7 +1336,6 @@ void pa_alsa_ucm_add_ports( snd_pcm_t *pcm_handle, bool ignore_dB) { - uint32_t idx; char *merged_roles; const char *role_name = is_sink ? PA_ALSA_PROP_UCM_PLAYBACK_ROLES : PA_ALSA_PROP_UCM_CAPTURE_ROLES; pa_alsa_ucm_device *dev; @@ -1371,12 +1370,12 @@ void pa_alsa_ucm_add_ports( merged_roles = tmp; } - if (context->ucm_modifiers) - PA_IDXSET_FOREACH(mod, context->ucm_modifiers, idx) { - tmp = merge_roles(merged_roles, mod->media_role); - pa_xfree(merged_roles); - merged_roles = tmp; - } + mod = context->ucm_modifier; + if (mod) { + tmp = merge_roles(merged_roles, mod->media_role); + pa_xfree(merged_roles); + merged_roles = tmp; + } if (merged_roles) pa_proplist_sets(proplist, PA_PROP_DEVICE_INTENDED_ROLES, merged_roles); @@ -1496,7 +1495,7 @@ static void alsa_mapping_add_ucm_modifier(pa_alsa_mapping *m, pa_alsa_ucm_modifi const char *new_desc, *mod_name, *channel_str; uint32_t channels = 0; - pa_idxset_put(m->ucm_context.ucm_modifiers, modifier, NULL); + m->ucm_context.ucm_modifier = modifier; new_desc = pa_proplist_gets(modifier->proplist, PA_ALSA_PROP_UCM_DESCRIPTION); cur_desc = m->description; @@ -1620,8 +1619,7 @@ static int ucm_create_mapping_for_modifier( pa_log_info("UCM mapping: %s modifier %s", m->name, mod_name); - if (!m->ucm_context.ucm_device && !m->ucm_context.ucm_modifiers) { /* new mapping */ - m->ucm_context.ucm_modifiers = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); + if (!m->ucm_context.ucm_device && !m->ucm_context.ucm_modifier) { /* new mapping */ m->ucm_context.ucm = ucm; m->ucm_context.direction = is_sink ? PA_DIRECTION_OUTPUT : PA_DIRECTION_INPUT; @@ -1630,8 +1628,7 @@ static int ucm_create_mapping_for_modifier( m->direction = is_sink ? PA_ALSA_DIRECTION_OUTPUT : PA_ALSA_DIRECTION_INPUT; /* Modifier sinks should not be routed to by default */ m->priority = 0; - } else if (!m->ucm_context.ucm_modifiers) /* share pcm with device */ - m->ucm_context.ucm_modifiers = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); + } alsa_mapping_add_ucm_modifier(m, modifier); @@ -2173,7 +2170,6 @@ void pa_alsa_ucm_free(pa_alsa_ucm_config *ucm) { void pa_alsa_ucm_mapping_context_free(pa_alsa_ucm_mapping_context *context) { pa_alsa_ucm_device *dev; pa_alsa_ucm_modifier *mod; - uint32_t idx; dev = context->ucm_device; if (dev) { @@ -2184,15 +2180,12 @@ void pa_alsa_ucm_mapping_context_free(pa_alsa_ucm_mapping_context *context) { dev->capture_mapping = NULL; } - if (context->ucm_modifiers) { - PA_IDXSET_FOREACH(mod, context->ucm_modifiers, idx) { - if (context->direction == PA_DIRECTION_OUTPUT) - mod->playback_mapping = NULL; - else - mod->capture_mapping = NULL; - } - - pa_idxset_free(context->ucm_modifiers, NULL); + mod = context->ucm_modifier; + if (mod) { + if (context->direction == PA_DIRECTION_OUTPUT) + mod->playback_mapping = NULL; + else + mod->capture_mapping = NULL; } } diff --git a/src/modules/alsa/alsa-ucm.h b/src/modules/alsa/alsa-ucm.h index 8bab6fc04..0f596ef0c 100644 --- a/src/modules/alsa/alsa-ucm.h +++ b/src/modules/alsa/alsa-ucm.h @@ -263,7 +263,7 @@ struct pa_alsa_ucm_mapping_context { pa_direction_t direction; pa_alsa_ucm_device *ucm_device; - pa_idxset *ucm_modifiers; + pa_alsa_ucm_modifier *ucm_modifier; }; struct pa_alsa_ucm_profile_context { From e49da7bcd6f0a7788bee1aa1c30979f532605b9d Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Tue, 29 Jun 2021 17:56:27 +0300 Subject: [PATCH 034/260] alsa-ucm: Disable old devices when switching profiles of same verb While switching profiles, it was enough to switch UCM verbs since that disables all enabled UCM devices and every profile had a distinct verb. However, switching to the current verb does not disable any devices. To support multiple profiles for a verb we need to explicitly disable the old profile's devices, since they might be conflicting with the new profile's devices and will prevent them from being enabled. Compare both profiles' mappings, and disable the devices not in the new mappings. Signed-off-by: Alper Nebi Yasak Part-of: --- src/modules/alsa/alsa-ucm.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c index 2fde322ba..ec011d2d5 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -1389,6 +1389,8 @@ int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, pa_card *card, pa_alsa_prof int ret = 0; const char *verb_name, *profile_name; pa_alsa_ucm_verb *verb; + pa_alsa_mapping *map; + uint32_t idx; if (new_profile == old_profile) return 0; @@ -1403,12 +1405,26 @@ int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, pa_card *card, pa_alsa_prof verb_name = pa_proplist_gets(verb->proplist, PA_ALSA_PROP_UCM_NAME); } - /* change verb */ pa_log_info("Set profile to %s", profile_name); - pa_log_info("Set UCM verb to %s", verb_name); - if ((snd_use_case_set(ucm->ucm_mgr, "_verb", verb_name)) < 0) { - pa_log("Failed to set verb %s", verb_name); - ret = -1; + if (ucm->active_verb != verb) { + /* change verb */ + pa_log_info("Set UCM verb to %s", verb_name); + if ((snd_use_case_set(ucm->ucm_mgr, "_verb", verb_name)) < 0) { + pa_log("Failed to set verb %s", verb_name); + ret = -1; + } + + } else if (ucm->active_verb) { + /* Disable devices not in new profile */ + PA_IDXSET_FOREACH(map, old_profile->input_mappings, idx) + if (new_profile && !pa_idxset_contains(new_profile->input_mappings, map)) + if (ucm_device_disable(ucm, map->ucm_context.ucm_device) < 0) + ret = -1; + + PA_IDXSET_FOREACH(map, old_profile->output_mappings, idx) + if (new_profile && !pa_idxset_contains(new_profile->output_mappings, map)) + if (ucm_device_disable(ucm, map->ucm_context.ucm_device) < 0) + ret = -1; } ucm->active_verb = verb; From 5dd411190deb1957a7ed86f284e4f7a0c58bb877 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Tue, 29 Jun 2021 21:20:40 +0300 Subject: [PATCH 035/260] alsa-ucm: Create multiple profiles per verb for conflicting devices Right now we try to add all UCM devices of a verb to a single profile. But if some devices using different PCMs are configured as conflicting with one another, we will only be able to utilize one of them, chosen seemingly based on the order in the UCM config file. This is not a problem with conflicting devices sharing a PCM, as they are assigned to the same mapping and the ports mechanism only enables one of them to be active at a time. To utilize all devices in a UCM verb even when there are conflicting devices using different PCMs, calculate subsets of devices which can be simultaneously used and create a profile for each such set. Signed-off-by: Alper Nebi Yasak Part-of: --- src/modules/alsa/alsa-ucm.c | 122 +++++++++++++++++++++++++++++------- 1 file changed, 100 insertions(+), 22 deletions(-) diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c index ec011d2d5..ba9840451 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -1019,7 +1019,7 @@ fail: } } -PA_UNUSED static char *devset_name(pa_idxset *devices, const char *sep) { +static char *devset_name(pa_idxset *devices, const char *sep) { int i = 0; int num = pa_idxset_size(devices); pa_alsa_ucm_device *sorted[num], *dev; @@ -1086,7 +1086,7 @@ PA_UNUSED static char *devset_description(pa_idxset *devices, const char *sep) { /* If invert is true, uses the formula 1/p = 1/p1 + 1/p2 + ... 1/pn. * This way, the result will always be less than the individual components, * yet higher components will lead to higher result. */ -PA_UNUSED static unsigned devset_playback_priority(pa_idxset *devices, bool invert) { +static unsigned devset_playback_priority(pa_idxset *devices, bool invert) { pa_alsa_ucm_device *dev; uint32_t idx; double priority = 0; @@ -1104,7 +1104,7 @@ PA_UNUSED static unsigned devset_playback_priority(pa_idxset *devices, bool inve return (unsigned) priority; } -PA_UNUSED static unsigned devset_capture_priority(pa_idxset *devices, bool invert) { +static unsigned devset_capture_priority(pa_idxset *devices, bool invert) { pa_alsa_ucm_device *dev; uint32_t idx; double priority = 0; @@ -1260,7 +1260,7 @@ static bool devset_supports_device(pa_idxset *devices, pa_alsa_ucm_device *dev) * *state should be NULL. It's not safe to modify the devices argument * until iteration ends. The returned idxsets must be freed by the * caller. */ -PA_UNUSED static pa_idxset *iterate_device_subsets(pa_idxset *devices, void **state) { +static pa_idxset *iterate_device_subsets(pa_idxset *devices, void **state) { uint32_t idx; pa_alsa_ucm_device *dev; @@ -1298,6 +1298,33 @@ PA_UNUSED static pa_idxset *iterate_device_subsets(pa_idxset *devices, void **st return pa_idxset_copy(*state, NULL); } +/* This a wrapper around iterate_device_subsets() that only returns the + * biggest possible groups and not any of their subsets. */ +static pa_idxset *iterate_maximal_device_subsets(pa_idxset *devices, void **state) { + uint32_t idx; + pa_alsa_ucm_device *dev; + pa_idxset *subset; + + pa_assert(devices); + pa_assert(state); + + subset = iterate_device_subsets(devices, state); + if (!subset) + return subset; + + /* Skip this group if it's incomplete, by checking if we can add any + * other device. If we can, this iteration is a subset of another + * group that we already returned or eventually return. */ + PA_IDXSET_FOREACH(dev, devices, idx) { + if (!pa_idxset_contains(subset, dev) && devset_supports_device(subset, dev)) { + pa_idxset_free(subset, NULL); + return iterate_maximal_device_subsets(devices, state); + } + } + + return subset; +} + static char* merge_roles(const char *cur, const char *add) { char *r, *ret; const char *state = NULL; @@ -1786,13 +1813,16 @@ static int ucm_create_verb_profiles( const char *verb_name, const char *verb_desc) { - pa_idxset *mappings; + pa_idxset *verb_devices, *p_devices, *p_mappings; pa_alsa_ucm_device *dev; pa_alsa_ucm_modifier *mod; int i = 0; - int ret = 0; + int n_profiles = 0; const char *name, *sink, *source; - unsigned int verb_priority; + char *p_name, *p_desc, *tmp; + unsigned int verb_priority, p_priority; + uint32_t idx; + void *state = NULL; /* TODO: get profile priority from policy management */ verb_priority = verb->priority; @@ -1813,8 +1843,6 @@ static int ucm_create_verb_profiles( pa_xfree(verb_cmp); } - mappings = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); - PA_LLIST_FOREACH(dev, verb->devices) { pa_alsa_jack *jack; const char *jack_hw_mute; @@ -1826,11 +1854,6 @@ static int ucm_create_verb_profiles( ucm_create_mapping(ucm, ps, dev, verb_name, name, sink, source); - if (dev->playback_mapping) - pa_idxset_put(mappings, dev->playback_mapping, NULL); - if (dev->capture_mapping) - pa_idxset_put(mappings, dev->capture_mapping, NULL); - jack = ucm_get_jack(ucm, dev); if (jack) device_set_jack(dev, jack); @@ -1883,18 +1906,73 @@ static int ucm_create_verb_profiles( ucm_create_mapping_for_modifier(ucm, ps, mod, verb_name, name, sink, true); else if (source) ucm_create_mapping_for_modifier(ucm, ps, mod, verb_name, name, source, false); - - if (mod->playback_mapping) - pa_idxset_put(mappings, mod->playback_mapping, NULL); - if (mod->capture_mapping) - pa_idxset_put(mappings, mod->capture_mapping, NULL); } - ret = ucm_create_profile(ucm, ps, verb, mappings, verb_name, verb_desc, verb_priority); + verb_devices = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); + PA_LLIST_FOREACH(dev, verb->devices) + pa_idxset_put(verb_devices, dev, NULL); - pa_idxset_free(mappings, NULL); + while ((p_devices = iterate_maximal_device_subsets(verb_devices, &state))) { + p_mappings = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); - return ret; + /* Add the mappings that include our selected devices */ + PA_IDXSET_FOREACH(dev, p_devices, idx) { + if (dev->playback_mapping) + pa_idxset_put(p_mappings, dev->playback_mapping, NULL); + if (dev->capture_mapping) + pa_idxset_put(p_mappings, dev->capture_mapping, NULL); + } + + /* Add mappings only for the modifiers that can work with our + * device selection */ + PA_LLIST_FOREACH(mod, verb->modifiers) + if (pa_idxset_isempty(mod->supported_devices) || pa_idxset_issubset(mod->supported_devices, p_devices)) + if (pa_idxset_isdisjoint(mod->conflicting_devices, p_devices)) { + if (mod->playback_mapping) + pa_idxset_put(p_mappings, mod->playback_mapping, NULL); + if (mod->capture_mapping) + pa_idxset_put(p_mappings, mod->capture_mapping, NULL); + } + + /* If we'll have multiple profiles for this verb, their names + * must be unique. Use a list of chosen devices to disambiguate + * them. If the profile contains all devices of a verb, we'll + * generate only onle profile whose name should be the verb + * name. GUIs usually show the profile description instead of + * the name, add the device names to those as well. */ + tmp = devset_name(p_devices, ", "); + if (pa_idxset_equals(p_devices, verb_devices)) { + p_name = pa_xstrdup(verb_name); + p_desc = pa_xstrdup(verb_desc); + } else { + p_name = pa_sprintf_malloc("%s (%s)", verb_name, tmp); + p_desc = pa_sprintf_malloc("%s (%s)", verb_desc, tmp); + } + + /* Make sure profiles with higher-priority devices are + * prioritized. */ + p_priority = verb_priority + devset_playback_priority(p_devices, false) + devset_capture_priority(p_devices, false); + + if (ucm_create_profile(ucm, ps, verb, p_mappings, p_name, p_desc, p_priority) == 0) { + pa_log_debug("Created profile %s for UCM verb %s", p_name, verb_name); + n_profiles++; + } + + pa_xfree(tmp); + pa_xfree(p_name); + pa_xfree(p_desc); + pa_idxset_free(p_mappings, NULL); + pa_idxset_free(p_devices, NULL); + } + + pa_idxset_free(verb_devices, NULL); + + if (n_profiles == 0) { + pa_log("UCM verb %s created no profiles", verb_name); + return -1; + } + + return 0; } static void mapping_init_eld(pa_alsa_mapping *m, snd_pcm_t *pcm) From eb870fcba9f1d3d9e4d0823012ff04ac2bea00ca Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 29 Jun 2022 17:01:32 +0200 Subject: [PATCH 036/260] alsa-ucm: remove extra space from the device.intended_roles property Before: device.intended_roles = " voice" After: device.intended_roles = "voice" Signed-off-by: Jaroslav Kysela Part-of: --- src/modules/alsa/alsa-ucm.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c index ba9840451..e75756f53 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -730,7 +730,7 @@ static void add_media_role(pa_alsa_ucm_device *dev, const char *role_name, const } static char *modifier_name_to_role(const char *mod_name, bool *is_sink) { - char *sub = NULL, *tmp; + char *sub = NULL, *tmp, *pos; *is_sink = false; @@ -740,19 +740,24 @@ static char *modifier_name_to_role(const char *mod_name, bool *is_sink) { } else if (pa_startswith(mod_name, "Capture")) sub = pa_xstrdup(mod_name + 7); - if (!sub || !*sub) { + pos = sub; + while (pos && *pos == ' ') pos++; + + if (!pos || !*pos) { pa_xfree(sub); pa_log_warn("Can't match media roles for modifier %s", mod_name); return NULL; } - tmp = sub; + tmp = pos; do { *tmp = tolower(*tmp); } while (*(++tmp)); - return sub; + tmp = pa_xstrdup(pos); + pa_xfree(sub); + return tmp; } static void ucm_set_media_roles(pa_alsa_ucm_modifier *modifier, const char *mod_name) { From d1675df0cdd5565aa6823afefe0795816228d06e Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 29 Jun 2022 08:56:38 +0200 Subject: [PATCH 037/260] alsa-mixer: fix the re-attach code for the mixer control element The new helem must be tracked and old helem must be cleared to make the code work properly. Introduce the pointer to helem as the private value for melem and add the necessary code. Also, add a check for the duplicate mixer elements. The duplicate mixer element invokes the abort check in alsa-lib. Print a warning instead and handle the exit gracefully. Fixes: def8eb074 ("alsa-mixer: allow to re-attach the mixer control element") Signed-off-by: Jaroslav Kysela Part-of: --- src/modules/alsa/alsa-util.c | 50 ++++++++++++++++++++++++----- src/modules/alsa/module-alsa-card.c | 13 ++++++-- 2 files changed, 52 insertions(+), 11 deletions(-) diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c index 81dc77cc3..d33f3d1f7 100644 --- a/src/modules/alsa/alsa-util.c +++ b/src/modules/alsa/alsa-util.c @@ -1618,10 +1618,11 @@ static snd_mixer_elem_t *pa_alsa_mixer_find(snd_mixer_t *mixer, snd_mixer_elem_t *elem; for (elem = snd_mixer_first_elem(mixer); elem; elem = snd_mixer_elem_next(elem)) { - snd_hctl_elem_t *helem; + snd_hctl_elem_t **_helem, *helem; if (snd_mixer_elem_get_type(elem) != SND_MIXER_ELEM_PULSEAUDIO) continue; - helem = snd_mixer_elem_get_private(elem); + _helem = snd_mixer_elem_get_private(elem); + helem = *_helem; if (snd_hctl_elem_get_interface(helem) != iface) continue; if (!pa_streq(snd_hctl_elem_get_name(helem), name)) @@ -1649,16 +1650,26 @@ static int mixer_class_compare(const snd_mixer_elem_t *c1, const snd_mixer_elem_ return c1 == c2 ? 0 : (c1 > c2 ? 1 : -1); } +static void mixer_melem_free(snd_mixer_elem_t *elem) +{ + snd_hctl_elem_t **_helem; + _helem = snd_mixer_elem_get_private(elem); + pa_xfree(_helem); +} + static int mixer_class_event(snd_mixer_class_t *class, unsigned int mask, snd_hctl_elem_t *helem, snd_mixer_elem_t *melem) { int err; const char *name = snd_hctl_elem_get_name(helem); + snd_hctl_elem_t **_helem; /* NOTE: The remove event is defined as '~0U`. */ if (mask == SND_CTL_EVENT_MASK_REMOVE) { /* NOTE: Unless we remove the pointer to melem from the linked-list at * private_data of helem, an assertion will be hit in alsa-lib since * the list is not empty. */ + _helem = snd_mixer_elem_get_private(melem); + *_helem = NULL; snd_mixer_elem_detach(melem, helem); } else if (mask & SND_CTL_EVENT_MASK_ADD) { snd_ctl_elem_iface_t iface = snd_hctl_elem_get_interface(helem); @@ -1669,25 +1680,48 @@ static int mixer_class_event(snd_mixer_class_t *class, unsigned int mask, const int index = snd_hctl_elem_get_index(helem); const int device = snd_hctl_elem_get_device(helem); snd_mixer_elem_t *new_melem; - + bool found = true; + new_melem = pa_alsa_mixer_find(mixer, iface, name, index, device); if (!new_melem) { + _helem = pa_xmalloc(sizeof(snd_hctl_elem_t *)); + *_helem = helem; /* Put the hctl pointer as our private data - it will be useful for callbacks */ - if ((err = snd_mixer_elem_new(&new_melem, SND_MIXER_ELEM_PULSEAUDIO, 0, helem, NULL)) < 0) { + if ((err = snd_mixer_elem_new(&new_melem, SND_MIXER_ELEM_PULSEAUDIO, 0, _helem, mixer_melem_free)) < 0) { pa_log_warn("snd_mixer_elem_new failed: %s", pa_alsa_strerror(err)); return 0; } + found = false; + } else { + _helem = snd_mixer_elem_get_private(new_melem); + if (_helem) { + char *s1, *s2; + snd_ctl_elem_id_t *id1, *id2; + snd_ctl_elem_id_alloca(&id1); + snd_ctl_elem_id_alloca(&id2); + snd_hctl_elem_get_id(helem, id1); + snd_hctl_elem_get_id(*_helem, id2); + s1 = snd_ctl_ascii_elem_id_get(id1); + s2 = snd_ctl_ascii_elem_id_get(id2); + pa_log_warn("mixer_class_event - duplicate mixer controls: %s | %s", s1, s2); + free(s2); + free(s1); + return 0; + } + *_helem = helem; } if ((err = snd_mixer_elem_attach(new_melem, helem)) < 0) { pa_log_warn("snd_mixer_elem_attach failed: %s", pa_alsa_strerror(err)); - snd_mixer_elem_free(melem); + snd_mixer_elem_free(melem); return 0; } - if ((err = snd_mixer_elem_add(new_melem, class)) < 0) { - pa_log_warn("snd_mixer_elem_add failed: %s", pa_alsa_strerror(err)); - return 0; + if (!found) { + if ((err = snd_mixer_elem_add(new_melem, class)) < 0) { + pa_log_warn("snd_mixer_elem_add failed: %s", pa_alsa_strerror(err)); + return 0; + } } } } diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c index a69fb7acc..05c87c6bb 100644 --- a/src/modules/alsa/module-alsa-card.c +++ b/src/modules/alsa/module-alsa-card.c @@ -370,7 +370,7 @@ struct temp_port_avail { static int report_jack_state(snd_mixer_elem_t *melem, unsigned int mask) { struct userdata *u = snd_mixer_elem_get_callback_private(melem); - snd_hctl_elem_t *elem = snd_mixer_elem_get_private(melem); + snd_hctl_elem_t **_elem = snd_mixer_elem_get_private(melem), *elem; snd_ctl_elem_value_t *elem_value; bool plugged_in; void *state; @@ -380,6 +380,8 @@ static int report_jack_state(snd_mixer_elem_t *melem, unsigned int mask) { pa_available_t active_available = PA_AVAILABLE_UNKNOWN; pa_assert(u); + pa_assert(_elem); + elem = *_elem; /* Changing the jack state may cause a port change, and a port change will * make the sink or source change the mixer settings. If there are multiple @@ -562,13 +564,18 @@ static pa_device_port* find_port_with_eld_device(struct userdata *u, int device) static int hdmi_eld_changed(snd_mixer_elem_t *melem, unsigned int mask) { struct userdata *u = snd_mixer_elem_get_callback_private(melem); - snd_hctl_elem_t *elem = snd_mixer_elem_get_private(melem); - int device = snd_hctl_elem_get_device(elem); + snd_hctl_elem_t **_elem = snd_mixer_elem_get_private(melem), *elem; + int device; const char *old_monitor_name; pa_device_port *p; pa_hdmi_eld eld; bool changed = false; + pa_assert(u); + pa_assert(_elem); + elem = *_elem; + device = snd_hctl_elem_get_device(elem); + if (mask == SND_CTL_EVENT_MASK_REMOVE) return 0; From 81a051089f3a5890972006256737776d22de9883 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 29 Jun 2022 11:23:20 +0200 Subject: [PATCH 038/260] alsa-mixer: extend pa_alsa_mixer_find with the subdevice check The full identifier check must be executed for the new melem creation, otherwise the duplicate control element code check is reached. Example (using the snd-aloop driver): numid=56,iface=PCM,name='PCM Notify',device=1,subdevice=1 numid=62,iface=PCM,name='PCM Notify',device=1,subdevice=2 Signed-off-by: Jaroslav Kysela Part-of: --- src/modules/alsa/alsa-util.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c index d33f3d1f7..9d464a8ac 100644 --- a/src/modules/alsa/alsa-util.c +++ b/src/modules/alsa/alsa-util.c @@ -1614,7 +1614,8 @@ static snd_mixer_elem_t *pa_alsa_mixer_find(snd_mixer_t *mixer, snd_ctl_elem_iface_t iface, const char *name, unsigned int index, - unsigned int device) { + unsigned int device, + unsigned int subdevice) { snd_mixer_elem_t *elem; for (elem = snd_mixer_first_elem(mixer); elem; elem = snd_mixer_elem_next(elem)) { @@ -1631,17 +1632,19 @@ static snd_mixer_elem_t *pa_alsa_mixer_find(snd_mixer_t *mixer, continue; if (snd_hctl_elem_get_device(helem) != device) continue; + if (snd_hctl_elem_get_subdevice(helem) != subdevice) + continue; return elem; } return NULL; } snd_mixer_elem_t *pa_alsa_mixer_find_card(snd_mixer_t *mixer, struct pa_alsa_mixer_id *alsa_id, unsigned int device) { - return pa_alsa_mixer_find(mixer, SND_CTL_ELEM_IFACE_CARD, alsa_id->name, alsa_id->index, device); + return pa_alsa_mixer_find(mixer, SND_CTL_ELEM_IFACE_CARD, alsa_id->name, alsa_id->index, device, 0); } snd_mixer_elem_t *pa_alsa_mixer_find_pcm(snd_mixer_t *mixer, const char *name, unsigned int device) { - return pa_alsa_mixer_find(mixer, SND_CTL_ELEM_IFACE_PCM, name, 0, device); + return pa_alsa_mixer_find(mixer, SND_CTL_ELEM_IFACE_PCM, name, 0, device, 0); } static int mixer_class_compare(const snd_mixer_elem_t *c1, const snd_mixer_elem_t *c2) @@ -1679,10 +1682,11 @@ static int mixer_class_event(snd_mixer_class_t *class, unsigned int mask, const char *name = snd_hctl_elem_get_name(helem); const int index = snd_hctl_elem_get_index(helem); const int device = snd_hctl_elem_get_device(helem); + const int subdevice = snd_hctl_elem_get_subdevice(helem); snd_mixer_elem_t *new_melem; bool found = true; - new_melem = pa_alsa_mixer_find(mixer, iface, name, index, device); + new_melem = pa_alsa_mixer_find(mixer, iface, name, index, device, subdevice); if (!new_melem) { _helem = pa_xmalloc(sizeof(snd_hctl_elem_t *)); *_helem = helem; From fd81201f283ffa4abc40e418198ce6a97f4c1c97 Mon Sep 17 00:00:00 2001 From: Nicolas Cavallari Date: Fri, 1 Jul 2022 14:03:44 +0200 Subject: [PATCH 039/260] build-sys: Fix atomic support detection Attempting to use atomics operations on an architecture that does not support them generally results in a link error: ld: /tmp/ccjYcMPP.o: in function `func': testfile.c:(.text+0x1c): undefined reference to `__sync_bool_compare_and_swap_4' The current build system uses cc.compiles() to check if atomic ops are supported, but cc.compiles() does not attempt to link, so the test fails to enable libatomics_opts. Fix this by using cc.links() instead of cc.compiles(). Signed-off-by: Nicolas Cavallari Part-of: --- meson.build | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/meson.build b/meson.build index c6db7e670..c5135330f 100644 --- a/meson.build +++ b/meson.build @@ -498,22 +498,24 @@ endif need_libatomic_ops = false -atomictest = '''void func() { +atomictest = '''int main() { volatile int atomic = 2; __sync_bool_compare_and_swap (&atomic, 2, 3); + return 0; } ''' -if cc.compiles(atomictest) +if cc.links(atomictest) cdata.set('HAVE_ATOMIC_BUILTINS', 1) - newatomictest = '''void func() { + newatomictest = '''int main() { int c = 0; __atomic_store_n(&c, 4, __ATOMIC_SEQ_CST); + return 0; } ''' - if(cc.compiles(newatomictest)) + if(cc.links(newatomictest)) cdata.set('HAVE_ATOMIC_BUILTINS_MEMORY_MODEL', 1) endif From baa3d24b760fe48d25d379b972728ea3ffa5492d Mon Sep 17 00:00:00 2001 From: Nicolas Cavallari Date: Mon, 4 Jul 2022 13:49:34 +0200 Subject: [PATCH 040/260] build-sys: Add missing libatomic_ops dependencies Add libatomic_ops dependencies to libraries/modules that showed a failure on an arch that does not have native atomic operations support. Not all optional dependencies were tested, so it is possible that some optional modules are still missing libatomic_ops dependencies. Signed-off-by: Nicolas Cavallari Part-of: --- src/meson.build | 2 +- src/modules/meson.build | 6 +++--- src/pulse/meson.build | 2 +- src/pulsecore/meson.build | 10 +++++----- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/meson.build b/src/meson.build index 96dcec354..9efb561d8 100644 --- a/src/meson.build +++ b/src/meson.build @@ -205,7 +205,7 @@ else libm_dep, thread_dep, dl_dep, shm_dep, iconv_dep, sndfile_dep, dbus_dep, x11_dep, libsystemd_dep, glib_dep.partial_dependency(compile_args: true), gtk_dep.partial_dependency(compile_args: true), asyncns_dep, libintl_dep, - platform_dep, platform_socket_dep, execinfo_dep, + platform_dep, platform_socket_dep, execinfo_dep, libatomic_ops_dep, ], implicit_include_directories : false) diff --git a/src/modules/meson.build b/src/modules/meson.build index 1d8004300..1e12569dc 100644 --- a/src/modules/meson.build +++ b/src/modules/meson.build @@ -14,7 +14,7 @@ all_modules = [ [ 'module-cli-protocol-tcp', 'module-protocol-stub.c', [], ['-DUSE_PROTOCOL_CLI', '-DUSE_TCP_SOCKETS'], [], libprotocol_cli ], [ 'module-cli-protocol-unix', 'module-protocol-stub.c', [], ['-DUSE_PROTOCOL_CLI', '-DUSE_UNIX_SOCKETS'], [], libprotocol_cli ], [ 'module-combine', 'module-combine.c' ], - [ 'module-combine-sink', 'module-combine-sink.c' ], + [ 'module-combine-sink', 'module-combine-sink.c', [], [], [libatomic_ops_dep] ], # [ 'module-coreaudio-detect', 'macosx/module-coreaudio-detect.c' ], # [ 'module-coreaudio-device', 'macosx/module-coreaudio-device.c' ], [ 'module-default-device-restore', 'module-default-device-restore.c', [], [], [], libprotocol_native ], @@ -73,7 +73,7 @@ endif if host_machine.system() != 'windows' all_modules += [ - [ 'module-rtp-recv', 'rtp/module-rtp-recv.c', [], [], [], librtp ], + [ 'module-rtp-recv', 'rtp/module-rtp-recv.c', [], [], [libatomic_ops_dep], librtp ], [ 'module-rtp-send', 'rtp/module-rtp-send.c' , [], [], [], librtp ], ] endif @@ -243,7 +243,7 @@ module_echo_cancel_sources = [ ] module_echo_cancel_orc_sources = [] module_echo_cancel_flags = [] -module_echo_cancel_deps = [] +module_echo_cancel_deps = [libatomic_ops_dep] module_echo_cancel_libs = [] if get_option('adrian-aec') diff --git a/src/pulse/meson.build b/src/pulse/meson.build index c2128e087..1b82c807c 100644 --- a/src/pulse/meson.build +++ b/src/pulse/meson.build @@ -85,7 +85,7 @@ libpulse = shared_library('pulse', link_args : [nodelete_link_args, versioning_link_args], install : true, install_rpath : privlibdir, - dependencies : [libm_dep, thread_dep, libpulsecommon_dep, dbus_dep, dl_dep, iconv_dep, libintl_dep, platform_dep, platform_socket_dep], + dependencies : [libm_dep, thread_dep, libpulsecommon_dep, dbus_dep, dl_dep, iconv_dep, libintl_dep, platform_dep, platform_socket_dep, libatomic_ops_dep], implicit_include_directories : false) libpulse_dep = declare_dependency(link_with: libpulse) diff --git a/src/pulsecore/meson.build b/src/pulsecore/meson.build index b30264b3a..b37fec499 100644 --- a/src/pulsecore/meson.build +++ b/src/pulsecore/meson.build @@ -251,7 +251,7 @@ libcli = shared_library('cli', c_args : [pa_c_args, server_c_args, database_c_args], link_args : [nodelete_link_args], include_directories : [configinc, topinc], - dependencies : [libpulse_dep, libpulsecommon_dep, libpulsecore_dep], + dependencies : [libpulse_dep, libpulsecommon_dep, libpulsecore_dep, libatomic_ops_dep], install : true, install_rpath : privlibdir, install_dir : modlibexecdir, @@ -268,7 +268,7 @@ libprotocol_cli = shared_library('protocol-cli', c_args : [pa_c_args, server_c_args, database_c_args], link_args : [nodelete_link_args], include_directories : [configinc, topinc], - dependencies : [libpulse_dep, libpulsecommon_dep, libpulsecore_dep, libcli_dep], + dependencies : [libpulse_dep, libpulsecommon_dep, libpulsecore_dep, libcli_dep, libatomic_ops_dep], install : true, install_rpath : rpath_dirs, install_dir : modlibexecdir, @@ -280,7 +280,7 @@ libprotocol_http = shared_library('protocol-http', c_args : [pa_c_args, server_c_args, database_c_args], link_args : [nodelete_link_args], include_directories : [configinc, topinc], - dependencies : [libpulse_dep, libpulsecommon_dep, libpulsecore_dep], + dependencies : [libpulse_dep, libpulsecommon_dep, libpulsecore_dep, libatomic_ops_dep], install : true, install_rpath : privlibdir, install_dir : modlibexecdir, @@ -292,7 +292,7 @@ libprotocol_native = shared_library('protocol-native', c_args : [pa_c_args, server_c_args, database_c_args], link_args : [nodelete_link_args], include_directories : [configinc, topinc], - dependencies : [libpulse_dep, libpulsecommon_dep, libpulsecore_dep, dbus_dep], + dependencies : [libpulse_dep, libpulsecommon_dep, libpulsecore_dep, dbus_dep, libatomic_ops_dep], install : true, install_rpath : privlibdir, install_dir : modlibexecdir, @@ -304,7 +304,7 @@ libprotocol_simple = shared_library('protocol-simple', c_args : [pa_c_args, server_c_args, database_c_args], link_args : [nodelete_link_args], include_directories : [configinc, topinc], - dependencies : [libpulse_dep, libpulsecommon_dep, libpulsecore_dep], + dependencies : [libpulse_dep, libpulsecommon_dep, libpulsecore_dep, libatomic_ops_dep], install : true, install_rpath : privlibdir, install_dir : modlibexecdir, From 07a9fcefbab049d66cb174ca2c9b91fecc444c5b Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Sat, 9 Jul 2022 09:12:38 +0300 Subject: [PATCH 041/260] build-sys: meson: Move qpaeq to daemon build Equalizer control requires server modules only available when daemon is built. Move qpaeq script to be installed together with daemon. Part-of: --- src/utils/meson.build | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/utils/meson.build b/src/utils/meson.build index 28e1fc10a..8496d0bc5 100644 --- a/src/utils/meson.build +++ b/src/utils/meson.build @@ -72,6 +72,10 @@ if get_option('daemon') c_args : pa_c_args, ) endif + + if dbus_dep.found() and fftw_dep.found() + install_data('qpaeq', install_dir : bindir) + endif endif if get_option('client') @@ -117,9 +121,5 @@ if get_option('client') ) endif - if dbus_dep.found() and fftw_dep.found() - install_data('qpaeq', install_dir : bindir) - endif - install_data('pa-info', install_dir : bindir) endif From 0b4af61ee7ae0de433d4cbd1c2797fb5d5e08424 Mon Sep 17 00:00:00 2001 From: Peter Meerwald-Stadler Date: Tue, 14 Jun 2022 00:15:34 +0200 Subject: [PATCH 042/260] module-combine-sink: Use fabs() instead of abs() for double Part-of: --- src/modules/module-combine-sink.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/module-combine-sink.c b/src/modules/module-combine-sink.c index 9892bbbaf..571b851fb 100644 --- a/src/modules/module-combine-sink.c +++ b/src/modules/module-combine-sink.c @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -239,7 +240,7 @@ static uint32_t rate_controller( /* Choose the rate that is nearer to base_rate */ new_rate = new_rate_2; - if (abs(new_rate_1 - base_rate) < abs(new_rate_2 - base_rate)) + if (fabs(new_rate_1 - base_rate) < fabs(new_rate_2 - base_rate)) new_rate = new_rate_1; return (uint32_t)(new_rate + 0.5); From 63d0db832ce6b5a9c4bc2e8dc6185d18329698c1 Mon Sep 17 00:00:00 2001 From: Peter Meerwald-Stadler Date: Tue, 14 Jun 2022 00:16:09 +0200 Subject: [PATCH 043/260] module-combine-sink: Fix indentation Part-of: --- src/modules/module-combine-sink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/module-combine-sink.c b/src/modules/module-combine-sink.c index 571b851fb..f98f4820b 100644 --- a/src/modules/module-combine-sink.c +++ b/src/modules/module-combine-sink.c @@ -179,7 +179,7 @@ struct userdata { #ifdef USE_SMOOTHER_2 pa_smoother_2 *smoother; #else - pa_smoother *smoother; + pa_smoother *smoother; #endif uint64_t counter; From f71eafe4d956d43aa6637fe905184cfacd5a3bce Mon Sep 17 00:00:00 2001 From: Peter Meerwald-Stadler Date: Tue, 14 Jun 2022 00:17:09 +0200 Subject: [PATCH 044/260] module-tunnel: Fix typos Part-of: --- src/modules/module-tunnel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 33cff1e82..61f427bd3 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -1000,7 +1000,7 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, uint else delay -= (int64_t) pa_bytes_to_usec((uint64_t) (read_index-write_index), ss); - /* Our measurements are already out of date, hence correct by the * + /* Our measurements are already out of date, hence correct by the * transport latency */ #ifdef TUNNEL_SINK delay -= (int64_t) u->transport_usec; @@ -1008,7 +1008,7 @@ static void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, uint delay += (int64_t) u->transport_usec; #endif - /* Now correct by what we have have written since we requested the update. This + /* Now correct by what we have written since we requested the update. This * is not necessary for the source, because if data is received between request * and reply, it was already posted before we requested the source latency. */ #ifdef TUNNEL_SINK From e8509ea85c5c35a460a5d5a68b57ce3eaef9bef9 Mon Sep 17 00:00:00 2001 From: Peter Meerwald-Stadler Date: Tue, 14 Jun 2022 00:17:53 +0200 Subject: [PATCH 045/260] volume: Fix typo Part-of: --- src/pulse/volume.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulse/volume.h b/src/pulse/volume.h index fe44b0bbc..d9b0986bd 100644 --- a/src/pulse/volume.h +++ b/src/pulse/volume.h @@ -49,7 +49,7 @@ * sink input. In fact, it depends on the server configuration. With flat * volumes enabled, it means the maximum volume that the sound hardware is * capable of, which is usually so high that you absolutely must not set sink - * input volume to 100% unless the the user explicitly requests that (note that + * input volume to 100% unless the user explicitly requests that (note that * usually you shouldn't set the volume anyway if the user doesn't explicitly * request it, instead, let PulseAudio decide the volume for the sink input). * With flat volumes disabled the sink input volume is relative to the sink From 9360dce76d9b0e85457fe004b17fd1333a16c673 Mon Sep 17 00:00:00 2001 From: Peter Meerwald-Stadler Date: Tue, 14 Jun 2022 00:19:16 +0200 Subject: [PATCH 046/260] raop-client: Fix typo Part-of: --- src/modules/raop/raop-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/raop/raop-client.c b/src/modules/raop/raop-client.c index 3bd749075..2dc3145f2 100644 --- a/src/modules/raop/raop-client.c +++ b/src/modules/raop/raop-client.c @@ -480,7 +480,7 @@ static ssize_t send_udp_audio_packet(pa_raop_client *c, pa_memchunk *block, size } pa_memblock_release(packet->memblock); - /* It is meaningless to preseve the partial data */ + /* It is meaningless to preserve the partial data */ block->index += block->length; block->length = 0; From 0f6234e320e7c2649cffd75d50a09fec888074ca Mon Sep 17 00:00:00 2001 From: Gogo Gogsi Date: Fri, 17 Jun 2022 08:36:52 +0000 Subject: [PATCH 047/260] Translated using Weblate (Croatian) Currently translated at 100.0% (572 of 572 strings) Translation: pulseaudio/pulseaudio Translate-URL: https://translate.fedoraproject.org/projects/pulseaudio/pulseaudio/hr/ Part-of: --- po/hr.po | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/po/hr.po b/po/hr.po index 7401e1a36..d25d8d8ca 100644 --- a/po/hr.po +++ b/po/hr.po @@ -1162,6 +1162,8 @@ msgstr "" #: src/modules/module-equalizer-sink.c:1097 #: src/modules/module-equalizer-sink.c:1220 +#: src/modules/module-equalizer-sink.c:1094 +#: src/modules/module-equalizer-sink.c:1217 #, c-format msgid "FFT based equalizer on %s" msgstr "FFT temeljen ekvalizator na %s" @@ -1229,12 +1231,16 @@ msgstr "Zvuk na @NAZIVRAČUNALA@" #. TODO: old tunnel put here the remote source_name into stream name e.g. 'Null Output for lynxis@lazus' #: src/modules/module-tunnel-sink-new.c:370 #: src/modules/module-tunnel-source-new.c:354 +#: src/modules/module-tunnel-sink-new.c:356 +#: src/modules/module-tunnel-source-new.c:342 #, c-format msgid "Tunnel for %s@%s" msgstr "Tunel za %s@%s" #: src/modules/module-tunnel-sink-new.c:715 #: src/modules/module-tunnel-source-new.c:684 +#: src/modules/module-tunnel-sink-new.c:697 +#: src/modules/module-tunnel-source-new.c:668 #, c-format msgid "Tunnel to %s/%s" msgstr "Tunel do %s/%s" @@ -1583,11 +1589,11 @@ msgstr "" msgid "Invalid log target." msgstr "Neispravno odredište zapisa." -#: src/pulsecore/sink.c:3609 +#: src/pulsecore/sink.c:3609 src/pulsecore/sink.c:3600 msgid "Built-in Audio" msgstr "Ugrađeni zvuk" -#: src/pulsecore/sink.c:3614 +#: src/pulsecore/sink.c:3614 src/pulsecore/sink.c:3605 msgid "Modem" msgstr "Modem" @@ -1904,7 +1910,7 @@ msgid "pa_stream_update_timing_info() failed: %s" msgstr "pa_stream_update_timing_info() neuspjelo: %s" #: src/utils/pacat.c:676 -#, fuzzy, c-format +#, c-format msgid "" "%s [options]\n" "%s\n" @@ -1985,7 +1991,9 @@ msgstr "" " -s, --server=POSLUŽITELJ Naziv poslužitelja za " "povezivanje\n" " -d, --device=UREĐAJ Naziv slivnika/izvora za " -"povezivanje\n" +"povezivanje. Posebni nazivi @DEFAULT_SINK@, @DEFAULT_SOURCE@ i " +"@DEFAULT_MONITOR@ mogu se koristiti za određivanje zadanog slivnika, izvora " +"i nadgledanja.\n" " -n, --client-name=NAZIV Naziv klijenta na poslužitelju\n" " --stream-name=NAZIV Naziv strujanja na poslužitelju\n" " --volume=GLASNOĆA ZVUKA Određuje početnu (linearnu) " @@ -1994,7 +2002,7 @@ msgstr "" " --format=FORMAT UZORKA Vrsta uzorka, pogledajte\n" " https://www.freedesktop.org/wiki/" "Software/PulseAudio/Documentation/User/SupportedAudioFormats/\n" -" za moguće vrijenosti (zadano je " +" za moguće vrijednosti (zadano je " "s16ne)\n" " --channels=KANALI Broj kanala, 1 za mono, 2 za stereo\n" " (zadano 2)\n" @@ -2002,14 +2010,14 @@ msgstr "" "umjesto zadanog\n" " --fix-format Uzima uzorak formata iz slivnika/" "izvora s kojim\n" -" je tok povezan.\n" +" je strujanje povezano.\n" " --fix-rate Uzima frekvenciju iz slivnika/izvora " "s kojim\n" -" je tok povezan.\n" +" je strujanje povezano.\n" " --fix-channels Uzima broj kanala i mapiranje " "kanala\n" -" iz slivnika/izvora s kojim je tok " -"povezan.\n" +" iz slivnika/izvora s kojim je " +"strujanje povezano.\n" " --no-remix Ne smanjuj ili pojačavaj kanale.\n" " --no-remap Mapiraj kanale prema sadržaju " "umjesto nazivu.\n" @@ -2021,8 +2029,8 @@ msgstr "" "msek.\n" " --process-time-msec=MSEK Zahtijevaj određeno vrijeme procesa " "po zahtjevu u msek.\n" -" --property=VLASNIŠTVO=VRIJEDNOST Postavi određeno vlasništvo " -"za određenu vrijednost.\n" +" --property=SVOJSTVO=VRIJEDNOST Postavi određeno svojstvo za " +"određenu vrijednost.\n" " --raw Snimaj/Reproduciraj osnovne PCM " "podatke.\n" " --passthrough Prolaz podataka.\n" From 932b72f4174dc4d719c7f1ad627a43a0491c79b6 Mon Sep 17 00:00:00 2001 From: Temuri Doghonadze Date: Sat, 18 Jun 2022 17:38:26 +0000 Subject: [PATCH 048/260] Translated using Weblate (Georgian) Currently translated at 29.8% (171 of 572 strings) Translation: pulseaudio/pulseaudio Translate-URL: https://translate.fedoraproject.org/projects/pulseaudio/pulseaudio/ka/ Part-of: --- po/ka.po | 350 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 176 insertions(+), 174 deletions(-) diff --git a/po/ka.po b/po/ka.po index d9a89546f..36cc278ba 100644 --- a/po/ka.po +++ b/po/ka.po @@ -9,14 +9,16 @@ msgstr "" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" "POT-Creation-Date: 2022-06-18 09:49+0300\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: Automatically generated\n" -"Language-Team: none\n" +"PO-Revision-Date: 2022-06-19 18:52+0000\n" +"Last-Translator: Temuri Doghonadze \n" +"Language-Team: Georgian \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: Weblate 4.13\n" #: src/daemon/cmdline.c:113 #, c-format @@ -244,32 +246,32 @@ msgstr "" #: src/daemon/dumpmodules.c:57 #, c-format msgid "Name: %s\n" -msgstr "" +msgstr "სახელი: %s\n" #: src/daemon/dumpmodules.c:60 #, c-format msgid "No module information available\n" -msgstr "" +msgstr "ინფორმაცია მოდულზე ხელმიუწვდომელია.\n" #: src/daemon/dumpmodules.c:63 #, c-format msgid "Version: %s\n" -msgstr "" +msgstr "ვერსია: %s\n" #: src/daemon/dumpmodules.c:65 #, c-format msgid "Description: %s\n" -msgstr "" +msgstr "აღწერა: %s\n" #: src/daemon/dumpmodules.c:67 #, c-format msgid "Author: %s\n" -msgstr "" +msgstr "ავტორი: %s\n" #: src/daemon/dumpmodules.c:69 #, c-format msgid "Usage: %s\n" -msgstr "" +msgstr "გამოყენება: %s\n" #: src/daemon/dumpmodules.c:70 #, c-format @@ -284,7 +286,7 @@ msgstr "" #: src/daemon/dumpmodules.c:76 #, c-format msgid "Path: %s\n" -msgstr "" +msgstr "ბილიკი: %s\n" #: src/daemon/ltdl-bind-now.c:75 #, c-format @@ -326,7 +328,7 @@ msgstr "" #: src/daemon/main.c:287 src/daemon/main.c:292 #, c-format msgid "Failed to create '%s': %s" -msgstr "" +msgstr "შეცდომა %s-ის გახსნისას: %s" #: src/daemon/main.c:299 #, c-format @@ -410,17 +412,17 @@ msgstr "" #: src/daemon/main.c:928 src/daemon/main.c:999 #, c-format msgid "pipe() failed: %s" -msgstr "" +msgstr "pipe() -ის შეცდომა: %s" #: src/daemon/main.c:933 src/daemon/main.c:1004 #, c-format msgid "fork() failed: %s" -msgstr "" +msgstr "fork() -ის შეცდომა: %s" #: src/daemon/main.c:948 src/daemon/main.c:1019 src/utils/pacat.c:562 #, c-format msgid "read() failed: %s" -msgstr "" +msgstr "read() -ის შეცდომა: %s" #: src/daemon/main.c:954 msgid "Daemon startup failed." @@ -429,7 +431,7 @@ msgstr "" #: src/daemon/main.c:987 #, c-format msgid "setsid() failed: %s" -msgstr "" +msgstr "setsid() -ის შეცდომა: %s" #: src/daemon/main.c:1119 msgid "Failed to get machine ID" @@ -446,11 +448,11 @@ msgstr "" #: src/daemon/main.c:1161 msgid "pa_pid_file_create() failed." -msgstr "" +msgstr "pa_pid_file_create() -ის შეცდომა." #: src/daemon/main.c:1193 msgid "pa_core_new() failed." -msgstr "" +msgstr "pa_core_new() -ის შეცდომა." #: src/daemon/main.c:1268 msgid "command line arguments" @@ -477,7 +479,7 @@ msgstr "" #: src/modules/alsa/alsa-mixer.c:2708 msgid "Input" -msgstr "" +msgstr "შეყვანა" #: src/modules/alsa/alsa-mixer.c:2709 msgid "Docking Station Input" @@ -498,7 +500,7 @@ msgstr "" #: src/modules/alsa/alsa-mixer.c:2713 src/modules/alsa/alsa-mixer.c:2797 #: src/modules/bluetooth/module-bluez5-device.c:1956 msgid "Microphone" -msgstr "" +msgstr "მიკროფონი" #: src/modules/alsa/alsa-mixer.c:2714 src/modules/alsa/alsa-mixer.c:2798 msgid "Front Microphone" @@ -519,12 +521,12 @@ msgstr "" #: src/modules/alsa/alsa-mixer.c:2718 src/modules/alsa/alsa-mixer.c:2804 #: src/utils/pactl.c:343 msgid "Radio" -msgstr "" +msgstr "რადიო" #: src/modules/alsa/alsa-mixer.c:2719 src/modules/alsa/alsa-mixer.c:2805 #: src/utils/pactl.c:344 msgid "Video" -msgstr "" +msgstr "ვიდეო" #: src/modules/alsa/alsa-mixer.c:2720 msgid "Automatic Gain Control" @@ -552,7 +554,7 @@ msgstr "" #: src/modules/alsa/alsa-mixer.c:2726 msgid "Bass Boost" -msgstr "" +msgstr "Bass-ის გაძლიერება" #: src/modules/alsa/alsa-mixer.c:2727 msgid "No Bass Boost" @@ -561,12 +563,12 @@ msgstr "" #: src/modules/alsa/alsa-mixer.c:2728 #: src/modules/bluetooth/module-bluez5-device.c:1964 src/utils/pactl.c:333 msgid "Speaker" -msgstr "" +msgstr "დინამიკი" #: src/modules/alsa/alsa-mixer.c:2729 src/modules/alsa/alsa-mixer.c:2807 #: src/utils/pactl.c:334 msgid "Headphones" -msgstr "" +msgstr "ყურსაცვამები" #: src/modules/alsa/alsa-mixer.c:2796 msgid "Analog Input" @@ -602,7 +604,7 @@ msgstr "" #: src/modules/alsa/alsa-mixer.c:2812 msgid "Speakers" -msgstr "" +msgstr "დინამიკები" #: src/modules/alsa/alsa-mixer.c:2813 msgid "HDMI / DisplayPort" @@ -665,16 +667,16 @@ msgstr "" #: src/modules/alsa/alsa-mixer.c:4567 src/pulse/channelmap.c:103 #: src/pulse/channelmap.c:770 msgid "Mono" -msgstr "" +msgstr "მონო" #: src/modules/alsa/alsa-mixer.c:4568 src/pulse/channelmap.c:774 msgid "Stereo" -msgstr "" +msgstr "სტერეო" #: src/modules/alsa/alsa-mixer.c:4576 src/modules/alsa/alsa-mixer.c:4734 #: src/modules/bluetooth/module-bluez5-device.c:1944 src/utils/pactl.c:337 msgid "Headset" -msgstr "" +msgstr "ყურსაცვამები & მიკროფონი" #: src/modules/alsa/alsa-mixer.c:4577 src/modules/alsa/alsa-mixer.c:4735 msgid "Speakerphone" @@ -754,11 +756,11 @@ msgstr "" #: src/modules/alsa/alsa-mixer.c:4597 msgid "Chat" -msgstr "" +msgstr "ჩატი" #: src/modules/alsa/alsa-mixer.c:4598 msgid "Game" -msgstr "" +msgstr "თამაში" #: src/modules/alsa/alsa-mixer.c:4732 msgid "Analog Mono Duplex" @@ -787,7 +789,7 @@ msgstr "" #: src/modules/alsa/alsa-mixer.c:4740 src/modules/alsa/module-alsa-card.c:197 #: src/modules/bluetooth/module-bluez5-device.c:2263 msgid "Off" -msgstr "" +msgstr "გამორთული" #: src/modules/alsa/alsa-mixer.c:4840 #, c-format @@ -896,7 +898,7 @@ msgstr "" #: src/modules/bluetooth/module-bluez5-device.c:1977 src/utils/pactl.c:347 msgid "Portable" -msgstr "" +msgstr "გადატანადი" #: src/modules/bluetooth/module-bluez5-device.c:1983 src/utils/pactl.c:349 msgid "Car" @@ -904,11 +906,11 @@ msgstr "" #: src/modules/bluetooth/module-bluez5-device.c:1989 src/utils/pactl.c:350 msgid "HiFi" -msgstr "" +msgstr "HiFi" #: src/modules/bluetooth/module-bluez5-device.c:1995 src/utils/pactl.c:351 msgid "Phone" -msgstr "" +msgstr "ტელეფონი" #: src/modules/bluetooth/module-bluez5-device.c:2042 msgid "High Fidelity Playback (A2DP Sink)" @@ -951,7 +953,7 @@ msgstr "" #. add on profile #: src/modules/macosx/module-coreaudio-device.c:825 msgid "On" -msgstr "" +msgstr "ჩართული" #: src/modules/module-allow-passthrough.c:71 #: src/modules/module-always-sink.c:80 @@ -1028,7 +1030,7 @@ msgstr "" #: src/modules/module-rygel-media-server.c:545 #: src/modules/module-rygel-media-server.c:904 msgid "Input Devices" -msgstr "" +msgstr "შემომტანი მოწყობილობები" #: src/modules/module-rygel-media-server.c:1061 msgid "Audio on @HOSTNAME@" @@ -1073,214 +1075,214 @@ msgstr "" #: src/modules/reserve-wrap.c:149 msgid "PulseAudio Sound Server" -msgstr "" +msgstr "PulseAudio Sound Server" #: src/pulse/channelmap.c:105 msgid "Front Center" -msgstr "" +msgstr "წინა ცენტრი" #: src/pulse/channelmap.c:106 msgid "Front Left" -msgstr "" +msgstr "წინა მარცხენა" #: src/pulse/channelmap.c:107 msgid "Front Right" -msgstr "" +msgstr "წინა მარჯვენა" #: src/pulse/channelmap.c:109 msgid "Rear Center" -msgstr "" +msgstr "უკანა ცენტრი" #: src/pulse/channelmap.c:110 msgid "Rear Left" -msgstr "" +msgstr "უკანა მარცხენა" #: src/pulse/channelmap.c:111 msgid "Rear Right" -msgstr "" +msgstr "უკანა მარკვენა" #: src/pulse/channelmap.c:113 msgid "Subwoofer" -msgstr "" +msgstr "საბვუფერი" #: src/pulse/channelmap.c:115 msgid "Front Left-of-center" -msgstr "" +msgstr "წინა ცენტრის მარცხენა" #: src/pulse/channelmap.c:116 msgid "Front Right-of-center" -msgstr "" +msgstr "წინა ცენტრის მარჯვენა" #: src/pulse/channelmap.c:118 msgid "Side Left" -msgstr "" +msgstr "მარცხენა მხარეს" #: src/pulse/channelmap.c:119 msgid "Side Right" -msgstr "" +msgstr "მარჯვენა მხარეს" #: src/pulse/channelmap.c:121 msgid "Auxiliary 0" -msgstr "" +msgstr "დამატებითი 0" #: src/pulse/channelmap.c:122 msgid "Auxiliary 1" -msgstr "" +msgstr "დამატებითი 1" #: src/pulse/channelmap.c:123 msgid "Auxiliary 2" -msgstr "" +msgstr "დამატებითი 2" #: src/pulse/channelmap.c:124 msgid "Auxiliary 3" -msgstr "" +msgstr "დამატებითი 3" #: src/pulse/channelmap.c:125 msgid "Auxiliary 4" -msgstr "" +msgstr "დამატებითი 4" #: src/pulse/channelmap.c:126 msgid "Auxiliary 5" -msgstr "" +msgstr "დამატებითი 5" #: src/pulse/channelmap.c:127 msgid "Auxiliary 6" -msgstr "" +msgstr "დამატებითი 6" #: src/pulse/channelmap.c:128 msgid "Auxiliary 7" -msgstr "" +msgstr "დამატებითი 7" #: src/pulse/channelmap.c:129 msgid "Auxiliary 8" -msgstr "" +msgstr "დამატებითი 8" #: src/pulse/channelmap.c:130 msgid "Auxiliary 9" -msgstr "" +msgstr "დამატებითი 9" #: src/pulse/channelmap.c:131 msgid "Auxiliary 10" -msgstr "" +msgstr "დამატებითი 10" #: src/pulse/channelmap.c:132 msgid "Auxiliary 11" -msgstr "" +msgstr "დამატებითი 11" #: src/pulse/channelmap.c:133 msgid "Auxiliary 12" -msgstr "" +msgstr "დამატებითი 12" #: src/pulse/channelmap.c:134 msgid "Auxiliary 13" -msgstr "" +msgstr "დამატებითი 13" #: src/pulse/channelmap.c:135 msgid "Auxiliary 14" -msgstr "" +msgstr "დამატებითი 14" #: src/pulse/channelmap.c:136 msgid "Auxiliary 15" -msgstr "" +msgstr "დამატებითი 15" #: src/pulse/channelmap.c:137 msgid "Auxiliary 16" -msgstr "" +msgstr "დამატებითი 16" #: src/pulse/channelmap.c:138 msgid "Auxiliary 17" -msgstr "" +msgstr "დამატებითი 17" #: src/pulse/channelmap.c:139 msgid "Auxiliary 18" -msgstr "" +msgstr "დამატებითი 18" #: src/pulse/channelmap.c:140 msgid "Auxiliary 19" -msgstr "" +msgstr "დამატებითი 19" #: src/pulse/channelmap.c:141 msgid "Auxiliary 20" -msgstr "" +msgstr "დამატებითი 20" #: src/pulse/channelmap.c:142 msgid "Auxiliary 21" -msgstr "" +msgstr "დამატებითი 21" #: src/pulse/channelmap.c:143 msgid "Auxiliary 22" -msgstr "" +msgstr "დამატებითი 22" #: src/pulse/channelmap.c:144 msgid "Auxiliary 23" -msgstr "" +msgstr "დამატებითი 23" #: src/pulse/channelmap.c:145 msgid "Auxiliary 24" -msgstr "" +msgstr "დამატებითი 24" #: src/pulse/channelmap.c:146 msgid "Auxiliary 25" -msgstr "" +msgstr "დამატებითი 25" #: src/pulse/channelmap.c:147 msgid "Auxiliary 26" -msgstr "" +msgstr "დამატებითი 26" #: src/pulse/channelmap.c:148 msgid "Auxiliary 27" -msgstr "" +msgstr "დამატებითი 27" #: src/pulse/channelmap.c:149 msgid "Auxiliary 28" -msgstr "" +msgstr "დამატებითი 28" #: src/pulse/channelmap.c:150 msgid "Auxiliary 29" -msgstr "" +msgstr "დამატებითი 29" #: src/pulse/channelmap.c:151 msgid "Auxiliary 30" -msgstr "" +msgstr "დამატებითი 30" #: src/pulse/channelmap.c:152 msgid "Auxiliary 31" -msgstr "" +msgstr "დამატებითი 31" #: src/pulse/channelmap.c:154 msgid "Top Center" -msgstr "" +msgstr "ზედა ცენტრი" #: src/pulse/channelmap.c:156 msgid "Top Front Center" -msgstr "" +msgstr "ზედა წინა ცენტრი" #: src/pulse/channelmap.c:157 msgid "Top Front Left" -msgstr "" +msgstr "ზედა წინა მარცხენა" #: src/pulse/channelmap.c:158 msgid "Top Front Right" -msgstr "" +msgstr "ზედა წინა მარჯვენა" #: src/pulse/channelmap.c:160 msgid "Top Rear Center" -msgstr "" +msgstr "ზედა უკანა ცენტრი" #: src/pulse/channelmap.c:161 msgid "Top Rear Left" -msgstr "" +msgstr "ზედა უკანა მარცხენა" #: src/pulse/channelmap.c:162 msgid "Top Rear Right" -msgstr "" +msgstr "ზედა უკანა მარჯვენა" #: src/pulse/channelmap.c:478 src/pulse/format.c:123 src/pulse/sample.c:177 #: src/pulse/volume.c:306 src/pulse/volume.c:332 src/pulse/volume.c:352 #: src/pulse/volume.c:384 src/pulse/volume.c:424 src/pulse/volume.c:443 #: src/utils/pactl.c:483 src/utils/pactl.c:504 msgid "(invalid)" -msgstr "" +msgstr "(არასწორი)" #: src/pulse/channelmap.c:779 msgid "Surround 4.0" @@ -1304,7 +1306,7 @@ msgstr "" #: src/pulse/client-conf-x11.c:61 src/utils/pax11publish.c:97 msgid "xcb_connect() failed" -msgstr "" +msgstr "xcb_connect() -ის შეცდომა" #: src/pulse/client-conf-x11.c:66 src/utils/pax11publish.c:102 msgid "xcb_connection_has_error() returned true" @@ -1317,12 +1319,12 @@ msgstr "" #: src/pulse/context.c:717 #, c-format msgid "fork(): %s" -msgstr "" +msgstr "fork(): %s" #: src/pulse/context.c:772 #, c-format msgid "waitpid(): %s" -msgstr "" +msgstr "waitpid(): %s" #: src/pulse/context.c:1488 #, c-format @@ -1331,11 +1333,11 @@ msgstr "" #: src/pulse/direction.c:37 msgid "input" -msgstr "" +msgstr "შეყვანა" #: src/pulse/direction.c:39 msgid "output" -msgstr "" +msgstr "გამოტანა" #: src/pulse/direction.c:41 msgid "bidirectional" @@ -1343,7 +1345,7 @@ msgstr "" #: src/pulse/direction.c:43 msgid "invalid" -msgstr "" +msgstr "არასწორი" #: src/pulsecore/core-util.c:1790 #, c-format @@ -1355,11 +1357,11 @@ msgstr "" #: src/pulsecore/core-util.h:97 msgid "yes" -msgstr "" +msgstr "დიახ" #: src/pulsecore/core-util.h:97 msgid "no" -msgstr "" +msgstr "არა" #: src/pulsecore/lock-autospawn.c:141 src/pulsecore/lock-autospawn.c:227 msgid "Cannot access autospawn lock." @@ -1386,23 +1388,23 @@ msgstr "" #: src/pulsecore/sink.c:3614 msgid "Modem" -msgstr "" +msgstr "მოდემი" #: src/pulse/error.c:38 msgid "OK" -msgstr "" +msgstr "დიახ" #: src/pulse/error.c:39 msgid "Access denied" -msgstr "" +msgstr "წვდომა აკრძალულია" #: src/pulse/error.c:40 msgid "Unknown command" -msgstr "" +msgstr "უცნობი ბრძანება" #: src/pulse/error.c:41 msgid "Invalid argument" -msgstr "" +msgstr "არასწორი არგუმენტი" #: src/pulse/error.c:42 msgid "Entity exists" @@ -1414,11 +1416,11 @@ msgstr "" #: src/pulse/error.c:44 msgid "Connection refused" -msgstr "" +msgstr "დაკავშირება უარყოფილია" #: src/pulse/error.c:45 msgid "Protocol error" -msgstr "" +msgstr "პროტოკოლის შეცდომა" #: src/pulse/error.c:46 msgid "Timeout" @@ -1430,7 +1432,7 @@ msgstr "" #: src/pulse/error.c:48 msgid "Internal error" -msgstr "" +msgstr "შიდა შეცდომა" #: src/pulse/error.c:49 msgid "Connection terminated" @@ -1454,7 +1456,7 @@ msgstr "" #: src/pulse/error.c:54 msgid "No data" -msgstr "" +msgstr "მონაცემების გარეშე" #: src/pulse/error.c:55 msgid "Incompatible protocol version" @@ -1466,7 +1468,7 @@ msgstr "" #: src/pulse/error.c:57 msgid "Not supported" -msgstr "" +msgstr "მხარდაუჭერელია" #: src/pulse/error.c:58 msgid "Unknown error code" @@ -1499,27 +1501,27 @@ msgstr "" #: src/pulse/sample.c:179 #, c-format msgid "%s %uch %uHz" -msgstr "" +msgstr "%s %uარხ %uჰც" #: src/pulse/sample.c:191 #, c-format msgid "%0.1f GiB" -msgstr "" +msgstr "%0.1f გიბ" #: src/pulse/sample.c:193 #, c-format msgid "%0.1f MiB" -msgstr "" +msgstr "%0.1f მიბ" #: src/pulse/sample.c:195 #, c-format msgid "%0.1f KiB" -msgstr "" +msgstr "%0.1f კიბ" #: src/pulse/sample.c:197 #, c-format msgid "%u B" -msgstr "" +msgstr "%u ბ" #: src/utils/pacat.c:134 #, c-format @@ -1537,17 +1539,17 @@ msgstr "" #: src/utils/pacat.c:163 #, c-format msgid "pa_stream_drain(): %s" -msgstr "" +msgstr "pa_stream_drain(): %s" #: src/utils/pacat.c:194 src/utils/pacat.c:543 #, c-format msgid "pa_stream_begin_write() failed: %s" -msgstr "" +msgstr "pa_stream_begin_write() -ის შეცდომა: %s" #: src/utils/pacat.c:244 src/utils/pacat.c:274 #, c-format msgid "pa_stream_peek() failed: %s" -msgstr "" +msgstr "pa_stream_peek() -ის შეცდომა: %s" #: src/utils/pacat.c:324 msgid "Stream successfully created." @@ -1556,7 +1558,7 @@ msgstr "" #: src/utils/pacat.c:327 #, c-format msgid "pa_stream_get_buffer_attr() failed: %s" -msgstr "" +msgstr "pa_stream_get_buffer_attr() -ის შეცდომა: %s" #: src/utils/pacat.c:331 #, c-format @@ -1642,12 +1644,12 @@ msgstr "" #: src/utils/pacat.c:453 #, c-format msgid "pa_stream_new() failed: %s" -msgstr "" +msgstr "pa_stream_new() -ის შეცდომა: %s" #: src/utils/pacat.c:491 #, c-format msgid "pa_stream_connect_playback() failed: %s" -msgstr "" +msgstr "pa_stream_connect_playback() -ის შეცდომა: %s" #: src/utils/pacat.c:497 #, c-format @@ -1657,7 +1659,7 @@ msgstr "" #: src/utils/pacat.c:501 #, c-format msgid "pa_stream_connect_record() failed: %s" -msgstr "" +msgstr "pa_stream_connect_record() -ის შეცდომა: %s" #: src/utils/pacat.c:514 src/utils/pactl.c:2508 #, c-format @@ -1676,7 +1678,7 @@ msgstr "" #: src/utils/pacat.c:605 #, c-format msgid "write() failed: %s" -msgstr "" +msgstr "write() -ის შეცდომა: %s" #: src/utils/pacat.c:626 msgid "Got signal, exiting." @@ -1841,16 +1843,16 @@ msgstr "" #: src/utils/pacat.c:1021 #, c-format msgid "open(): %s" -msgstr "" +msgstr "open(): %s" #: src/utils/pacat.c:1026 #, c-format msgid "dup2(): %s" -msgstr "" +msgstr "dup2(): %s" #: src/utils/pacat.c:1033 msgid "Too many arguments." -msgstr "" +msgstr "მეტისმეტად ბევრი არგუმენტი." #: src/utils/pacat.c:1044 msgid "Failed to generate sample specification for file." @@ -1890,11 +1892,11 @@ msgstr "" #: src/utils/pacat.c:1138 msgid "recording" -msgstr "" +msgstr "ჩაწერა" #: src/utils/pacat.c:1138 msgid "playback" -msgstr "" +msgstr "დაკვრა" #: src/utils/pacat.c:1162 msgid "Failed to set media name." @@ -1902,28 +1904,28 @@ msgstr "" #: src/utils/pacat.c:1172 src/utils/pactl.c:3218 msgid "pa_mainloop_new() failed." -msgstr "" +msgstr "pa_mainloop_new() -ის შეცდომა." #: src/utils/pacat.c:1195 msgid "io_new() failed." -msgstr "" +msgstr "io_new() -ის შეცდომა." #: src/utils/pacat.c:1202 src/utils/pactl.c:3230 msgid "pa_context_new() failed." -msgstr "" +msgstr "pa_context_new() -ის შეცდომა." #: src/utils/pacat.c:1210 src/utils/pactl.c:3236 #, c-format msgid "pa_context_connect() failed: %s" -msgstr "" +msgstr "pa_context_connect() -ის შეცდომა: %s" #: src/utils/pacat.c:1216 msgid "pa_context_rttime_new() failed." -msgstr "" +msgstr "pa_context_rttime_new() -ის შეცდომა." #: src/utils/pacat.c:1223 src/utils/pactl.c:3241 msgid "pa_mainloop_run() failed." -msgstr "" +msgstr "pa_mainloop_run() -ის შეცდომა." #: src/utils/pacmd.c:51 src/utils/pactl.c:2643 msgid "NAME [ARGS ...]" @@ -1937,7 +1939,7 @@ msgstr "" #: src/utils/pacmd.c:53 src/utils/pacmd.c:63 src/utils/pactl.c:2642 #: src/utils/pactl.c:2649 msgid "NAME" -msgstr "" +msgstr "სახელი" #: src/utils/pacmd.c:54 msgid "NAME|#N VOLUME" @@ -1953,7 +1955,7 @@ msgstr "" #: src/utils/pacmd.c:57 msgid "#N 1|0" -msgstr "" +msgstr "#N 1|0" #: src/utils/pacmd.c:58 msgid "NAME|#N KEY=VALUE" @@ -1965,7 +1967,7 @@ msgstr "" #: src/utils/pacmd.c:61 msgid "#N" -msgstr "" +msgstr "#N" #: src/utils/pacmd.c:62 msgid "NAME SINK|#N" @@ -1977,7 +1979,7 @@ msgstr "" #: src/utils/pacmd.c:66 msgid "PATHNAME" -msgstr "" +msgstr "ბილიკის სახელი" #: src/utils/pacmd.c:67 msgid "FILENAME SINK|#N" @@ -1989,7 +1991,7 @@ msgstr "" #: src/utils/pacmd.c:71 src/utils/pacmd.c:77 src/utils/pacmd.c:78 msgid "1|0" -msgstr "" +msgstr "1|0" #: src/utils/pacmd.c:72 src/utils/pactl.c:2647 msgid "CARD PROFILE" @@ -2005,7 +2007,7 @@ msgstr "" #: src/utils/pacmd.c:75 msgid "TARGET" -msgstr "" +msgstr "სამიზნე" #: src/utils/pacmd.c:76 msgid "NUMERIC-LEVEL" @@ -2048,7 +2050,7 @@ msgstr "" #: src/utils/pacmd.c:165 #, c-format msgid "connect(): %s" -msgstr "" +msgstr "connect(): %s" #: src/utils/pacmd.c:173 msgid "Failed to kill PulseAudio daemon." @@ -2061,17 +2063,17 @@ msgstr "" #: src/utils/pacmd.c:213 src/utils/pacmd.c:322 src/utils/pacmd.c:340 #, c-format msgid "write(): %s" -msgstr "" +msgstr "write(): %s" #: src/utils/pacmd.c:269 #, c-format msgid "poll(): %s" -msgstr "" +msgstr "poll(): %s" #: src/utils/pacmd.c:280 src/utils/pacmd.c:300 #, c-format msgid "read(): %s" -msgstr "" +msgstr "read(): %s" #: src/utils/pactl.c:183 #, c-format @@ -2106,7 +2108,7 @@ msgstr "" #: src/utils/pactl.c:224 src/utils/pactl.c:236 #, c-format msgid "%s\n" -msgstr "" +msgstr "%s\n" #: src/utils/pactl.c:281 #, c-format @@ -2139,15 +2141,15 @@ msgstr "" #: src/utils/pactl.c:321 msgid "available" -msgstr "" +msgstr "ხელმისაწვდომია" #: src/utils/pactl.c:322 msgid "not available" -msgstr "" +msgstr "მიუწვდომელია" #: src/utils/pactl.c:331 src/utils/pactl.c:355 msgid "Unknown" -msgstr "" +msgstr "უცნობი" #: src/utils/pactl.c:332 msgid "Aux" @@ -2155,7 +2157,7 @@ msgstr "" #: src/utils/pactl.c:335 msgid "Line" -msgstr "" +msgstr "ხაზი" #: src/utils/pactl.c:336 msgid "Mic" @@ -2171,31 +2173,31 @@ msgstr "" #: src/utils/pactl.c:340 msgid "SPDIF" -msgstr "" +msgstr "SPDIF" #: src/utils/pactl.c:341 msgid "HDMI" -msgstr "" +msgstr "HDMI" #: src/utils/pactl.c:342 msgid "TV" -msgstr "" +msgstr "TV" #: src/utils/pactl.c:345 msgid "USB" -msgstr "" +msgstr "USB" #: src/utils/pactl.c:346 msgid "Bluetooth" -msgstr "" +msgstr "Bluetooth" #: src/utils/pactl.c:352 msgid "Network" -msgstr "" +msgstr "ქსელი" #: src/utils/pactl.c:353 msgid "Analog" -msgstr "" +msgstr "ანალოგური" #: src/utils/pactl.c:567 src/utils/pactl.c:1834 src/utils/pactl.c:1852 #: src/utils/pactl.c:1875 src/utils/pactl.c:1992 @@ -2228,7 +2230,7 @@ msgstr "" #: src/utils/pactl.c:706 src/utils/pactl.c:890 src/utils/pactl.c:1251 #, c-format msgid "\tPorts:\n" -msgstr "" +msgstr "\tპორტები:\n" #: src/utils/pactl.c:708 src/utils/pactl.c:892 #, c-format @@ -2247,7 +2249,7 @@ msgstr "" #: src/utils/pactl.c:721 src/utils/pactl.c:905 #, c-format msgid "\tFormats:\n" -msgstr "" +msgstr "\tფორმატები:\n" #: src/utils/pactl.c:753 src/utils/pactl.c:1893 src/utils/pactl.c:1911 #: src/utils/pactl.c:1934 src/utils/pactl.c:2007 @@ -2283,7 +2285,7 @@ msgstr "" #: src/utils/pactl.c:1519 src/utils/pactl.c:1557 src/utils/pactl.c:1582 #: src/utils/pactl.c:1624 msgid "n/a" -msgstr "" +msgstr "ა/მ" #: src/utils/pactl.c:924 src/utils/pactl.c:1793 #, c-format @@ -2335,7 +2337,7 @@ msgstr "" #: src/utils/pactl.c:1238 #, c-format msgid "\tProfiles:\n" -msgstr "" +msgstr "\tპროფილები:\n" #: src/utils/pactl.c:1240 #, c-format @@ -2345,7 +2347,7 @@ msgstr "" #: src/utils/pactl.c:1245 #, c-format msgid "\tActive Profile: %s\n" -msgstr "" +msgstr "\tაქტიური პროფილი: %s\n" #: src/utils/pactl.c:1254 #, c-format @@ -2496,19 +2498,19 @@ msgstr "" #: src/utils/pactl.c:2144 msgid "new" -msgstr "" +msgstr "ახალი" #: src/utils/pactl.c:2147 msgid "change" -msgstr "" +msgstr "შეცვლა" #: src/utils/pactl.c:2150 msgid "remove" -msgstr "" +msgstr "წაშლა" #: src/utils/pactl.c:2153 src/utils/pactl.c:2188 msgid "unknown" -msgstr "" +msgstr "უცნობი" #: src/utils/pactl.c:2161 msgid "sink" @@ -2516,7 +2518,7 @@ msgstr "" #: src/utils/pactl.c:2164 msgid "source" -msgstr "" +msgstr "წყარო" #: src/utils/pactl.c:2167 msgid "sink-input" @@ -2528,11 +2530,11 @@ msgstr "" #: src/utils/pactl.c:2173 msgid "module" -msgstr "" +msgstr "მოდული" #: src/utils/pactl.c:2176 msgid "client" -msgstr "" +msgstr "კლიენტი" #: src/utils/pactl.c:2179 msgid "sample-cache" @@ -2540,11 +2542,11 @@ msgstr "" #: src/utils/pactl.c:2182 msgid "server" -msgstr "" +msgstr "სერვერი" #: src/utils/pactl.c:2185 msgid "card" -msgstr "" +msgstr "კარტი" #: src/utils/pactl.c:2206 #, c-format @@ -2581,7 +2583,7 @@ msgstr "" #: src/utils/pactl.c:2657 src/utils/pactl.c:2658 src/utils/pactl.c:2659 #: src/utils/pactl.c:2660 msgid "[options]" -msgstr "" +msgstr "[პარამეტრები]" #: src/utils/pactl.c:2638 msgid "[TYPE]" @@ -2824,12 +2826,12 @@ msgstr "" #: src/utils/pasuspender.c:79 #, c-format msgid "fork(): %s\n" -msgstr "" +msgstr "fork(): %s\n" #: src/utils/pasuspender.c:92 #, c-format msgid "execvp(): %s\n" -msgstr "" +msgstr "execvp(): %s\n" #: src/utils/pasuspender.c:111 #, c-format @@ -2886,17 +2888,17 @@ msgstr "" #: src/utils/pasuspender.c:296 #, c-format msgid "pa_mainloop_new() failed.\n" -msgstr "" +msgstr "pa_mainloop_new()-ის შეცდომა.\n" #: src/utils/pasuspender.c:309 #, c-format msgid "pa_context_new() failed.\n" -msgstr "" +msgstr "pa_context_new() -ის შეცდომა.\n" #: src/utils/pasuspender.c:321 #, c-format msgid "pa_mainloop_run() failed.\n" -msgstr "" +msgstr "pa_mainloop_run() -ის შეცდომა.\n" #: src/utils/pax11publish.c:58 #, c-format @@ -2918,12 +2920,12 @@ msgstr "" #: src/utils/pax11publish.c:110 #, c-format msgid "Server: %s\n" -msgstr "" +msgstr "სერვერი: %s\n" #: src/utils/pax11publish.c:112 #, c-format msgid "Source: %s\n" -msgstr "" +msgstr "წყარო: %s\n" #: src/utils/pax11publish.c:114 #, c-format From dbe455ce955f00fc70e7ff13989832570e8a6954 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=9D=B8=EC=88=98?= Date: Sun, 17 Jul 2022 15:16:48 +0000 Subject: [PATCH 049/260] Translated using Weblate (Korean) Currently translated at 100.0% (572 of 572 strings) Translation: pulseaudio/pulseaudio Translate-URL: https://translate.fedoraproject.org/projects/pulseaudio/pulseaudio/ko/ Part-of: --- po/ko.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/po/ko.po b/po/ko.po index 0693dc631..7e39624fd 100644 --- a/po/ko.po +++ b/po/ko.po @@ -7,8 +7,8 @@ msgstr "" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" "POT-Creation-Date: 2022-06-18 09:49+0300\n" -"PO-Revision-Date: 2022-06-12 14:19+0000\n" -"Last-Translator: Seong-ho Cho \n" +"PO-Revision-Date: 2022-07-18 15:19+0000\n" +"Last-Translator: 김인수 \n" "Language-Team: Korean \n" "Language: ko\n" @@ -16,7 +16,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 4.12.2\n" +"X-Generator: Weblate 4.13\n" #: src/daemon/cmdline.c:113 #, c-format @@ -389,7 +389,7 @@ msgstr "'%s' 사용자의 GID와 '%s' 그룹 정보가 일치하지 않습니다 #: src/daemon/main.c:284 #, c-format msgid "Home directory of user '%s' is not '%s', ignoring." -msgstr "'%s' 사용자의 홈 디렉터리가 '%s' 경로가 아닙니다, 무시함." +msgstr "사용자 '%s'의 홈 디렉토리가 '%s' 아니면, 무시합니다." #: src/daemon/main.c:287 src/daemon/main.c:292 #, c-format From 15f242aee53fb54ccd6e94e25fc6d59ff831eed7 Mon Sep 17 00:00:00 2001 From: Temuri Doghonadze Date: Wed, 20 Jul 2022 11:15:15 +0000 Subject: [PATCH 050/260] Translated using Weblate (Georgian) Currently translated at 43.5% (249 of 572 strings) Translation: pulseaudio/pulseaudio Translate-URL: https://translate.fedoraproject.org/projects/pulseaudio/pulseaudio/ka/ Part-of: --- po/ka.po | 178 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 103 insertions(+), 75 deletions(-) diff --git a/po/ka.po b/po/ka.po index 36cc278ba..6a88ebfb1 100644 --- a/po/ka.po +++ b/po/ka.po @@ -9,7 +9,7 @@ msgstr "" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" "POT-Creation-Date: 2022-06-18 09:49+0300\n" -"PO-Revision-Date: 2022-06-19 18:52+0000\n" +"PO-Revision-Date: 2022-07-21 12:42+0000\n" "Last-Translator: Temuri Doghonadze \n" "Language-Team: Georgian \n" @@ -483,19 +483,19 @@ msgstr "შეყვანა" #: src/modules/alsa/alsa-mixer.c:2709 msgid "Docking Station Input" -msgstr "" +msgstr "Docking Station-ის შეყვანა" #: src/modules/alsa/alsa-mixer.c:2710 msgid "Docking Station Microphone" -msgstr "" +msgstr "Docking Station-ის მიკროფონი" #: src/modules/alsa/alsa-mixer.c:2711 msgid "Docking Station Line In" -msgstr "" +msgstr "Docking Station Line In" #: src/modules/alsa/alsa-mixer.c:2712 src/modules/alsa/alsa-mixer.c:2803 msgid "Line In" -msgstr "" +msgstr "Line In" #: src/modules/alsa/alsa-mixer.c:2713 src/modules/alsa/alsa-mixer.c:2797 #: src/modules/bluetooth/module-bluez5-device.c:1956 @@ -504,19 +504,19 @@ msgstr "მიკროფონი" #: src/modules/alsa/alsa-mixer.c:2714 src/modules/alsa/alsa-mixer.c:2798 msgid "Front Microphone" -msgstr "" +msgstr "წინა მიკროფონი" #: src/modules/alsa/alsa-mixer.c:2715 src/modules/alsa/alsa-mixer.c:2799 msgid "Rear Microphone" -msgstr "" +msgstr "უკანა მიკფოფონი" #: src/modules/alsa/alsa-mixer.c:2716 msgid "External Microphone" -msgstr "" +msgstr "გარე მიკროფონი" #: src/modules/alsa/alsa-mixer.c:2717 src/modules/alsa/alsa-mixer.c:2801 msgid "Internal Microphone" -msgstr "" +msgstr "შიდა მიკროფონი" #: src/modules/alsa/alsa-mixer.c:2718 src/modules/alsa/alsa-mixer.c:2804 #: src/utils/pactl.c:343 @@ -530,27 +530,27 @@ msgstr "ვიდეო" #: src/modules/alsa/alsa-mixer.c:2720 msgid "Automatic Gain Control" -msgstr "" +msgstr "ხმის მომატების ავტომატური კონტროლი" #: src/modules/alsa/alsa-mixer.c:2721 msgid "No Automatic Gain Control" -msgstr "" +msgstr "ხმის მომატების ავტომატური კონტროლის გამორთვა" #: src/modules/alsa/alsa-mixer.c:2722 msgid "Boost" -msgstr "" +msgstr "გაძლიერება" #: src/modules/alsa/alsa-mixer.c:2723 msgid "No Boost" -msgstr "" +msgstr "გაძლიერების გარეშე" #: src/modules/alsa/alsa-mixer.c:2724 msgid "Amplifier" -msgstr "" +msgstr "გამაძლიერებელი" #: src/modules/alsa/alsa-mixer.c:2725 msgid "No Amplifier" -msgstr "" +msgstr "გამაძლიერებლის გარეშე" #: src/modules/alsa/alsa-mixer.c:2726 msgid "Bass Boost" @@ -558,7 +558,7 @@ msgstr "Bass-ის გაძლიერება" #: src/modules/alsa/alsa-mixer.c:2727 msgid "No Bass Boost" -msgstr "" +msgstr "Bass-ის გაძლიერების გარეშე" #: src/modules/alsa/alsa-mixer.c:2728 #: src/modules/bluetooth/module-bluez5-device.c:1964 src/utils/pactl.c:333 @@ -572,35 +572,35 @@ msgstr "ყურსაცვამები" #: src/modules/alsa/alsa-mixer.c:2796 msgid "Analog Input" -msgstr "" +msgstr "ანალოგური შეყვანა" #: src/modules/alsa/alsa-mixer.c:2800 msgid "Dock Microphone" -msgstr "" +msgstr "მისამაგრებელი მიკროფონი" #: src/modules/alsa/alsa-mixer.c:2802 msgid "Headset Microphone" -msgstr "" +msgstr "ყურსაცვამის მიროფონი" #: src/modules/alsa/alsa-mixer.c:2806 msgid "Analog Output" -msgstr "" +msgstr "ანალოგური გამოტანა" #: src/modules/alsa/alsa-mixer.c:2808 msgid "Headphones 2" -msgstr "" +msgstr "ყურსაცვამები 2" #: src/modules/alsa/alsa-mixer.c:2809 msgid "Headphones Mono Output" -msgstr "" +msgstr "ყურსაცვამები მონო" #: src/modules/alsa/alsa-mixer.c:2810 msgid "Line Out" -msgstr "" +msgstr "ხაზოვანი გამოყვანა" #: src/modules/alsa/alsa-mixer.c:2811 msgid "Analog Mono Output" -msgstr "" +msgstr "ანალოგური მონო გამოყვანა" #: src/modules/alsa/alsa-mixer.c:2812 msgid "Speakers" @@ -608,51 +608,51 @@ msgstr "დინამიკები" #: src/modules/alsa/alsa-mixer.c:2813 msgid "HDMI / DisplayPort" -msgstr "" +msgstr "HDMI / DisplayPort" #: src/modules/alsa/alsa-mixer.c:2814 msgid "Digital Output (S/PDIF)" -msgstr "" +msgstr "ციფრული გამოყვანა (S/PDIF)" #: src/modules/alsa/alsa-mixer.c:2815 msgid "Digital Input (S/PDIF)" -msgstr "" +msgstr "ციფრული შეტანა (S/PDIF)" #: src/modules/alsa/alsa-mixer.c:2816 msgid "Multichannel Input" -msgstr "" +msgstr "მრავალარხიანი შეყვანა" #: src/modules/alsa/alsa-mixer.c:2817 msgid "Multichannel Output" -msgstr "" +msgstr "მრავალარხიანი გამოყვანა" #: src/modules/alsa/alsa-mixer.c:2818 msgid "Game Output" -msgstr "" +msgstr "თამაშის გამოყვანა" #: src/modules/alsa/alsa-mixer.c:2819 src/modules/alsa/alsa-mixer.c:2820 msgid "Chat Output" -msgstr "" +msgstr "ჩატის გამოყვანა" #: src/modules/alsa/alsa-mixer.c:2821 msgid "Chat Input" -msgstr "" +msgstr "ჩატის შეყვანა" #: src/modules/alsa/alsa-mixer.c:2822 msgid "Virtual Surround 7.1" -msgstr "" +msgstr "ვირტუალური სივრცითი ხმა 7.1" #: src/modules/alsa/alsa-mixer.c:4563 msgid "Analog Mono" -msgstr "" +msgstr "ანალოგური მონო" #: src/modules/alsa/alsa-mixer.c:4564 msgid "Analog Mono (Left)" -msgstr "" +msgstr "ანალოგური მონო (მარცხენა)" #: src/modules/alsa/alsa-mixer.c:4565 msgid "Analog Mono (Right)" -msgstr "" +msgstr "ანალოგური მონო (მარჯვენა)" #. Note: Not translated to "Analog Stereo Input", because the source #. * name gets "Input" appended to it automatically, so adding "Input" @@ -662,7 +662,7 @@ msgstr "" #: src/modules/alsa/alsa-mixer.c:4566 src/modules/alsa/alsa-mixer.c:4574 #: src/modules/alsa/alsa-mixer.c:4575 msgid "Analog Stereo" -msgstr "" +msgstr "ანალოგური სტერეო" #: src/modules/alsa/alsa-mixer.c:4567 src/pulse/channelmap.c:103 #: src/pulse/channelmap.c:770 @@ -680,79 +680,79 @@ msgstr "ყურსაცვამები & მიკროფონი" #: src/modules/alsa/alsa-mixer.c:4577 src/modules/alsa/alsa-mixer.c:4735 msgid "Speakerphone" -msgstr "" +msgstr "სამაგიდო დინამიკი" #: src/modules/alsa/alsa-mixer.c:4578 src/modules/alsa/alsa-mixer.c:4579 msgid "Multichannel" -msgstr "" +msgstr "მრავალარხიანი" #: src/modules/alsa/alsa-mixer.c:4580 msgid "Analog Surround 2.1" -msgstr "" +msgstr "ანალოგური სივრცითი 2.1" #: src/modules/alsa/alsa-mixer.c:4581 msgid "Analog Surround 3.0" -msgstr "" +msgstr "ანალოგური სივრცითი 3.0" #: src/modules/alsa/alsa-mixer.c:4582 msgid "Analog Surround 3.1" -msgstr "" +msgstr "ანალოგური სივრცითი 3.1" #: src/modules/alsa/alsa-mixer.c:4583 msgid "Analog Surround 4.0" -msgstr "" +msgstr "ანალოგური სივრცითი 4.0" #: src/modules/alsa/alsa-mixer.c:4584 msgid "Analog Surround 4.1" -msgstr "" +msgstr "ანალოგური სივრცითი 4.1" #: src/modules/alsa/alsa-mixer.c:4585 msgid "Analog Surround 5.0" -msgstr "" +msgstr "ანალოგური სივრცითი 5.0" #: src/modules/alsa/alsa-mixer.c:4586 msgid "Analog Surround 5.1" -msgstr "" +msgstr "ანალოგური სივრცითი 5.1" #: src/modules/alsa/alsa-mixer.c:4587 msgid "Analog Surround 6.0" -msgstr "" +msgstr "ანალოგური სივრცითი 6.0" #: src/modules/alsa/alsa-mixer.c:4588 msgid "Analog Surround 6.1" -msgstr "" +msgstr "ანალოგური სივრცითი 6.1" #: src/modules/alsa/alsa-mixer.c:4589 msgid "Analog Surround 7.0" -msgstr "" +msgstr "ანალოგური სივრცითი 7.0" #: src/modules/alsa/alsa-mixer.c:4590 msgid "Analog Surround 7.1" -msgstr "" +msgstr "ანალოგური სივრცითი 7.1" #: src/modules/alsa/alsa-mixer.c:4591 msgid "Digital Stereo (IEC958)" -msgstr "" +msgstr "ციფრული სტერეო (IEC958)" #: src/modules/alsa/alsa-mixer.c:4592 msgid "Digital Surround 4.0 (IEC958/AC3)" -msgstr "" +msgstr "ციფრული სივრცითი 4.0 (IEC958/AC3)" #: src/modules/alsa/alsa-mixer.c:4593 msgid "Digital Surround 5.1 (IEC958/AC3)" -msgstr "" +msgstr "ციფრული სივრცითი 5.1 (IEC958/AC3)" #: src/modules/alsa/alsa-mixer.c:4594 msgid "Digital Surround 5.1 (IEC958/DTS)" -msgstr "" +msgstr "ციფრული სივრცითი 5.1 (IEC958/DTS)" #: src/modules/alsa/alsa-mixer.c:4595 msgid "Digital Stereo (HDMI)" -msgstr "" +msgstr "ციფრული სტერეო (HDMI)" #: src/modules/alsa/alsa-mixer.c:4596 msgid "Digital Surround 5.1 (HDMI)" -msgstr "" +msgstr "ციფრული სივრცითი 5.1 (HDMI)" #: src/modules/alsa/alsa-mixer.c:4597 msgid "Chat" @@ -764,27 +764,27 @@ msgstr "თამაში" #: src/modules/alsa/alsa-mixer.c:4732 msgid "Analog Mono Duplex" -msgstr "" +msgstr "ანალოგური მონო დუპლექსი" #: src/modules/alsa/alsa-mixer.c:4733 msgid "Analog Stereo Duplex" -msgstr "" +msgstr "ანალოგური სტერეო დუპლექსი" #: src/modules/alsa/alsa-mixer.c:4736 msgid "Digital Stereo Duplex (IEC958)" -msgstr "" +msgstr "ციფრული სტერეო დუპლექსი (IEC958)" #: src/modules/alsa/alsa-mixer.c:4737 msgid "Multichannel Duplex" -msgstr "" +msgstr "მრავალარხიანი დუპლექსი" #: src/modules/alsa/alsa-mixer.c:4738 msgid "Stereo Duplex" -msgstr "" +msgstr "სტერეო დუპლექსი" #: src/modules/alsa/alsa-mixer.c:4739 msgid "Mono Chat + 7.1 Surround" -msgstr "" +msgstr "მონო ჩატი + 7.1 სივრცითი" #: src/modules/alsa/alsa-mixer.c:4740 src/modules/alsa/module-alsa-card.c:197 #: src/modules/bluetooth/module-bluez5-device.c:2263 @@ -794,12 +794,12 @@ msgstr "გამორთული" #: src/modules/alsa/alsa-mixer.c:4840 #, c-format msgid "%s Output" -msgstr "" +msgstr "%s გამოყვანა" #: src/modules/alsa/alsa-mixer.c:4848 #, c-format msgid "%s Input" -msgstr "" +msgstr "%s შეყვანა" #: src/modules/alsa/alsa-sink.c:672 src/modules/alsa/alsa-sink.c:862 #, c-format @@ -836,7 +836,15 @@ msgid_plural "" "Most likely this is a bug in the ALSA driver '%s'. Please report this issue " "to the ALSA developers." msgstr[0] "" +"snd_pcm_avail()-ის მიერ დაბრუნებული მნიშვნელობა არაჩვეულებრივად დიდია: %lu " +"ბაიტი (%lu მწმ).\n" +"ყველაზე ხშირად ეს ALSA-ს დრაივერის (%s) შეცდომის გამო ხდება. დაუკავშირდით " +"ALSA-ის პროგრამისტებს." msgstr[1] "" +"snd_pcm_avail()-ის მიერ დაბრუნებული მნიშვნელობა არაჩვეულებრივად დიდია: %lu " +"ბაიტი (%lu მწმ).\n" +"ყველაზე ხშირად ეს ALSA-ს დრაივერის (%s) შეცდომის გამო ხდება. დაუკავშირდით " +"ALSA-ის პროგრამისტებს." #: src/modules/alsa/alsa-util.c:1249 #, c-format @@ -851,7 +859,15 @@ msgid_plural "" "Most likely this is a bug in the ALSA driver '%s'. Please report this issue " "to the ALSA developers." msgstr[0] "" +"snd_pcm_delay()-ის მიერ დაბრუნებული მნიშვნელობა არაჩვეულებრივად დიდია: %li " +"ბაიტი (%s%lu მწმ).\n" +"ყველაზე ხშირად ეს ALSA-ს დრაივერის (%s) შეცდომის გამო ხდება. დაუკავშირდით " +"ALSA-ის პროგრამისტებს." msgstr[1] "" +"snd_pcm_delay()-ის მიერ დაბრუნებული მნიშვნელობა არაჩვეულებრივად დიდია: %li " +"ბაიტი (%s%lu მწმ).\n" +"ყველაზე ხშირად ეს ALSA-ს დრაივერის (%s) შეცდომის გამო ხდება. დაუკავშირდით " +"ALSA-ის პროგრამისტებს." #: src/modules/alsa/alsa-util.c:1296 #, c-format @@ -861,6 +877,10 @@ msgid "" "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-ის პროგრამისტებს." #: src/modules/alsa/alsa-util.c:1339 #, c-format @@ -875,7 +895,15 @@ msgid_plural "" "Most likely this is a bug in the ALSA driver '%s'. Please report this issue " "to the ALSA developers." msgstr[0] "" +"snd_pcm_mmap_begin()-ის მიერ დაბრუნებული მნიშვნელობა არაჩვეულებრივად დიდია: " +"%lu ბაიტი (%lu მწმ).\n" +"ყველაზე ხშირად ეს ALSA-ს დრაივერის (%s) შეცდომის გამო ხდება. დაუკავშირდით " +"ALSA-ის პროგრამისტებს." msgstr[1] "" +"snd_pcm_mmap_begin()-ის მიერ დაბრუნებული მნიშვნელობა არაჩვეულებრივად დიდია: " +"%lu ბაიტი (%lu მწმ).\n" +"ყველაზე ხშირად ეს ALSA-ს დრაივერის (%s) შეცდომის გამო ხდება. დაუკავშირდით " +"ALSA-ის პროგრამისტებს." #: src/modules/bluetooth/module-bluez5-device.c:1937 #: src/modules/bluetooth/module-bluez5-device.c:1963 @@ -890,11 +918,11 @@ msgstr "" #: src/modules/bluetooth/module-bluez5-device.c:1950 src/utils/pactl.c:348 msgid "Handsfree" -msgstr "" +msgstr "ხელის გარეშე სამართავი" #: src/modules/bluetooth/module-bluez5-device.c:1971 msgid "Headphone" -msgstr "" +msgstr "ყურსაცვამი" #: src/modules/bluetooth/module-bluez5-device.c:1977 src/utils/pactl.c:347 msgid "Portable" @@ -902,7 +930,7 @@ msgstr "გადატანადი" #: src/modules/bluetooth/module-bluez5-device.c:1983 src/utils/pactl.c:349 msgid "Car" -msgstr "" +msgstr "მანქანა" #: src/modules/bluetooth/module-bluez5-device.c:1989 src/utils/pactl.c:350 msgid "HiFi" @@ -914,7 +942,7 @@ msgstr "ტელეფონი" #: src/modules/bluetooth/module-bluez5-device.c:2042 msgid "High Fidelity Playback (A2DP Sink)" -msgstr "" +msgstr "მაღალი ხარისხის ხმა (A2DP Sink)" #: src/modules/bluetooth/module-bluez5-device.c:2054 msgid "High Fidelity Capture (A2DP Source)" @@ -958,7 +986,7 @@ msgstr "ჩართული" #: src/modules/module-allow-passthrough.c:71 #: src/modules/module-always-sink.c:80 msgid "Dummy Output" -msgstr "" +msgstr "ნულოვანი გამოყვანა" #: src/modules/module-always-sink.c:34 msgid "Always keeps at least one sink loaded even if it's a null one" @@ -1042,13 +1070,13 @@ msgstr "" #: src/modules/module-tunnel-source-new.c:354 #, c-format msgid "Tunnel for %s@%s" -msgstr "" +msgstr "გვირაბი %s@%s-სთვის" #: src/modules/module-tunnel-sink-new.c:715 #: src/modules/module-tunnel-source-new.c:684 #, c-format msgid "Tunnel to %s/%s" -msgstr "" +msgstr "გვირაბი %s/%s -მდე" #: src/modules/module-virtual-surround-sink.c:50 msgid "Virtual surround sink" @@ -1384,7 +1412,7 @@ msgstr "" #: src/pulsecore/sink.c:3609 msgid "Built-in Audio" -msgstr "" +msgstr "ჩაშენებული აუდიო" #: src/pulsecore/sink.c:3614 msgid "Modem" @@ -1424,7 +1452,7 @@ msgstr "პროტოკოლის შეცდომა" #: src/pulse/error.c:46 msgid "Timeout" -msgstr "" +msgstr "ვადა" #: src/pulse/error.c:47 msgid "No authentication key" @@ -1452,7 +1480,7 @@ msgstr "" #: src/pulse/error.c:53 msgid "Bad state" -msgstr "" +msgstr "შეცდომის შემცველი მდგომარეობა" #: src/pulse/error.c:54 msgid "No data" @@ -2446,7 +2474,7 @@ msgstr "" #: src/utils/pactl.c:1633 src/utils/pactl.c:1643 #, c-format msgid "Failure: %s" -msgstr "" +msgstr "შეცდომა: %s" #: src/utils/pactl.c:1667 #, c-format From 9337d4b5b5a2d51e9d653435631483c081644cc3 Mon Sep 17 00:00:00 2001 From: Joachim Philipp Date: Thu, 21 Jul 2022 07:26:24 +0000 Subject: [PATCH 051/260] Translated using Weblate (German) Currently translated at 94.9% (543 of 572 strings) Translation: pulseaudio/pulseaudio Translate-URL: https://translate.fedoraproject.org/projects/pulseaudio/pulseaudio/de/ Part-of: --- po/de.po | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/po/de.po b/po/de.po index c510f5904..12b58f5b6 100644 --- a/po/de.po +++ b/po/de.po @@ -15,8 +15,8 @@ msgstr "" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" "POT-Creation-Date: 2022-06-18 09:49+0300\n" -"PO-Revision-Date: 2021-12-05 21:16+0000\n" -"Last-Translator: Ettore Atalan \n" +"PO-Revision-Date: 2022-07-22 13:18+0000\n" +"Last-Translator: Joachim Philipp \n" "Language-Team: German \n" "Language: de\n" @@ -24,7 +24,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.9.1\n" +"X-Generator: Weblate 4.13\n" #: src/daemon/cmdline.c:113 #, fuzzy, c-format @@ -188,7 +188,6 @@ msgid "--fail expects boolean argument" msgstr "--fail erfordert boolesche Variable" #: src/daemon/cmdline.c:265 -#, fuzzy msgid "" "--log-level expects log level argument (either numeric in range 0..4 or one " "of error, warn, notice, info, debug)." @@ -218,14 +217,12 @@ msgid "--use-pid-file expects boolean argument" msgstr "--use-pid-file erfordert boolesche Variable" #: src/daemon/cmdline.c:328 -#, fuzzy msgid "" "Invalid log target: use either 'syslog', 'journal', 'stderr' or 'auto' or a " "valid file name 'file:', 'newfile:'." msgstr "" -"Ungültiges Protokollziel: Benutzen Sie entweder »syslog«, »journal«, " -"»stderr« oder »auto« oder einen gültigen Dateinamen »file:«, »newfile:" -"«." +"Ungültiges Protokollziel: Benutzen Sie entweder »syslog«, »journal«, »stderr«" +" oder »auto« oder einen gültigen Dateinamen »file:«, »newfile:«." #: src/daemon/cmdline.c:330 msgid "" From dc027d69e886cbd0da1eb2124fd824251e157b18 Mon Sep 17 00:00:00 2001 From: Temuri Doghonadze Date: Thu, 21 Jul 2022 12:43:02 +0000 Subject: [PATCH 052/260] Translated using Weblate (Georgian) Currently translated at 43.5% (249 of 572 strings) Translation: pulseaudio/pulseaudio Translate-URL: https://translate.fedoraproject.org/projects/pulseaudio/pulseaudio/ka/ Part-of: --- po/ka.po | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/po/ka.po b/po/ka.po index 6a88ebfb1..33de0539d 100644 --- a/po/ka.po +++ b/po/ka.po @@ -9,7 +9,7 @@ msgstr "" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/" "issues/new\n" "POT-Creation-Date: 2022-06-18 09:49+0300\n" -"PO-Revision-Date: 2022-07-21 12:42+0000\n" +"PO-Revision-Date: 2022-07-22 13:18+0000\n" "Last-Translator: Temuri Doghonadze \n" "Language-Team: Georgian \n" @@ -491,7 +491,7 @@ msgstr "Docking Station-ის მიკროფონი" #: src/modules/alsa/alsa-mixer.c:2711 msgid "Docking Station Line In" -msgstr "Docking Station Line In" +msgstr "Docking Station-ის Line In პორტი" #: src/modules/alsa/alsa-mixer.c:2712 src/modules/alsa/alsa-mixer.c:2803 msgid "Line In" From 9f725cafb8bd4667ca0411b8c73ad90912256168 Mon Sep 17 00:00:00 2001 From: hashitaku Date: Fri, 22 Jul 2022 18:14:14 +0900 Subject: [PATCH 053/260] shell-completion: add new subcommand get-* for bash Added to shell-completion of bash as there is no completion for the subcommand get-*. Part-of: --- shell-completion/bash/pactl | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/shell-completion/bash/pactl b/shell-completion/bash/pactl index b269815d2..60d47964a 100644 --- a/shell-completion/bash/pactl +++ b/shell-completion/bash/pactl @@ -116,12 +116,13 @@ _pactl() { modules samples clients message-handlers' local commands=(stat info list exit upload-sample play-sample remove-sample load-module unload-module move-sink-input move-source-output - suspend-sink suspend-source set-card-profile set-default-sink - set-sink-port set-default-source set-source-port set-sink-volume + suspend-sink suspend-source set-card-profile get-default-sink + set-default-sink set-sink-port get-default-source set-default-source + set-source-port get-sink-volume set-sink-volume get-source-volume set-source-volume set-sink-input-volume set-source-output-volume - set-sink-mute set-source-mute set-sink-input-mute - set-source-output-mute set-sink-formats set-port-latency-offset - subscribe send-message help) + get-sink-mute set-sink-mute get-source-mute set-source-mute + set-sink-input-mute set-source-output-mute set-sink-formats + set-port-latency-offset subscribe send-message help) _init_completion -n = || return preprev=${words[$cword-2]} @@ -186,6 +187,8 @@ _pactl() { remove-sample) ;; # TODO + get-default*) ;; + load-module) comps=$(__all_modules) COMPREPLY=($(compgen -W '${comps[*]}' -- "$cur")) From ffbcf368545f2b244f23dd67130c3eae40f6b6b1 Mon Sep 17 00:00:00 2001 From: hashitaku Date: Fri, 22 Jul 2022 18:40:42 +0900 Subject: [PATCH 054/260] shell-completion: add new subcommand get-* for zsh Added to shell-completion of zsh as there is no completion for the subcommand get-*. Part-of: --- shell-completion/zsh/_pulseaudio | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/shell-completion/zsh/_pulseaudio b/shell-completion/zsh/_pulseaudio index f198014cc..aaa2ccfc0 100644 --- a/shell-completion/zsh/_pulseaudio +++ b/shell-completion/zsh/_pulseaudio @@ -18,10 +18,12 @@ _devices() { if [[ $service == pactl || $service == pacmd ]]; then case $words[$((CURRENT - 1))] in set-sink-input-*) cmd=('sink-inputs');; + get-sink-*) cmd=('sinks');; set-sink-*) cmd=('sinks');; set-default-sink) cmd=('sinks');; set-default-source) cmd=('sources');; set-source-output-*) cmd=('source-outputs');; + get-source-*) cmd=('sources');; set-source-*) cmd=('sources');; suspend-sink) cmd=('sinks');; suspend-source) cmd=('sources');; @@ -257,16 +259,22 @@ _pactl_completion() { 'suspend-sink: suspend or resume a sink' 'suspend-source: suspend or resume a source' 'set-card-profile: set a card profile' + 'get-default-sink: get the default sink' 'set-default-sink: set the default sink' + 'get-default-source: get the default source' 'set-default-source: set the default source' 'set-sink-port: set the sink port of a sink' 'set-source-port: set the source port of a source' 'set-port-latency-offset: set a latency offset on a port' + 'get-sink-volume: get the volume of a sink' 'set-sink-volume: set the volume of a sink' + 'get-source-volume: get the volume of a source' 'set-source-volume: set the volume of a source' 'set-sink-input-volume: set the volume of a stream' 'set-source-output-volume: set the volume of a recording stream' + 'get-sink-mute: get the mute status of a sink' 'set-sink-mute: mute a sink' + 'get-source-mute: get the mute status of a source' 'set-source-mute: mute a source' 'set-sink-input-mute: mute a stream' 'set-source-output-mute: mute a recording stream' @@ -492,11 +500,15 @@ _pactl_completion() { set-default-source) if ((CURRENT == 2)); then _devices; fi;; set-sink-port) _set_sink_port_parameter;; set-source-port) _set_source_port_parameter;; + get-sink-volume) if ((CURRENT == 2)); then _devices; fi;; set-sink-volume) if ((CURRENT == 2)); then _devices; fi;; + get-source-volume) if ((CURRENT == 2)); then _devices; fi;; set-source-volume) if ((CURRENT == 2)); then _devices; fi;; set-sink-input-volume) if ((CURRENT == 2)); then _devices; fi;; set-source-output-volume) if ((CURRENT == 2)); then _devices; fi;; + get-sink-mute) if ((CURRENT == 2)); then _devices; fi;; set-sink-mute) _set_sink_mute_parameter;; + get-source-mute) if ((CURRENT == 2)); then _devices; fi;; set-source-mute) _set_source_mute_parameter;; set-sink-input-mute) _set_sink_input_mute_parameter;; set-source-output-mute) _set_source_output_mute_parameter;; From ff6010b80f1cf8ebeabaea8b8fc3fc53aa2bd7a1 Mon Sep 17 00:00:00 2001 From: Rosen Penev Date: Tue, 26 Jul 2022 19:22:09 -0700 Subject: [PATCH 055/260] meson: fix meson warnings Signed-off-by: Rosen Penev Part-of: --- meson.build | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index c5135330f..132f35c92 100644 --- a/meson.build +++ b/meson.build @@ -1,10 +1,12 @@ project('pulseaudio', 'c', 'cpp', - version : run_command(find_program('git-version-gen'), join_paths(meson.current_source_dir(), '.tarball-version')).stdout().strip(), + version : run_command(find_program('git-version-gen'), join_paths(meson.current_source_dir(), '.tarball-version'), check : false).stdout().strip(), meson_version : '>= 0.50.0', default_options : [ 'c_std=gnu11', 'cpp_std=c++11' ] ) -meson.add_dist_script('scripts/save-tarball-version.sh', meson.project_version()) +if not meson.is_subproject() + meson.add_dist_script('scripts/save-tarball-version.sh', meson.project_version()) +endif pa_version_str = meson.project_version() # For tarballs, the first split will do nothing, but for builds in git, we From b05e34e092d5f40ff9a305fea181bd2308829824 Mon Sep 17 00:00:00 2001 From: Dylan Van Assche Date: Wed, 6 Apr 2022 08:15:13 +0200 Subject: [PATCH 056/260] bluez5-util: move pa_bluetooth_discovery to header Part-of: --- src/modules/bluetooth/bluez5-util.c | 23 ----------------------- src/modules/bluetooth/bluez5-util.h | 24 ++++++++++++++++++++++++ src/modules/meson.build | 2 +- 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/modules/bluetooth/bluez5-util.c b/src/modules/bluetooth/bluez5-util.c index 596f008cb..6ac4c2e7c 100644 --- a/src/modules/bluetooth/bluez5-util.c +++ b/src/modules/bluetooth/bluez5-util.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -128,28 +127,6 @@ static uint16_t volume_to_a2dp_gain(pa_volume_t volume) { return gain; } -struct pa_bluetooth_discovery { - PA_REFCNT_DECLARE; - - pa_core *core; - pa_dbus_connection *connection; - bool filter_added; - bool matches_added; - bool objects_listed; - pa_hook hooks[PA_BLUETOOTH_HOOK_MAX]; - pa_hashmap *adapters; - pa_hashmap *devices; - pa_hashmap *transports; - pa_bluetooth_profile_status_t profiles_status[PA_BLUETOOTH_PROFILE_COUNT]; - - int headset_backend; - pa_bluetooth_backend *ofono_backend, *native_backend; - PA_LLIST_HEAD(pa_dbus_pending, pending); - bool enable_native_hsp_hs; - bool enable_native_hfp_hf; - bool enable_msbc; -}; - static pa_dbus_pending* send_and_add_to_pending(pa_bluetooth_discovery *y, DBusMessage *m, DBusPendingCallNotifyFunction func, void *call_data) { pa_dbus_pending *p; diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h index 86eb6301e..f899d9d0c 100644 --- a/src/modules/bluetooth/bluez5-util.h +++ b/src/modules/bluetooth/bluez5-util.h @@ -22,6 +22,7 @@ ***/ #include +#include #include "a2dp-codec-util.h" @@ -134,6 +135,29 @@ struct pa_bluetooth_transport { void *userdata; }; +struct pa_bluetooth_discovery { + PA_REFCNT_DECLARE; + + pa_core *core; + pa_dbus_connection *connection; + bool filter_added; + bool matches_added; + bool objects_listed; + pa_hook hooks[PA_BLUETOOTH_HOOK_MAX]; + pa_hashmap *adapters; + pa_hashmap *devices; + pa_hashmap *transports; + pa_bluetooth_profile_status_t profiles_status[PA_BLUETOOTH_PROFILE_COUNT]; + + int headset_backend; + pa_bluetooth_backend *ofono_backend, *native_backend; + PA_LLIST_HEAD(pa_dbus_pending, pending); + bool enable_native_hsp_hs; + bool enable_native_hfp_hf; + bool enable_msbc; +}; + + struct pa_bluetooth_device { pa_bluetooth_discovery *discovery; pa_bluetooth_adapter *adapter; diff --git a/src/modules/meson.build b/src/modules/meson.build index 1e12569dc..c4e53d6d9 100644 --- a/src/modules/meson.build +++ b/src/modules/meson.build @@ -123,7 +123,7 @@ if cdata.has('HAVE_BLUEZ_5') all_modules += [ [ 'module-bluetooth-discover', 'bluetooth/module-bluetooth-discover.c' ], [ 'module-bluetooth-policy', 'bluetooth/module-bluetooth-policy.c', [], [], [dbus_dep] ], - [ 'module-bluez5-device', 'bluetooth/module-bluez5-device.c', [], [], [], libbluez5_util ], + [ 'module-bluez5-device', 'bluetooth/module-bluez5-device.c', [], [], [dbus_dep], libbluez5_util ], [ 'module-bluez5-discover', 'bluetooth/module-bluez5-discover.c', [], [], [dbus_dep], libbluez5_util ], ] endif From cca0d69375f590c203a53edb084299aeab564648 Mon Sep 17 00:00:00 2001 From: Dylan Van Assche Date: Tue, 5 Apr 2022 20:10:05 +0200 Subject: [PATCH 057/260] bluetooth: add AT+BIA support AT+BIA is used to enable/disable CIND indicators by Bluetooth HFP spec. By default, all indicators are enabled on connection. AT+BIA will configure which indicators should be disabled then, the disabled indicators may be enabled later on again with AT+BIA. When the connection is lost and recovered, all indicators are enabled again. The HF will reconfigure the indicators again with an AT+BIA command. Part-of: --- src/modules/bluetooth/backend-native.c | 98 +++++++++++++++++++++++--- 1 file changed, 89 insertions(+), 9 deletions(-) diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c index f6b85e90d..26156353f 100644 --- a/src/modules/bluetooth/backend-native.c +++ b/src/modules/bluetooth/backend-native.c @@ -39,6 +39,11 @@ #include "bluez5-util.h" #include "bt-codec-msbc.h" +#define MANDATORY_CALL_INDICATORS \ + "(\"call\",(0-1))," \ + "(\"callsetup\",(0-3))," \ + "(\"callheld\",(0-2))" \ + struct pa_bluetooth_backend { pa_core *core; pa_dbus_connection *connection; @@ -47,6 +52,8 @@ struct pa_bluetooth_backend { bool enable_shared_profiles; bool enable_hsp_hs; bool enable_hfp_hf; + bool cmer_indicator_reporting_enabled; + uint32_t cind_enabled_indicators; PA_LLIST_HEAD(pa_dbus_pending, pending); }; @@ -97,6 +104,20 @@ enum hfp_ag_features { HFP_AG_INDICATORS = 10, }; +/* + * Always keep this struct in sync with indicator discovery of AT+CIND=? + * These indicators are used in bitflags and intentionally start at 1 + * since AT+CIND indicators start at index 1. + */ +typedef enum pa_bluetooth_ag_to_hf_indicators { + CIND_CALL_INDICATOR = 1, + CIND_CALL_SETUP_INDICATOR = 2, + CIND_CALL_HELD_INDICATOR = 3, + CIND_SERVICE_INDICATOR = 4, + CIND_BATT_CHG_INDICATOR = 5, + CIND_INDICATOR_MAX = 6 +} pa_bluetooth_ag_to_hf_indicators_t; + /* gateway features we support, which is as little as we can get away with */ static uint32_t hfp_features = /* HFP 1.6 requires this */ @@ -588,12 +609,13 @@ static pa_volume_t set_source_volume(pa_bluetooth_transport *t, pa_volume_t volu static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf) { + struct pa_bluetooth_discovery *discovery = t->device->discovery; struct hfp_config *c = t->config; - int indicator, val; + int indicator, mode, val; char str[5]; const char *r; size_t len; - const char *state; + const char *state = NULL; /* first-time initialize selected codec to CVSD */ if (c->selected_codec == 0) @@ -608,11 +630,38 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf c->state = 1; return true; + } else if (sscanf(buf, "AT+BIA=%s", str) == 1) { + /* Indicators start with index 1 and follow the order of the AT+CIND=? response */ + indicator = 1; + + while ((r = pa_split_in_place(str, ",", &len, &state))) { + /* Ignore updates to mandantory indicators which are always ON */ + if (indicator == CIND_CALL_INDICATOR + || indicator == CIND_CALL_SETUP_INDICATOR + || indicator == CIND_CALL_HELD_INDICATOR) + continue; + + /* Indicators may have no value and should be skipped */ + if (len == 0) + continue; + + if (len == 1 && r[0] == '1') + discovery->native_backend->cind_enabled_indicators |= (1 << indicator); + else if (len == 1 && r[0] == '0') + discovery->native_backend->cind_enabled_indicators &= ~(1 << indicator); + else { + pa_log_error("Unable to parse indicator of AT+BIA command: %s", buf); + rfcomm_write_response(fd, "ERROR"); + return false; + } + + indicator++; + } + + return true; } else if (sscanf(buf, "AT+BAC=%3s", str) == 1) { c->support_msbc = false; - state = NULL; - /* check if codec id 2 (mSBC) is in the list of supported codecs */ while ((r = pa_split_in_place(str, ",", &len, &state))) { if (len == 1 && r[0] == '2') { @@ -637,10 +686,8 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf rfcomm_write_response(fd, "+CIND: " /* many indicators can be supported, only call and * callheld are mandatory, so that's all we reply */ - "(\"service\",(0-1))," - "(\"call\",(0-1))," - "(\"callsetup\",(0-3))," - "(\"callheld\",(0-2))"); + MANDATORY_CALL_INDICATORS ",", + "(\"service\",(0-1))"); c->state = 2; return true; @@ -650,7 +697,24 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf return true; } else if ((c->state == 2 || c->state == 3) && pa_startswith(buf, "AT+CMER=")) { - rfcomm_write_response(fd, "OK"); + if (sscanf(buf, "AT+CMER=%d,%*d,%*d,%d", &mode, &val) == 2) { + /* Bluetooth HFP spec only defines mode == 3 */ + if (mode != 3) { + pa_log_warn("Unexpected mode for AT+CMER: %d", mode); + } + + /* Configure CMER event reporting */ + discovery->native_backend->cmer_indicator_reporting_enabled = !!val; + + pa_log_debug("Event indications enabled? %s", pa_yes_no(val)); + + rfcomm_write_response(fd, "OK"); + } + else { + pa_log_error("Unable to parse AT+CMER command: %s", buf); + rfcomm_write_response(fd, "ERROR"); + return false; + } if (c->support_codec_negotiation) { if (c->support_msbc && pa_bluetooth_discovery_get_enable_msbc(t->device->discovery)) { @@ -740,6 +804,8 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf static void rfcomm_io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) { pa_bluetooth_transport *t = userdata; + pa_bluetooth_discovery *discovery = t->device->discovery; + int i; pa_assert(io); pa_assert(t); @@ -860,6 +926,11 @@ static void rfcomm_io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_i return; fail: + /* Service Connection lost, reset indicators and event reporting to default values */ + discovery->native_backend->cmer_indicator_reporting_enabled = false; + for (i = 1; i < CIND_INDICATOR_MAX; i++) + discovery->native_backend->cind_enabled_indicators |= (1 << i); + pa_bluetooth_transport_unlink(t); pa_bluetooth_transport_free(t); } @@ -1188,6 +1259,7 @@ void pa_bluetooth_native_backend_enable_shared_profiles(pa_bluetooth_backend *na pa_bluetooth_backend *pa_bluetooth_native_backend_new(pa_core *c, pa_bluetooth_discovery *y, bool enable_shared_profiles) { pa_bluetooth_backend *backend; DBusError err; + int i; pa_log_debug("Bluetooth Headset Backend API support using the native backend"); @@ -1220,6 +1292,14 @@ pa_bluetooth_backend *pa_bluetooth_native_backend_new(pa_core *c, pa_bluetooth_d if (backend->enable_shared_profiles) native_backend_apply_profile_registration_change(backend, true); + /* All CIND indicators are enabled by default until overriden by AT+BIA */ + for (i = 1; i < CIND_INDICATOR_MAX; i++) + backend->cind_enabled_indicators |= (1 << i); + + /* While all CIND indicators are enabled, event reporting is not enabled by default */ + backend->cmer_indicator_reporting_enabled = false; + + return backend; } From 3621731050b9c38f8bd25a2746e7aa64ddeda837 Mon Sep 17 00:00:00 2001 From: Dylan Van Assche Date: Tue, 5 Apr 2022 20:26:09 +0200 Subject: [PATCH 058/260] bluetooth: add UPower backend UPower provides information about the power supply and battery level of the host. Add a backend to retrieve the host battery level. Part-of: --- src/modules/bluetooth/meson.build | 4 +- src/modules/bluetooth/upower.c | 300 ++++++++++++++++++++++++++++++ src/modules/bluetooth/upower.h | 39 ++++ 3 files changed, 342 insertions(+), 1 deletion(-) create mode 100644 src/modules/bluetooth/upower.c create mode 100644 src/modules/bluetooth/upower.h diff --git a/src/modules/bluetooth/meson.build b/src/modules/bluetooth/meson.build index ca77ee6aa..0703d5086 100644 --- a/src/modules/bluetooth/meson.build +++ b/src/modules/bluetooth/meson.build @@ -16,6 +16,8 @@ libbluez5_util_headers = [ if get_option('bluez5-native-headset') libbluez5_util_sources += [ 'backend-native.c' ] + libbluez5_util_sources += [ 'upower.c' ] + libbluez5_util_headers += [ 'upower.h' ] endif if get_option('bluez5-ofono-headset') @@ -35,7 +37,7 @@ libbluez5_util = shared_library('bluez5-util', c_args : [pa_c_args, server_c_args], link_args : [nodelete_link_args], include_directories : [configinc, topinc], - dependencies : [libpulse_dep, libpulsecommon_dep, libpulsecore_dep, bluez_dep, dbus_dep, sbc_dep, libintl_dep, bluez5_gst_dep, bluez5_gstapp_dep], + dependencies : [libpulse_dep, libpulsecommon_dep, libpulsecore_dep, bluez_dep, dbus_dep, sbc_dep, libintl_dep, bluez5_gst_dep, bluez5_gstapp_dep, libm_dep], install : true, install_rpath : privlibdir, install_dir : modlibexecdir, diff --git a/src/modules/bluetooth/upower.c b/src/modules/bluetooth/upower.c new file mode 100644 index 000000000..eb60d0c7b --- /dev/null +++ b/src/modules/bluetooth/upower.c @@ -0,0 +1,300 @@ +/*** + This file is part of PulseAudio. + + Copyright 2022 Dylan Van Assche + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, see . +***/ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "upower.h" + +static pa_dbus_pending* send_and_add_to_pending(pa_upower_backend *backend, DBusMessage *m, + DBusPendingCallNotifyFunction func, void *call_data) { + + pa_dbus_pending *p; + DBusPendingCall *call; + + pa_assert(backend); + pa_assert(m); + + pa_assert_se(dbus_connection_send_with_reply(pa_dbus_connection_get(backend->connection), m, &call, -1)); + + p = pa_dbus_pending_new(pa_dbus_connection_get(backend->connection), m, call, backend, call_data); + PA_LLIST_PREPEND(pa_dbus_pending, backend->pending, p); + dbus_pending_call_set_notify(call, func, p, NULL); + + return p; +} + +static void parse_percentage(pa_upower_backend *b, DBusMessageIter *i) { + double percentage; + unsigned int battery_level; + + pa_assert(i); + pa_assert(dbus_message_iter_get_arg_type(i) == DBUS_TYPE_DOUBLE); + + dbus_message_iter_get_basic(i, &percentage); + battery_level = (unsigned int) round(percentage / 20.0); + + if (battery_level != b->battery_level) { + b->battery_level = battery_level; + pa_log_debug("AG battery level updated (%d/5)", b->battery_level); + pa_hook_fire(pa_bluetooth_discovery_hook(b->discovery, PA_BLUETOOTH_HOOK_HOST_BATTERY_LEVEL_CHANGED), b); + } +} + +static void get_percentage_reply(DBusPendingCall *pending, void *userdata) { + pa_dbus_pending *p; + pa_upower_backend *b; + DBusMessage *r; + DBusMessageIter arg_i, variant_i; + + pa_assert(pending); + pa_assert_se(p = userdata); + pa_assert_se(b = p->context_data); + pa_assert_se(r = dbus_pending_call_steal_reply(pending)); + + if (dbus_message_is_error(r, DBUS_ERROR_UNKNOWN_METHOD)) { + pa_log_warn("UPower D-Bus Display Device not available"); + goto finish; + } + + if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) { + pa_log_error("Get() failed: %s: %s", dbus_message_get_error_name(r), pa_dbus_get_error_message(r)); + goto finish; + } + + if (!dbus_message_iter_init(r, &arg_i) || !pa_streq(dbus_message_get_signature(r), "v")) { + pa_log_error("Invalid reply signature for Get()"); + goto finish; + } + + dbus_message_iter_recurse(&arg_i, &variant_i); + parse_percentage(b, &variant_i); + +finish: + dbus_message_unref(r); + + PA_LLIST_REMOVE(pa_dbus_pending, b->pending, p); + pa_dbus_pending_free(p); +} + +static const char *check_variant_property(DBusMessageIter *i) { + const char *key; + + pa_assert(i); + + if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING) { + pa_log_error("Property name not a string."); + return NULL; + } + + dbus_message_iter_get_basic(i, &key); + + if (!dbus_message_iter_next(i)) { + pa_log_error("Property value missing"); + return NULL; + } + + if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_VARIANT) { + pa_log_error("Property value not a variant."); + return NULL; + } + + return key; +} + +static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *data) { + DBusError err; + DBusMessage *m2; + static const char* upower_device_interface = UPOWER_SERVICE UPOWER_DEVICE_INTERFACE; + static const char* percentage_property = "Percentage"; + pa_upower_backend *b = data; + const char *path, *interface, *member; + + pa_assert(bus); + pa_assert(m); + pa_assert(b); + + dbus_error_init(&err); + + path = dbus_message_get_path(m); + interface = dbus_message_get_interface(m); + member = dbus_message_get_member(m); + + pa_log_debug("dbus: path=%s, interface=%s, member=%s", path, interface, member); + + /* UPower D-Bus status change */ + if (dbus_message_is_signal(m, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) { + const char *name, *old_owner, *new_owner; + + if (!dbus_message_get_args(m, &err, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_STRING, &old_owner, + DBUS_TYPE_STRING, &new_owner, + DBUS_TYPE_INVALID)) { + pa_log_error("Failed to parse " DBUS_INTERFACE_DBUS ".NameOwnerChanged: %s", err.message); + goto fail; + } + + if (pa_streq(name, UPOWER_SERVICE)) { + + /* UPower disappeared from D-Bus */ + if (old_owner && *old_owner) { + pa_log_debug("UPower disappeared from D-Bus"); + b->battery_level = 0; + pa_hook_fire(pa_bluetooth_discovery_hook(b->discovery, PA_BLUETOOTH_HOOK_HOST_BATTERY_LEVEL_CHANGED), b); + } + + /* UPower appeared on D-Bus */ + if (new_owner && *new_owner) { + pa_log_debug("UPower appeared on D-Bus"); + + /* Update battery level */ + pa_assert_se(m2 = dbus_message_new_method_call(UPOWER_SERVICE, UPOWER_DISPLAY_DEVICE_OBJECT, DBUS_INTERFACE_PROPERTIES, "Get")); + pa_assert_se(dbus_message_append_args(m2, + DBUS_TYPE_STRING, &upower_device_interface, + DBUS_TYPE_STRING, &percentage_property, + DBUS_TYPE_INVALID)); + send_and_add_to_pending(b, m2, get_percentage_reply, NULL); + } + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + /* UPower battery level property updates */ + } else if (dbus_message_is_signal(m, DBUS_INTERFACE_PROPERTIES, "PropertiesChanged")) { + DBusMessageIter arg_i, element_i; + + if (!dbus_message_iter_init(m, &arg_i) || !pa_streq(dbus_message_get_signature(m), "sa{sv}as")) { + pa_log_error("Invalid signature found in PropertiesChanged"); + goto fail; + } + + /* Skip interface name */ + pa_assert_se(dbus_message_iter_next(&arg_i)); + pa_assert(dbus_message_iter_get_arg_type(&arg_i) == DBUS_TYPE_ARRAY); + + dbus_message_iter_recurse(&arg_i, &element_i); + + /* Parse UPower property updates */ + while (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_DICT_ENTRY) { + DBusMessageIter dict_i, variant_i; + const char *key; + + dbus_message_iter_recurse(&element_i, &dict_i); + + /* Retrieve property name */ + key = check_variant_property(&dict_i); + if (key == NULL) { + pa_log_error("Received invalid property!"); + break; + } + + dbus_message_iter_recurse(&dict_i, &variant_i); + + if(pa_streq(path, UPOWER_DISPLAY_DEVICE_OBJECT)) { + pa_log_debug("UPower Device property updated: %s", key); + + if(pa_streq(key, "Percentage")) + parse_percentage(b, &variant_i); + } + + dbus_message_iter_next(&element_i); + } + } + +fail: + dbus_error_free(&err); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +unsigned int pa_upower_get_battery_level(pa_upower_backend *backend) { + return backend->battery_level; +} + +pa_upower_backend *pa_upower_backend_new(pa_core *c, pa_bluetooth_discovery *d) { + pa_upower_backend *backend; + DBusError err; + DBusMessage *m; + static const char* upower_device_interface = UPOWER_SERVICE UPOWER_DEVICE_INTERFACE; + static const char* percentage_property = "Percentage"; + + pa_log_debug("Native backend enabled UPower battery status reporting"); + + backend = pa_xnew0(pa_upower_backend, 1); + backend->core = c; + backend->discovery = d; + + /* Get DBus connection */ + dbus_error_init(&err); + if (!(backend->connection = pa_dbus_bus_get(c, DBUS_BUS_SYSTEM, &err))) { + pa_log("Failed to get D-Bus connection: %s", err.message); + dbus_error_free(&err); + pa_xfree(backend); + return NULL; + } + + /* Add filter callback for DBus connection */ + if (!dbus_connection_add_filter(pa_dbus_connection_get(backend->connection), filter_cb, backend, NULL)) { + pa_log_error("Failed to add filter function"); + pa_dbus_connection_unref(backend->connection); + pa_xfree(backend); + return NULL; + } + + /* Register for battery level changes from UPower */ + if (pa_dbus_add_matches(pa_dbus_connection_get(backend->connection), &err, + "type='signal',sender='" DBUS_SERVICE_DBUS "',interface='" DBUS_INTERFACE_DBUS "',member='NameOwnerChanged'," + "arg0='" UPOWER_SERVICE "'", + "type='signal',sender='" UPOWER_SERVICE "',interface='" DBUS_INTERFACE_PROPERTIES "',member='PropertiesChanged'", + NULL) < 0) { + pa_log("Failed to add UPower D-Bus matches: %s", err.message); + dbus_connection_remove_filter(pa_dbus_connection_get(backend->connection), filter_cb, backend); + pa_dbus_connection_unref(backend->connection); + pa_xfree(backend); + return NULL; + } + + /* Initialize battery level by requesting it from UPower */ + pa_assert_se(m = dbus_message_new_method_call(UPOWER_SERVICE, UPOWER_DISPLAY_DEVICE_OBJECT, DBUS_INTERFACE_PROPERTIES, "Get")); + pa_assert_se(dbus_message_append_args(m, + DBUS_TYPE_STRING, &upower_device_interface, + DBUS_TYPE_STRING, &percentage_property, + DBUS_TYPE_INVALID)); + send_and_add_to_pending(backend, m, get_percentage_reply, NULL); + + return backend; +} + +void pa_upower_backend_free(pa_upower_backend *backend) { + pa_assert(backend); + + pa_dbus_free_pending_list(&backend->pending); + + pa_dbus_connection_unref(backend->connection); + + pa_xfree(backend); +} + diff --git a/src/modules/bluetooth/upower.h b/src/modules/bluetooth/upower.h new file mode 100644 index 000000000..e9a82c68c --- /dev/null +++ b/src/modules/bluetooth/upower.h @@ -0,0 +1,39 @@ +#pragma once + +/*** + This file is part of PulseAudio. + + Copyright 2022 Dylan Van Assche + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, see . +***/ + +#include "bluez5-util.h" + +#define UPOWER_SERVICE "org.freedesktop.UPower" +#define UPOWER_DEVICE_INTERFACE ".Device" +#define UPOWER_DISPLAY_DEVICE_OBJECT "/org/freedesktop/UPower/devices/DisplayDevice" + +struct pa_upower_backend { + pa_core *core; + pa_dbus_connection *connection; + pa_bluetooth_discovery *discovery; + unsigned int battery_level; + + PA_LLIST_HEAD(pa_dbus_pending, pending); +}; + +pa_upower_backend *pa_upower_backend_new(pa_core *c, pa_bluetooth_discovery *d); +void pa_upower_backend_free(pa_upower_backend *backend); +unsigned int pa_upower_get_battery_level(pa_upower_backend *backend); From 1b031ecee69142c4b0ff6ea9767c0cabb61af144 Mon Sep 17 00:00:00 2001 From: Dylan Van Assche Date: Tue, 5 Apr 2022 20:39:11 +0200 Subject: [PATCH 059/260] bluetooth: hook up UPower backend Hook up the UPower backend to backend-native to report the host battery level to the HF. Part-of: --- src/modules/bluetooth/backend-native.c | 91 ++++++++++++++++++++++++-- src/modules/bluetooth/bluez5-util.h | 2 + 2 files changed, 86 insertions(+), 7 deletions(-) diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c index 26156353f..bc57fb2f7 100644 --- a/src/modules/bluetooth/backend-native.c +++ b/src/modules/bluetooth/backend-native.c @@ -38,6 +38,7 @@ #include "bluez5-util.h" #include "bt-codec-msbc.h" +#include "upower.h" #define MANDATORY_CALL_INDICATORS \ "(\"call\",(0-1))," \ @@ -49,6 +50,8 @@ struct pa_bluetooth_backend { pa_dbus_connection *connection; pa_bluetooth_discovery *discovery; pa_hook_slot *adapter_uuids_changed_slot; + pa_hook_slot *host_battery_level_changed_slot; + pa_upower_backend *upower; bool enable_shared_profiles; bool enable_hsp_hs; bool enable_hfp_hf; @@ -682,17 +685,27 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf return true; } else if (c->state == 1 && pa_startswith(buf, "AT+CIND=?")) { - /* we declare minimal no indicators */ - rfcomm_write_response(fd, "+CIND: " - /* many indicators can be supported, only call and - * callheld are mandatory, so that's all we reply */ - MANDATORY_CALL_INDICATORS ",", - "(\"service\",(0-1))"); + /* UPower backend available, declare support for more indicators */ + if (discovery->native_backend->upower) { + rfcomm_write_response(fd, "+CIND: " + MANDATORY_CALL_INDICATORS "," + "(\"service\",(0-1))," + "(\"battchg\",(0-5))"); + + /* Minimal indicators supported without any additional backend */ + } else { + rfcomm_write_response(fd, "+CIND: " + MANDATORY_CALL_INDICATORS "," + "(\"service\",(0-1))"); + } c->state = 2; return true; } else if (c->state == 2 && pa_startswith(buf, "AT+CIND?")) { - rfcomm_write_response(fd, "+CIND: 0,0,0,0"); + if (discovery->native_backend->upower) + rfcomm_write_response(fd, "+CIND: 0,0,0,0,%u", pa_upower_get_battery_level(discovery->native_backend->upower)); + else + rfcomm_write_response(fd, "+CIND: 0,0,0,0"); c->state = 3; return true; @@ -802,6 +815,58 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf return true; } +static int get_rfcomm_fd (pa_bluetooth_discovery *discovery) { + struct pa_bluetooth_transport *t; + struct transport_data *trd = NULL; + void *state = NULL; + + /* Find RFCOMM transport by checking if a HSP or HFP profile transport is available */ + while ((t = pa_hashmap_iterate(discovery->transports, &state, NULL))) { + /* Skip non-connected transports */ + if (!t || t->state == PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED) { + pa_log_debug("Profile disconnected or unavailable"); + continue; + } + + /* Break when an RFCOMM capable transport profile is available */ + if (t->profile == PA_BLUETOOTH_PROFILE_HFP_HF) { + trd = t->userdata; + break; + } + } + + /* Skip if RFCOMM channel is not available yet */ + if (!trd) { + pa_log_info("RFCOMM not available yet, skipping notification"); + return -1; + } + + return trd->rfcomm_fd; +} + +static pa_hook_result_t host_battery_level_changed_cb(pa_bluetooth_discovery *y, const pa_upower_backend *u, pa_bluetooth_backend *b) { + int rfcomm_fd; + + pa_assert(y); + pa_assert(u); + pa_assert(b); + + /* Get RFCOMM channel if available */ + rfcomm_fd = get_rfcomm_fd (y); + if (rfcomm_fd < 0) + return PA_HOOK_OK; + + /* Notify HF about AG battery level change over RFCOMM */ + if (b->cmer_indicator_reporting_enabled && (b->cind_enabled_indicators & (1 << CIND_BATT_CHG_INDICATOR))) { + rfcomm_write_response(rfcomm_fd, "+CIEV: %d,%d", CIND_BATT_CHG_INDICATOR, u->battery_level); + pa_log_debug("HG notified of AG's battery level change"); + /* Skip notification if indicator is disabled or event reporting is completely disabled */ + } else + pa_log_debug("Battery level change indicator disabled, skipping notification"); + + return PA_HOOK_OK; +} + static void rfcomm_io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) { pa_bluetooth_transport *t = userdata; pa_bluetooth_discovery *discovery = t->device->discovery; @@ -1283,6 +1348,10 @@ pa_bluetooth_backend *pa_bluetooth_native_backend_new(pa_core *c, pa_bluetooth_d pa_hook_connect(pa_bluetooth_discovery_hook(y, PA_BLUETOOTH_HOOK_ADAPTER_UUIDS_CHANGED), PA_HOOK_NORMAL, (pa_hook_cb_t) adapter_uuids_changed_cb, backend); + backend->host_battery_level_changed_slot = + pa_hook_connect(pa_bluetooth_discovery_hook(y, PA_BLUETOOTH_HOOK_HOST_BATTERY_LEVEL_CHANGED), PA_HOOK_NORMAL, + (pa_hook_cb_t) host_battery_level_changed_cb, backend); + if (!backend->enable_hsp_hs && !backend->enable_hfp_hf) pa_log_warn("Both HSP HS and HFP HF bluetooth profiles disabled in native backend. Native backend will not register for headset connections."); @@ -1292,6 +1361,8 @@ pa_bluetooth_backend *pa_bluetooth_native_backend_new(pa_core *c, pa_bluetooth_d if (backend->enable_shared_profiles) native_backend_apply_profile_registration_change(backend, true); + backend->upower = pa_upower_backend_new(c, y); + /* All CIND indicators are enabled by default until overriden by AT+BIA */ for (i = 1; i < CIND_INDICATOR_MAX; i++) backend->cind_enabled_indicators |= (1 << i); @@ -1311,12 +1382,18 @@ void pa_bluetooth_native_backend_free(pa_bluetooth_backend *backend) { if (backend->adapter_uuids_changed_slot) pa_hook_slot_free(backend->adapter_uuids_changed_slot); + if (backend->host_battery_level_changed_slot) + pa_hook_slot_free(backend->host_battery_level_changed_slot); + if (backend->enable_shared_profiles) native_backend_apply_profile_registration_change(backend, false); if (backend->enable_hsp_hs) profile_done(backend, PA_BLUETOOTH_PROFILE_HSP_HS); + if (backend->upower) + pa_upower_backend_free(backend->upower); + pa_dbus_connection_unref(backend->connection); pa_xfree(backend); diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h index f899d9d0c..a24a0b823 100644 --- a/src/modules/bluetooth/bluez5-util.h +++ b/src/modules/bluetooth/bluez5-util.h @@ -63,12 +63,14 @@ typedef struct pa_bluetooth_device pa_bluetooth_device; typedef struct pa_bluetooth_adapter pa_bluetooth_adapter; typedef struct pa_bluetooth_discovery pa_bluetooth_discovery; typedef struct pa_bluetooth_backend pa_bluetooth_backend; +typedef struct pa_upower_backend pa_upower_backend; typedef enum pa_bluetooth_hook { PA_BLUETOOTH_HOOK_ADAPTER_UUIDS_CHANGED, /* Call data: pa_bluetooth_adapter */ PA_BLUETOOTH_HOOK_DEVICE_CONNECTION_CHANGED, /* Call data: pa_bluetooth_device */ PA_BLUETOOTH_HOOK_DEVICE_UNLINK, /* Call data: pa_bluetooth_device */ PA_BLUETOOTH_HOOK_DEVICE_BATTERY_LEVEL_CHANGED, /* Call data: pa_bluetooth_device */ + PA_BLUETOOTH_HOOK_HOST_BATTERY_LEVEL_CHANGED, /* Call data: pa_upower_backend */ PA_BLUETOOTH_HOOK_TRANSPORT_STATE_CHANGED, /* Call data: pa_bluetooth_transport */ PA_BLUETOOTH_HOOK_TRANSPORT_SOURCE_VOLUME_CHANGED, /* Call data: pa_bluetooth_transport */ PA_BLUETOOTH_HOOK_TRANSPORT_SINK_VOLUME_CHANGED, /* Call data: pa_bluetooth_transport */ From c789bc5fe37d45e0a16b1b062b262785d25d2dfc Mon Sep 17 00:00:00 2001 From: Fabrice Fontaine Date: Mon, 25 Jul 2022 21:49:25 +0200 Subject: [PATCH 060/260] meson.build: fix build without C++ Fix the following build failure without C++: ../output-1/build/pulseaudio-16.1/meson.build:1:0: ERROR: Unknown compiler(s): [['/home/autobuild/autobuild/instance-1/output-1/per-package/pulseaudio/host/bin/powerpc64-buildroot-linux-gnu-g++']] The following exception(s) were encountered: Running "/home/autobuild/autobuild/instance-1/output-1/per-package/pulseaudio/host/bin/powerpc64-buildroot-linux-gnu-g++ --version" gave "[Errno 2] No such file or directory: '/home/autobuild/autobuild/instance-1/output-1/per-package/pulseaudio/host/bin/powerpc64-buildroot-linux-gnu-g++'" Fixes: - http://autobuild.buildroot.org/results/6526a21bd4da3b8458188f27c1ec04c381e4b673 Signed-off-by: Fabrice Fontaine Part-of: --- meson.build | 3 ++- src/modules/echo-cancel/meson.build | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 132f35c92..90f1ede61 100644 --- a/meson.build +++ b/meson.build @@ -1,4 +1,4 @@ -project('pulseaudio', 'c', 'cpp', +project('pulseaudio', 'c', version : run_command(find_program('git-version-gen'), join_paths(meson.current_source_dir(), '.tarball-version'), check : false).stdout().strip(), meson_version : '>= 0.50.0', default_options : [ 'c_std=gnu11', 'cpp_std=c++11' ] @@ -435,6 +435,7 @@ endif # Code coverage if get_option('gcov') + add_languages('cpp') add_project_arguments('--coverage', language: ['c', 'cpp']) add_project_link_arguments('--coverage', language: ['c', 'cpp']) endif diff --git a/src/modules/echo-cancel/meson.build b/src/modules/echo-cancel/meson.build index 641cd35e7..3b998364e 100644 --- a/src/modules/echo-cancel/meson.build +++ b/src/modules/echo-cancel/meson.build @@ -6,6 +6,8 @@ # '-Wl,--unresolved-symbols=ignore-in-object-files' otherwise it fails # at link time. +add_languages('cpp') + libwebrtc_util_sources = [ 'webrtc.cc' ] From de8b0c11242a49c335abdae292d0bb9f6d71d2dd Mon Sep 17 00:00:00 2001 From: Yureka Date: Mon, 11 Jul 2022 12:17:18 +0200 Subject: [PATCH 061/260] Make gio-2.0 optional when gsettings is disabled Part-of: --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 90f1ede61..9f47b2f02 100644 --- a/meson.build +++ b/meson.build @@ -686,7 +686,7 @@ if get_option('daemon') cdata.set('HAVE_ALSA_UCM', 1) endif - gio_dep = dependency('gio-2.0', version : '>= 2.26.0') + gio_dep = dependency('gio-2.0', version : '>= 2.26.0', required : false) if get_option('gsettings').enabled() assert(gio_dep.found(), 'GSettings support needs glib I/O library (GIO)') cdata.set('HAVE_GSETTINGS', 1) From c6bd6656a2eb141685f94e7e9015187bba6027ec Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Tue, 2 Aug 2022 11:35:14 +0200 Subject: [PATCH 062/260] backend-native: Fix indentation and whitespace style Replace tabs with spaces, remove trailing whitespace, remove bracing around single-line `if` blocks. Part-of: --- src/modules/bluetooth/backend-native.c | 41 +++++++++++++------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c index bc57fb2f7..5b1912a86 100644 --- a/src/modules/bluetooth/backend-native.c +++ b/src/modules/bluetooth/backend-native.c @@ -638,10 +638,10 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf indicator = 1; while ((r = pa_split_in_place(str, ",", &len, &state))) { - /* Ignore updates to mandantory indicators which are always ON */ - if (indicator == CIND_CALL_INDICATOR + /* Ignore updates to mandatory indicators which are always ON */ + if (indicator == CIND_CALL_INDICATOR || indicator == CIND_CALL_SETUP_INDICATOR - || indicator == CIND_CALL_HELD_INDICATOR) + || indicator == CIND_CALL_HELD_INDICATOR) continue; /* Indicators may have no value and should be skipped */ @@ -652,16 +652,16 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf discovery->native_backend->cind_enabled_indicators |= (1 << indicator); else if (len == 1 && r[0] == '0') discovery->native_backend->cind_enabled_indicators &= ~(1 << indicator); - else { + else { pa_log_error("Unable to parse indicator of AT+BIA command: %s", buf); rfcomm_write_response(fd, "ERROR"); - return false; + return false; } indicator++; } - return true; + return true; } else if (sscanf(buf, "AT+BAC=%3s", str) == 1) { c->support_msbc = false; @@ -688,15 +688,15 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf /* UPower backend available, declare support for more indicators */ if (discovery->native_backend->upower) { rfcomm_write_response(fd, "+CIND: " - MANDATORY_CALL_INDICATORS "," - "(\"service\",(0-1))," - "(\"battchg\",(0-5))"); + MANDATORY_CALL_INDICATORS "," + "(\"service\",(0-1))," + "(\"battchg\",(0-5))"); /* Minimal indicators supported without any additional backend */ } else { rfcomm_write_response(fd, "+CIND: " - MANDATORY_CALL_INDICATORS "," - "(\"service\",(0-1))"); + MANDATORY_CALL_INDICATORS "," + "(\"service\",(0-1))"); } c->state = 2; @@ -710,14 +710,13 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf return true; } else if ((c->state == 2 || c->state == 3) && pa_startswith(buf, "AT+CMER=")) { - if (sscanf(buf, "AT+CMER=%d,%*d,%*d,%d", &mode, &val) == 2) { + if (sscanf(buf, "AT+CMER=%d,%*d,%*d,%d", &mode, &val) == 2) { /* Bluetooth HFP spec only defines mode == 3 */ - if (mode != 3) { + if (mode != 3) pa_log_warn("Unexpected mode for AT+CMER: %d", mode); - } - /* Configure CMER event reporting */ - discovery->native_backend->cmer_indicator_reporting_enabled = !!val; + /* Configure CMER event reporting */ + discovery->native_backend->cmer_indicator_reporting_enabled = !!val; pa_log_debug("Event indications enabled? %s", pa_yes_no(val)); @@ -726,7 +725,7 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf else { pa_log_error("Unable to parse AT+CMER command: %s", buf); rfcomm_write_response(fd, "ERROR"); - return false; + return false; } if (c->support_codec_negotiation) { @@ -815,7 +814,7 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf return true; } -static int get_rfcomm_fd (pa_bluetooth_discovery *discovery) { +static int get_rfcomm_fd(pa_bluetooth_discovery *discovery) { struct pa_bluetooth_transport *t; struct transport_data *trd = NULL; void *state = NULL; @@ -852,14 +851,14 @@ static pa_hook_result_t host_battery_level_changed_cb(pa_bluetooth_discovery *y, pa_assert(b); /* Get RFCOMM channel if available */ - rfcomm_fd = get_rfcomm_fd (y); + rfcomm_fd = get_rfcomm_fd(y); if (rfcomm_fd < 0) return PA_HOOK_OK; /* Notify HF about AG battery level change over RFCOMM */ if (b->cmer_indicator_reporting_enabled && (b->cind_enabled_indicators & (1 << CIND_BATT_CHG_INDICATOR))) { - rfcomm_write_response(rfcomm_fd, "+CIEV: %d,%d", CIND_BATT_CHG_INDICATOR, u->battery_level); - pa_log_debug("HG notified of AG's battery level change"); + rfcomm_write_response(rfcomm_fd, "+CIEV: %d,%d", CIND_BATT_CHG_INDICATOR, u->battery_level); + pa_log_debug("HG notified of AG's battery level change"); /* Skip notification if indicator is disabled or event reporting is completely disabled */ } else pa_log_debug("Battery level change indicator disabled, skipping notification"); From 391dac58a970867e15ff894cdb6d9a8f682e9aef Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Tue, 2 Aug 2022 12:05:15 +0200 Subject: [PATCH 063/260] backend-native: Add backend pointer to transport_data This removes the inverse/recursive dependency of backend-native on the `pa_bluetooth_discovery` struct, which is supposed to be opaque outside of `bluez5-util` in favour of the many accessor functions defined in `bluez5-util.h`. Part-of: --- src/modules/bluetooth/backend-native.c | 26 +++++++++++++++----------- src/modules/bluetooth/bluez5-util.c | 7 +++++++ src/modules/bluetooth/bluez5-util.h | 1 + 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c index 5b1912a86..f94a8eeb4 100644 --- a/src/modules/bluetooth/backend-native.c +++ b/src/modules/bluetooth/backend-native.c @@ -67,6 +67,7 @@ struct transport_data { int sco_fd; pa_io_event *sco_io; pa_mainloop_api *mainloop; + pa_bluetooth_backend *backend; }; struct hfp_config { @@ -612,8 +613,9 @@ static pa_volume_t set_source_volume(pa_bluetooth_transport *t, pa_volume_t volu static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf) { - struct pa_bluetooth_discovery *discovery = t->device->discovery; struct hfp_config *c = t->config; + struct transport_data *trd = t->userdata; + pa_bluetooth_backend *b = trd->backend; int indicator, mode, val; char str[5]; const char *r; @@ -649,9 +651,9 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf continue; if (len == 1 && r[0] == '1') - discovery->native_backend->cind_enabled_indicators |= (1 << indicator); + b->cind_enabled_indicators |= (1 << indicator); else if (len == 1 && r[0] == '0') - discovery->native_backend->cind_enabled_indicators &= ~(1 << indicator); + b->cind_enabled_indicators &= ~(1 << indicator); else { pa_log_error("Unable to parse indicator of AT+BIA command: %s", buf); rfcomm_write_response(fd, "ERROR"); @@ -686,7 +688,7 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf return true; } else if (c->state == 1 && pa_startswith(buf, "AT+CIND=?")) { /* UPower backend available, declare support for more indicators */ - if (discovery->native_backend->upower) { + if (b->upower) { rfcomm_write_response(fd, "+CIND: " MANDATORY_CALL_INDICATORS "," "(\"service\",(0-1))," @@ -702,8 +704,8 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf return true; } else if (c->state == 2 && pa_startswith(buf, "AT+CIND?")) { - if (discovery->native_backend->upower) - rfcomm_write_response(fd, "+CIND: 0,0,0,0,%u", pa_upower_get_battery_level(discovery->native_backend->upower)); + if (b->upower) + rfcomm_write_response(fd, "+CIND: 0,0,0,0,%u", pa_upower_get_battery_level(b->upower)); else rfcomm_write_response(fd, "+CIND: 0,0,0,0"); c->state = 3; @@ -716,7 +718,7 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf pa_log_warn("Unexpected mode for AT+CMER: %d", mode); /* Configure CMER event reporting */ - discovery->native_backend->cmer_indicator_reporting_enabled = !!val; + b->cmer_indicator_reporting_enabled = !!val; pa_log_debug("Event indications enabled? %s", pa_yes_no(val)); @@ -820,7 +822,7 @@ static int get_rfcomm_fd(pa_bluetooth_discovery *discovery) { void *state = NULL; /* Find RFCOMM transport by checking if a HSP or HFP profile transport is available */ - while ((t = pa_hashmap_iterate(discovery->transports, &state, NULL))) { + while ((t = pa_hashmap_iterate(pa_bluetooth_discovery_get_transports(discovery), &state, NULL))) { /* Skip non-connected transports */ if (!t || t->state == PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED) { pa_log_debug("Profile disconnected or unavailable"); @@ -868,7 +870,8 @@ static pa_hook_result_t host_battery_level_changed_cb(pa_bluetooth_discovery *y, static void rfcomm_io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) { pa_bluetooth_transport *t = userdata; - pa_bluetooth_discovery *discovery = t->device->discovery; + struct transport_data *trd = t->userdata; + pa_bluetooth_backend *b = trd->backend; int i; pa_assert(io); @@ -991,9 +994,9 @@ static void rfcomm_io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_i fail: /* Service Connection lost, reset indicators and event reporting to default values */ - discovery->native_backend->cmer_indicator_reporting_enabled = false; + b->cmer_indicator_reporting_enabled = false; for (i = 1; i < CIND_INDICATOR_MAX; i++) - discovery->native_backend->cind_enabled_indicators |= (1 << i); + b->cind_enabled_indicators |= (1 << i); pa_bluetooth_transport_unlink(t); pa_bluetooth_transport_free(t); @@ -1157,6 +1160,7 @@ static DBusMessage *profile_new_connection(DBusConnection *conn, DBusMessage *m, trd = pa_xnew0(struct transport_data, 1); trd->rfcomm_fd = fd; trd->mainloop = b->core->mainloop; + trd->backend = b; trd->rfcomm_io = trd->mainloop->io_new(b->core->mainloop, fd, PA_IO_EVENT_INPUT, rfcomm_io_callback, t); t->userdata = trd; diff --git a/src/modules/bluetooth/bluez5-util.c b/src/modules/bluetooth/bluez5-util.c index 6ac4c2e7c..b72f5e52f 100644 --- a/src/modules/bluetooth/bluez5-util.c +++ b/src/modules/bluetooth/bluez5-util.c @@ -1179,6 +1179,13 @@ bool pa_bluetooth_discovery_get_enable_msbc(pa_bluetooth_discovery *y) return y->enable_msbc; } +pa_hashmap* pa_bluetooth_discovery_get_transports(pa_bluetooth_discovery *y) { + pa_assert(y); + pa_assert(PA_REFCNT_VALUE(y) > 0); + + return y->transports; +} + pa_bluetooth_device* pa_bluetooth_discovery_get_device_by_address(pa_bluetooth_discovery *y, const char *remote, const char *local) { pa_bluetooth_device *d; void *state = NULL; diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h index a24a0b823..c169edd8d 100644 --- a/src/modules/bluetooth/bluez5-util.h +++ b/src/modules/bluetooth/bluez5-util.h @@ -271,4 +271,5 @@ void pa_bluetooth_discovery_set_ofono_running(pa_bluetooth_discovery *y, bool is bool pa_bluetooth_discovery_get_enable_native_hsp_hs(pa_bluetooth_discovery *y); bool pa_bluetooth_discovery_get_enable_native_hfp_hf(pa_bluetooth_discovery *y); bool pa_bluetooth_discovery_get_enable_msbc(pa_bluetooth_discovery *y); +pa_hashmap* pa_bluetooth_discovery_get_transports(pa_bluetooth_discovery *y); #endif From 6ec084e2b3d941c5fb098ddbd83e734be7a500c3 Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Tue, 2 Aug 2022 12:05:17 +0200 Subject: [PATCH 064/260] Revert "bluez5-util: move pa_bluetooth_discovery to header" This reverts commit b05e34e092d5f40ff9a305fea181bd2308829824. Now that backend-native uses a different way to get to its own `native_backend` instance - without going through `pa_bluetooth_discovery` - this patch can be reverted again, as nothing outside bluez5-util is supposed to know the internals of this struct. That's what the many functions are for which all take pointers to this (at that point) opaque struct instead. Part-of: --- src/modules/bluetooth/bluez5-util.c | 23 +++++++++++++++++++++++ src/modules/bluetooth/bluez5-util.h | 24 ------------------------ src/modules/meson.build | 2 +- 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/modules/bluetooth/bluez5-util.c b/src/modules/bluetooth/bluez5-util.c index b72f5e52f..2431b3831 100644 --- a/src/modules/bluetooth/bluez5-util.c +++ b/src/modules/bluetooth/bluez5-util.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -127,6 +128,28 @@ static uint16_t volume_to_a2dp_gain(pa_volume_t volume) { return gain; } +struct pa_bluetooth_discovery { + PA_REFCNT_DECLARE; + + pa_core *core; + pa_dbus_connection *connection; + bool filter_added; + bool matches_added; + bool objects_listed; + pa_hook hooks[PA_BLUETOOTH_HOOK_MAX]; + pa_hashmap *adapters; + pa_hashmap *devices; + pa_hashmap *transports; + pa_bluetooth_profile_status_t profiles_status[PA_BLUETOOTH_PROFILE_COUNT]; + + int headset_backend; + pa_bluetooth_backend *ofono_backend, *native_backend; + PA_LLIST_HEAD(pa_dbus_pending, pending); + bool enable_native_hsp_hs; + bool enable_native_hfp_hf; + bool enable_msbc; +}; + static pa_dbus_pending* send_and_add_to_pending(pa_bluetooth_discovery *y, DBusMessage *m, DBusPendingCallNotifyFunction func, void *call_data) { pa_dbus_pending *p; diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h index c169edd8d..fff3d573c 100644 --- a/src/modules/bluetooth/bluez5-util.h +++ b/src/modules/bluetooth/bluez5-util.h @@ -22,7 +22,6 @@ ***/ #include -#include #include "a2dp-codec-util.h" @@ -137,29 +136,6 @@ struct pa_bluetooth_transport { void *userdata; }; -struct pa_bluetooth_discovery { - PA_REFCNT_DECLARE; - - pa_core *core; - pa_dbus_connection *connection; - bool filter_added; - bool matches_added; - bool objects_listed; - pa_hook hooks[PA_BLUETOOTH_HOOK_MAX]; - pa_hashmap *adapters; - pa_hashmap *devices; - pa_hashmap *transports; - pa_bluetooth_profile_status_t profiles_status[PA_BLUETOOTH_PROFILE_COUNT]; - - int headset_backend; - pa_bluetooth_backend *ofono_backend, *native_backend; - PA_LLIST_HEAD(pa_dbus_pending, pending); - bool enable_native_hsp_hs; - bool enable_native_hfp_hf; - bool enable_msbc; -}; - - struct pa_bluetooth_device { pa_bluetooth_discovery *discovery; pa_bluetooth_adapter *adapter; diff --git a/src/modules/meson.build b/src/modules/meson.build index c4e53d6d9..1e12569dc 100644 --- a/src/modules/meson.build +++ b/src/modules/meson.build @@ -123,7 +123,7 @@ if cdata.has('HAVE_BLUEZ_5') all_modules += [ [ 'module-bluetooth-discover', 'bluetooth/module-bluetooth-discover.c' ], [ 'module-bluetooth-policy', 'bluetooth/module-bluetooth-policy.c', [], [], [dbus_dep] ], - [ 'module-bluez5-device', 'bluetooth/module-bluez5-device.c', [], [], [dbus_dep], libbluez5_util ], + [ 'module-bluez5-device', 'bluetooth/module-bluez5-device.c', [], [], [], libbluez5_util ], [ 'module-bluez5-discover', 'bluetooth/module-bluez5-discover.c', [], [], [dbus_dep], libbluez5_util ], ] endif From 518ca03019f9c7cfd361b57673e9e6c3c1787579 Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Tue, 2 Aug 2022 12:21:22 +0200 Subject: [PATCH 065/260] backend-native: Update all CIND indicators When `indicator` is initialized to `1`: - it always succeeds the `indicator == CIND_CALL_INDICATOR` check; - hence always calls `continue`; - hence never reaches the end of the `while` loop where `indicator++` is called; - hence `indicator` never contains any other value than `1` meaning `cind_enabled_indicators` is ever updated. Part-of: --- src/modules/bluetooth/backend-native.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c index f94a8eeb4..1e366acf8 100644 --- a/src/modules/bluetooth/backend-native.c +++ b/src/modules/bluetooth/backend-native.c @@ -637,9 +637,8 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf return true; } else if (sscanf(buf, "AT+BIA=%s", str) == 1) { /* Indicators start with index 1 and follow the order of the AT+CIND=? response */ - indicator = 1; - while ((r = pa_split_in_place(str, ",", &len, &state))) { + for (indicator = 1; (r = pa_split_in_place(str, ",", &len, &state)); indicator++) { /* Ignore updates to mandatory indicators which are always ON */ if (indicator == CIND_CALL_INDICATOR || indicator == CIND_CALL_SETUP_INDICATOR @@ -659,8 +658,6 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf rfcomm_write_response(fd, "ERROR"); return false; } - - indicator++; } return true; From 8188b49bed7be08e23abcf92b098f62c1fc5c2ec Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Fri, 12 Aug 2022 14:22:52 +0200 Subject: [PATCH 066/260] backend-native: Remove uninformative "Profile unavailable" debug message This message would print for all transports while not even conveying the profile of the transport, and might be printed for non-`HFP_HF` profiles which is the only transport-profile we're interested in. Part-of: --- src/modules/bluetooth/backend-native.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c index 1e366acf8..bda9c7fa0 100644 --- a/src/modules/bluetooth/backend-native.c +++ b/src/modules/bluetooth/backend-native.c @@ -822,7 +822,6 @@ static int get_rfcomm_fd(pa_bluetooth_discovery *discovery) { while ((t = pa_hashmap_iterate(pa_bluetooth_discovery_get_transports(discovery), &state, NULL))) { /* Skip non-connected transports */ if (!t || t->state == PA_BLUETOOTH_TRANSPORT_STATE_DISCONNECTED) { - pa_log_debug("Profile disconnected or unavailable"); continue; } From 8fe50bbc31e11abf2f30864f1e2dbdaa16d0e1c3 Mon Sep 17 00:00:00 2001 From: Georg Chini Date: Thu, 25 Aug 2022 08:11:04 +0200 Subject: [PATCH 067/260] time-smoother-2: Fix stream time when stream starts paused When a stream is started but has not yet called smoother_2_put(), pa_smoother_2_get() returns the time since the start of the stream even if the stream was started paused. When the stream is started paused, pa_smoother_2_get() should return 0 instead. This patch fixes the problem. Part-of: --- src/pulsecore/time-smoother_2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulsecore/time-smoother_2.c b/src/pulsecore/time-smoother_2.c index e14b52f72..ea7ec1b36 100644 --- a/src/pulsecore/time-smoother_2.c +++ b/src/pulsecore/time-smoother_2.c @@ -295,7 +295,7 @@ pa_usec_t pa_smoother_2_get(pa_smoother_2 *s, pa_usec_t time_stamp) { /* If the smoother has not started, just return system time since resume */ if (!s->start_time) { - if (time_stamp >= s->resume_time) + if (time_stamp >= s->resume_time && !s->paused) current_time = time_stamp - s->resume_time; else current_time = 0; From 68a0603d7688e7908d7178ea749428ab2c453a35 Mon Sep 17 00:00:00 2001 From: wael <40663@proton.me> Date: Wed, 21 Sep 2022 07:06:45 +0000 Subject: [PATCH 068/260] meson: use proper type for bools Part-of: --- meson_options.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson_options.txt b/meson_options.txt index e7160a3a7..0ab985d2a 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -169,7 +169,7 @@ option('x11', type : 'feature', value : 'auto', description : 'Optional X11 support') option('enable-smoother-2', - type : 'boolean', value : 'true', + type : 'boolean', value : true, description : 'Use alternative time smoother implementation') # Echo cancellation From 45df212d6614ad7f57d9e53616c0faac00195c86 Mon Sep 17 00:00:00 2001 From: acheronfail Date: Fri, 9 Sep 2022 14:45:49 +0930 Subject: [PATCH 069/260] pactl: SUBSCRIBE add a newline after every json message Part-of: --- src/utils/pactl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/pactl.c b/src/utils/pactl.c index 2761ebaaf..9e343954f 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -2200,7 +2200,7 @@ static void context_subscribe_callback(pa_context *c, pa_subscription_event_type pa_json_encoder_end_object(encoder); char* json_str = pa_json_encoder_to_string_free(encoder); - printf("%s", json_str); + printf("%s\n", json_str); pa_xfree(json_str); } else { printf(_("Event '%s' on %s #%u\n"), From 48f40352a684d34cf0f95ec75431d309aeadc27c Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Mon, 6 Sep 2021 22:53:42 +0300 Subject: [PATCH 070/260] bluetooth: Free memblock after codec errors Part-of: --- src/modules/bluetooth/module-bluez5-device.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c index 767482e4a..9c40a60ff 100644 --- a/src/modules/bluetooth/module-bluez5-device.c +++ b/src/modules/bluetooth/module-bluez5-device.c @@ -392,6 +392,8 @@ static int bt_process_render(struct userdata *u) { if (processed != u->write_memchunk.length) { pa_log_error("Encoding error"); + pa_memblock_unref(u->write_memchunk.memblock); + pa_memchunk_reset(&u->write_memchunk); return -1; } @@ -535,6 +537,7 @@ static int bt_process_push(struct userdata *u) { if (processed != (size_t) received) { pa_log_error("Decoding error"); + pa_memblock_unref(memchunk.memblock); return -1; } From 0498e7a3d05c8ccd4f0389778e04f964f8a0b2f8 Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Mon, 6 Sep 2021 01:34:21 +0300 Subject: [PATCH 071/260] bluetooth: Do not use hardware volume control for A2DP backchannel Part-of: --- src/modules/bluetooth/module-bluez5-device.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c index 9c40a60ff..bac8ca4b2 100644 --- a/src/modules/bluetooth/module-bluez5-device.c +++ b/src/modules/bluetooth/module-bluez5-device.c @@ -964,6 +964,12 @@ static void source_setup_volume_callback(pa_source *s) { if (pa_bluetooth_profile_is_a2dp(u->profile) && !u->transport->device->avrcp_absolute_volume) return; + /* Do not use hardware volume controls for backchannel of A2DP sink */ + if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK) { + pa_assert_fp(u->transport->bt_codec && u->transport->bt_codec->support_backchannel); + return; + } + /* Remote volume control has to be supported for the callback to make sense, * otherwise this source should continue performing attenuation in software * without HW_VOLUME_CTL. @@ -1032,6 +1038,12 @@ static int add_source(struct userdata *u) { if (!u->transport_acquired) switch (u->profile) { + case PA_BLUETOOTH_PROFILE_A2DP_SINK: + if (u->bt_codec && u->bt_codec->support_backchannel) + data.suspend_cause = PA_SUSPEND_USER; + else + pa_assert_not_reached(); + break; case PA_BLUETOOTH_PROFILE_A2DP_SOURCE: case PA_BLUETOOTH_PROFILE_HFP_AG: case PA_BLUETOOTH_PROFILE_HSP_AG: @@ -1046,7 +1058,6 @@ static int add_source(struct userdata *u) { else pa_assert_not_reached(); break; - case PA_BLUETOOTH_PROFILE_A2DP_SINK: case PA_BLUETOOTH_PROFILE_OFF: pa_assert_not_reached(); break; @@ -1201,6 +1212,12 @@ static void sink_setup_volume_callback(pa_sink *s) { if (pa_bluetooth_profile_is_a2dp(u->profile) && !u->transport->device->avrcp_absolute_volume) return; + /* Do not use hardware volume controls for backchannel of A2DP source */ + if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SOURCE) { + pa_assert_fp(u->transport->bt_codec && u->transport->bt_codec->support_backchannel); + return; + } + /* Remote volume control has to be supported for the callback to make sense, * otherwise this sink should continue performing attenuation in software * without HW_VOLUME_CTL. From cddb9f144a71cc0f1f690898056737fb4402b2b9 Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Tue, 20 Apr 2021 19:30:52 +0300 Subject: [PATCH 072/260] bluetooth: Add faststream codec Part-of: --- src/modules/bluetooth/a2dp-codec-api.h | 3 - src/modules/bluetooth/a2dp-codec-aptx-gst.c | 2 - src/modules/bluetooth/a2dp-codec-ldac-gst.c | 3 - src/modules/bluetooth/a2dp-codec-sbc.c | 460 ++++++++++++++++++- src/modules/bluetooth/a2dp-codec-util.c | 2 + src/modules/bluetooth/bt-codec-api.h | 3 + src/modules/bluetooth/module-bluez5-device.c | 36 +- 7 files changed, 482 insertions(+), 27 deletions(-) diff --git a/src/modules/bluetooth/a2dp-codec-api.h b/src/modules/bluetooth/a2dp-codec-api.h index bdfd3f390..e46981836 100644 --- a/src/modules/bluetooth/a2dp-codec-api.h +++ b/src/modules/bluetooth/a2dp-codec-api.h @@ -42,9 +42,6 @@ typedef struct pa_a2dp_endpoint_conf { /* A2DP codec id */ pa_a2dp_codec_id id; - /* True if codec is bi-directional and supports backchannel */ - bool support_backchannel; - /* Returns true if the codec can be supported on the system */ bool (*can_be_supported)(bool for_encoding); diff --git a/src/modules/bluetooth/a2dp-codec-aptx-gst.c b/src/modules/bluetooth/a2dp-codec-aptx-gst.c index 61b995b25..d0573e3b2 100644 --- a/src/modules/bluetooth/a2dp-codec-aptx-gst.c +++ b/src/modules/bluetooth/a2dp-codec-aptx-gst.c @@ -556,7 +556,6 @@ static size_t decode_buffer_hd(void *codec_info, const uint8_t *input_buffer, si const pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_aptx = { .id = { A2DP_CODEC_VENDOR, APTX_VENDOR_ID, APTX_CODEC_ID }, - .support_backchannel = false, .can_be_supported = can_be_supported, .can_accept_capabilities = can_accept_capabilities, .choose_remote_endpoint = choose_remote_endpoint, @@ -580,7 +579,6 @@ const pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_aptx = { const pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_aptx_hd = { .id = { A2DP_CODEC_VENDOR, APTX_HD_VENDOR_ID, APTX_HD_CODEC_ID }, - .support_backchannel = false, .can_be_supported = can_be_supported, .can_accept_capabilities = can_accept_capabilities_hd, .choose_remote_endpoint = choose_remote_endpoint_hd, diff --git a/src/modules/bluetooth/a2dp-codec-ldac-gst.c b/src/modules/bluetooth/a2dp-codec-ldac-gst.c index c0bcc6668..dfefbf186 100644 --- a/src/modules/bluetooth/a2dp-codec-ldac-gst.c +++ b/src/modules/bluetooth/a2dp-codec-ldac-gst.c @@ -433,7 +433,6 @@ static size_t encode_buffer(void *codec_info, uint32_t timestamp, const uint8_t const pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_ldac_eqmid_hq = { .id = { A2DP_CODEC_VENDOR, LDAC_VENDOR_ID, LDAC_CODEC_ID }, - .support_backchannel = false, .can_be_supported = can_be_supported, .can_accept_capabilities = can_accept_capabilities, .choose_remote_endpoint = choose_remote_endpoint, @@ -456,7 +455,6 @@ const pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_ldac_eqmid_hq = { const pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_ldac_eqmid_sq = { .id = { A2DP_CODEC_VENDOR, LDAC_VENDOR_ID, LDAC_CODEC_ID }, - .support_backchannel = false, .can_be_supported = can_be_supported, .can_accept_capabilities = can_accept_capabilities, .choose_remote_endpoint = choose_remote_endpoint, @@ -479,7 +477,6 @@ const pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_ldac_eqmid_sq = { const pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_ldac_eqmid_mq = { .id = { A2DP_CODEC_VENDOR, LDAC_VENDOR_ID, LDAC_CODEC_ID }, - .support_backchannel = false, .can_be_supported = can_be_supported, .can_accept_capabilities = can_accept_capabilities, .choose_remote_endpoint = choose_remote_endpoint, diff --git a/src/modules/bluetooth/a2dp-codec-sbc.c b/src/modules/bluetooth/a2dp-codec-sbc.c index 54e52ae4c..6c6f99bb8 100644 --- a/src/modules/bluetooth/a2dp-codec-sbc.c +++ b/src/modules/bluetooth/a2dp-codec-sbc.c @@ -108,6 +108,24 @@ static bool can_accept_capabilities_xq(const uint8_t *capabilities_buffer, uint8 return true; } +static bool can_accept_capabilities_faststream(const uint8_t *capabilities_buffer, uint8_t capabilities_size, bool for_encoding) { + const a2dp_faststream_t *capabilities = (const a2dp_faststream_t *) capabilities_buffer; + + if (capabilities_size != sizeof(*capabilities)) + return false; + + if (!(capabilities->direction & (FASTSTREAM_DIRECTION_SINK | FASTSTREAM_DIRECTION_SOURCE))) + return false; + + if (!(capabilities->sink_frequency & (FASTSTREAM_SINK_SAMPLING_FREQ_44100 | FASTSTREAM_SINK_SAMPLING_FREQ_48000))) + return false; + + if (!(capabilities->source_frequency & FASTSTREAM_SOURCE_SAMPLING_FREQ_16000)) + return false; + + return true; +} + static const char *choose_remote_endpoint(const pa_hashmap *capabilities_hashmap, const pa_sample_spec *default_sample_spec, bool for_encoding) { const pa_a2dp_codec_capabilities *a2dp_capabilities; const char *key; @@ -136,6 +154,23 @@ static const char *choose_remote_endpoint_xq(const pa_hashmap *capabilities_hash return NULL; } +static const char *choose_remote_endpoint_faststream(const pa_hashmap *capabilities_hashmap, const pa_sample_spec *default_sample_spec, bool for_encoding) { + const pa_a2dp_codec_capabilities *a2dp_capabilities; + const char *key; + void *state; + + /* There is no preference, just choose random valid entry */ + PA_HASHMAP_FOREACH_KV(key, a2dp_capabilities, capabilities_hashmap, state) { + pa_log_debug("choose_remote_endpoint_faststream checking peer endpoint '%s'", key); + if (can_accept_capabilities_faststream(a2dp_capabilities->buffer, a2dp_capabilities->size, for_encoding)) + return key; + } + + pa_log_debug("choose_remote_endpoint_faststream matched no peer endpoint"); + + return NULL; +} + static uint8_t fill_capabilities(uint8_t capabilities_buffer[MAX_A2DP_CAPS_SIZE]) { a2dp_sbc_t *capabilities = (a2dp_sbc_t *) capabilities_buffer; @@ -326,6 +361,46 @@ static uint8_t fill_capabilities_xq(uint8_t capabilities_buffer[MAX_A2DP_CAPS_SI return sizeof(*capabilities); } +static uint8_t fill_capabilities_faststream(uint8_t capabilities_buffer[MAX_A2DP_CAPS_SIZE]) { + a2dp_faststream_t *capabilities = (a2dp_faststream_t *) capabilities_buffer; + + pa_zero(*capabilities); + + capabilities->info = A2DP_SET_VENDOR_ID_CODEC_ID(FASTSTREAM_VENDOR_ID, FASTSTREAM_CODEC_ID); + + capabilities->direction = FASTSTREAM_DIRECTION_SINK | FASTSTREAM_DIRECTION_SOURCE; + capabilities->sink_frequency = FASTSTREAM_SINK_SAMPLING_FREQ_44100 | FASTSTREAM_SINK_SAMPLING_FREQ_48000; + capabilities->source_frequency = FASTSTREAM_SOURCE_SAMPLING_FREQ_16000; + + return sizeof(*capabilities); +} + +static bool is_configuration_valid_faststream(const uint8_t *config_buffer, uint8_t config_size) { + const a2dp_faststream_t *config = (const a2dp_faststream_t *) config_buffer; + + if (config_size != sizeof(*config)) { + pa_log_error("Invalid size of config buffer"); + return false; + } + + if (!(config->direction & (FASTSTREAM_DIRECTION_SINK | FASTSTREAM_DIRECTION_SOURCE))) { + pa_log_error("Invalid FastStream direction in configuration"); + return false; + } + + if (config->sink_frequency != FASTSTREAM_SINK_SAMPLING_FREQ_44100 && config->sink_frequency != FASTSTREAM_SINK_SAMPLING_FREQ_48000) { + pa_log_error("Invalid FastStream sink sampling frequency in configuration"); + return false; + } + + if (config->source_frequency != FASTSTREAM_SOURCE_SAMPLING_FREQ_16000) { + pa_log_error("Invalid FastStream source sampling frequency in configuration"); + return false; + } + + return true; +} + static bool is_configuration_valid(const uint8_t *config_buffer, uint8_t config_size) { const a2dp_sbc_t *config = (const a2dp_sbc_t *) config_buffer; @@ -527,6 +602,85 @@ static uint8_t fill_preferred_configuration(const pa_sample_spec *default_sample return sizeof(*config); } +static uint8_t fill_preferred_configuration_faststream(const pa_sample_spec *default_sample_spec, const uint8_t *capabilities_buffer, uint8_t capabilities_size, uint8_t config_buffer[MAX_A2DP_CAPS_SIZE]) { + a2dp_faststream_t *config = (a2dp_faststream_t *) config_buffer; + const a2dp_faststream_t *capabilities = (const a2dp_faststream_t *) capabilities_buffer; + int i; + + static const struct { + uint32_t rate; + uint8_t cap; + } sink_freq_table[] = { + { 44100U, FASTSTREAM_SINK_SAMPLING_FREQ_44100 }, + { 48000U, FASTSTREAM_SINK_SAMPLING_FREQ_48000 } + }; + + static const struct { + uint32_t rate; + uint8_t cap; + } source_freq_table[] = { + { 16000U, FASTSTREAM_SOURCE_SAMPLING_FREQ_16000 } + }; + + if (capabilities_size != sizeof(*capabilities)) { + pa_log_error("Invalid size of FastStream capabilities buffer"); + return 0; + } + + pa_zero(*config); + + /* Find the lowest freq that is at least as high as the requested sampling rate */ + for (i = 0; (unsigned) i < PA_ELEMENTSOF(sink_freq_table); i++) + if (sink_freq_table[i].rate >= default_sample_spec->rate && (capabilities->sink_frequency & sink_freq_table[i].cap)) { + config->sink_frequency = sink_freq_table[i].cap; + break; + } + + /* Match with endpoint capabilities */ + if ((unsigned) i == PA_ELEMENTSOF(sink_freq_table)) { + for (--i; i >= 0; i--) { + if (capabilities->sink_frequency & sink_freq_table[i].cap) { + config->sink_frequency = sink_freq_table[i].cap; + break; + } + } + + if (i < 0) { + pa_log_error("Not suitable FastStream sink sample rate"); + return 0; + } + } + + pa_assert((unsigned) i < PA_ELEMENTSOF(sink_freq_table)); + + /* Only single frequency (for now?) */ + config->source_frequency = FASTSTREAM_SOURCE_SAMPLING_FREQ_16000; + i = 0; + + /* Match with endpoint capabilities */ + if ((unsigned) i == PA_ELEMENTSOF(source_freq_table)) { + for (--i; i >= 0; i--) { + if (capabilities->source_frequency & source_freq_table[i].cap) { + config->source_frequency = source_freq_table[i].cap; + break; + } + } + + if (i < 0) { + pa_log_error("Not suitable FastStream source sample rate"); + return 0; + } + } + + pa_assert((unsigned) i < PA_ELEMENTSOF(source_freq_table)); + + config->direction = FASTSTREAM_DIRECTION_SINK | FASTSTREAM_DIRECTION_SOURCE; + + config->info = A2DP_SET_VENDOR_ID_CODEC_ID(FASTSTREAM_VENDOR_ID, FASTSTREAM_CODEC_ID); + + return sizeof(*config); +} + static uint8_t fill_preferred_configuration_xq(const pa_sample_spec *default_sample_spec, const uint8_t *capabilities_buffer, uint8_t capabilities_size, uint8_t config_buffer[MAX_A2DP_CAPS_SIZE], uint32_t bitrate_cap) { a2dp_sbc_t *config = (a2dp_sbc_t *) config_buffer; const a2dp_sbc_t *capabilities = (const a2dp_sbc_t *) capabilities_buffer; @@ -684,6 +838,79 @@ static void *init(bool for_encoding, bool for_backchannel, const uint8_t *config return sbc_info; } +static void *init_faststream(bool for_encoding, bool for_backchannel, const uint8_t *config_buffer, uint8_t config_size, pa_sample_spec *sample_spec, pa_core *core) { + struct sbc_info *sbc_info; + const a2dp_faststream_t *config = (const a2dp_faststream_t *) config_buffer; + int ret; + + pa_assert(config_size == sizeof(*config)); + + sbc_info = pa_xnew0(struct sbc_info, 1); + + ret = sbc_init(&sbc_info->sbc, 0); + if (ret != 0) { + pa_xfree(sbc_info); + pa_log_error("SBC initialization failed: %d", ret); + return NULL; + } + + sample_spec->format = PA_SAMPLE_S16LE; + + if (for_encoding != for_backchannel) { + switch (config->sink_frequency) { + case FASTSTREAM_SINK_SAMPLING_FREQ_44100: + sbc_info->frequency = SBC_FREQ_44100; + sample_spec->rate = 44100U; + break; + case FASTSTREAM_SINK_SAMPLING_FREQ_48000: + sbc_info->frequency = SBC_FREQ_48000; + sample_spec->rate = 48000U; + break; + default: + pa_assert_not_reached(); + } + + sample_spec->channels = 2; + + sbc_info->mode = SBC_MODE_JOINT_STEREO; + sbc_info->initial_bitpool = sbc_info->min_bitpool = sbc_info->max_bitpool = 29; + } else { + switch (config->source_frequency) { + case FASTSTREAM_SOURCE_SAMPLING_FREQ_16000: + sbc_info->frequency = SBC_FREQ_16000; + sample_spec->rate = 16000U; + break; + default: + pa_assert_not_reached(); + } + + sample_spec->channels = 1; + + sbc_info->mode = SBC_MODE_MONO; + sbc_info->initial_bitpool = sbc_info->min_bitpool = sbc_info->max_bitpool = 32; + } + + sbc_info->allocation = SBC_AM_LOUDNESS; + sbc_info->subbands = SBC_SB_8; + sbc_info->nr_subbands = 8; + sbc_info->blocks = SBC_BLK_16; + sbc_info->nr_blocks = 16; + + set_params(sbc_info); + if (sbc_info->frame_length & 1) + ++sbc_info->frame_length; + + pa_log_info("FastStream %s SBC parameters: allocation=%s, subbands=%u, blocks=%u, mode=%s bitpool=%u codesize=%u frame_length=%u", + for_encoding ? "encoder" : "decoder", + sbc_info->sbc.allocation ? "SNR" : "Loudness", sbc_info->sbc.subbands ? 8 : 4, + (sbc_info->sbc.blocks+1)*4, sbc_info->sbc.mode == SBC_MODE_MONO ? "Mono" : + sbc_info->sbc.mode == SBC_MODE_DUAL_CHANNEL ? "DualChannel" : + sbc_info->sbc.mode == SBC_MODE_STEREO ? "Stereo" : "JointStereo", + sbc_info->sbc.bitpool, (unsigned)sbc_info->codesize, (unsigned)sbc_info->frame_length); + + return sbc_info; +} + static void deinit(void *codec_info) { struct sbc_info *sbc_info = (struct sbc_info *) codec_info; @@ -722,6 +949,25 @@ static int reset(void *codec_info) { return 0; } +static int reset_faststream(void *codec_info) { + struct sbc_info *sbc_info = (struct sbc_info *) codec_info; + int ret; + + ret = sbc_reinit(&sbc_info->sbc, 0); + if (ret != 0) { + pa_log_error("SBC reinitialization failed: %d", ret); + return -1; + } + + /* sbc_reinit() sets also default parameters, so reset them back */ + set_params(sbc_info); + if (sbc_info->frame_length & 1) + ++sbc_info->frame_length; + + sbc_info->seq_num = 0; + return 0; +} + static size_t get_block_size(void *codec_info, size_t link_mtu) { struct sbc_info *sbc_info = (struct sbc_info *) codec_info; size_t rtp_size = sizeof(struct rtp_header) + sizeof(struct rtp_payload); @@ -742,6 +988,28 @@ static size_t get_block_size(void *codec_info, size_t link_mtu) { return frame_count * sbc_info->codesize; } +static size_t get_write_block_size_faststream(void *codec_info, size_t link_mtu) { + struct sbc_info *sbc_info = (struct sbc_info *) codec_info; + size_t frame_count = link_mtu / sbc_info->frame_length; + + /* 3 frames seem to work best, with minimal glitches */ + if (frame_count > 3) + frame_count = 3; + + return frame_count * sbc_info->codesize; +} + +static size_t get_read_block_size_faststream(void *codec_info, size_t link_mtu) { + /* With SBC bitpool >= 29 and any combination of blocks, subbands + * and channels maximum compression ratio 4:1 is achieved with + * blocks=16, subbands=8, channels=2, bitpool=29 + * + * Though smaller bitpools can yield higher compression ratio, faststream is + * assumed to have fixed bitpool so maximum output size is link_mtu * 4. + */ + return link_mtu * 4; +} + static size_t get_encoded_block_size(void *codec_info, size_t input_size) { struct sbc_info *sbc_info = (struct sbc_info *) codec_info; size_t rtp_size = sizeof(struct rtp_header) + sizeof(struct rtp_payload); @@ -752,6 +1020,15 @@ static size_t get_encoded_block_size(void *codec_info, size_t input_size) { return (input_size / sbc_info->codesize) * sbc_info->frame_length + rtp_size; } +static size_t get_encoded_block_size_faststream(void *codec_info, size_t input_size) { + struct sbc_info *sbc_info = (struct sbc_info *) codec_info; + + /* input size should be aligned to codec input block size */ + pa_assert_fp(input_size % sbc_info->codesize == 0); + + return (input_size / sbc_info->codesize) * sbc_info->frame_length; +} + static size_t reduce_encoder_bitrate(void *codec_info, size_t write_link_mtu) { struct sbc_info *sbc_info = (struct sbc_info *) codec_info; uint8_t bitpool; @@ -860,6 +1137,72 @@ static size_t encode_buffer(void *codec_info, uint32_t timestamp, const uint8_t return d - output_buffer; } +static size_t encode_buffer_faststream(void *codec_info, uint32_t timestamp, const uint8_t *input_buffer, size_t input_size, uint8_t *output_buffer, size_t output_size, size_t *processed) { + struct sbc_info *sbc_info = (struct sbc_info *) codec_info; + uint8_t *d; + const uint8_t *p; + size_t to_write, to_encode; + uint8_t frame_count; + + frame_count = 0; + + p = input_buffer; + to_encode = input_size; + + d = output_buffer; + to_write = output_size; + + /* frame_count is only 4 bit number */ + while (PA_LIKELY(to_encode > 0 && to_write > 0)) { + ssize_t written; + ssize_t encoded; + + encoded = sbc_encode(&sbc_info->sbc, + p, to_encode, + d, to_write, + &written); + + if (PA_UNLIKELY(encoded <= 0)) { + pa_log_error("SBC encoding error (%li)", (long) encoded); + break; + } + + if (PA_UNLIKELY(written < 0)) { + pa_log_error("SBC encoding error (%li)", (long) written); + break; + } + + while (written < sbc_info->frame_length && written < to_write) + d[written++] = 0; + + pa_assert_fp((size_t) encoded <= to_encode); + pa_assert_fp((size_t) encoded == sbc_info->codesize); + + pa_assert_fp((size_t) written <= to_write); + pa_assert_fp((size_t) written == sbc_info->frame_length); + + p += encoded; + to_encode -= encoded; + + d += written; + to_write -= written; + + frame_count++; + } + + PA_ONCE_BEGIN { + pa_log_debug("Using SBC codec implementation: %s", pa_strnull(sbc_get_implementation_info(&sbc_info->sbc))); + } PA_ONCE_END; + + if (PA_UNLIKELY(frame_count == 0)) { + *processed = 0; + return 0; + } + + *processed = p - input_buffer; + return d - output_buffer; +} + static size_t decode_buffer(void *codec_info, const uint8_t *input_buffer, size_t input_size, uint8_t *output_buffer, size_t output_size, size_t *processed) { struct sbc_info *sbc_info = (struct sbc_info *) codec_info; @@ -924,9 +1267,76 @@ static size_t decode_buffer(void *codec_info, const uint8_t *input_buffer, size_ return d - output_buffer; } +static size_t decode_buffer_faststream(void *codec_info, const uint8_t *input_buffer, size_t input_size, uint8_t *output_buffer, size_t output_size, size_t *processed) { + struct sbc_info *sbc_info = (struct sbc_info *) codec_info; + + const uint8_t *p; + uint8_t *d; + size_t to_write, to_decode; + pa_sample_spec decoded_sample_spec = { + .format = PA_SAMPLE_S16LE, + .channels = 1, + .rate = 16000U + }; + + p = input_buffer; + to_decode = input_size; + + d = output_buffer; + to_write = output_size; + + while (PA_LIKELY(to_decode > 0 && to_write > 0)) { + size_t written; + ssize_t decoded; + + decoded = sbc_decode(&sbc_info->sbc, + p, to_decode, + d, to_write, + &written); + + if (PA_UNLIKELY(decoded <= 0)) { + pa_log_error("FastStream SBC decoding error (%li)", (long) decoded); + decoded = PA_MIN(sbc_info->frame_length, to_decode); + written = PA_MIN(sbc_info->codesize, to_write); + pa_silence_memory(d, written, &decoded_sample_spec); + } else { + /* Reset codesize and frame_length to values found by decoder */ + sbc_info->codesize = sbc_get_codesize(&sbc_info->sbc); + sbc_info->frame_length = sbc_get_frame_length(&sbc_info->sbc); + + if (sbc_info->frequency != sbc_info->sbc.frequency) { + /* some devices unexpectedly return SBC frequency different from 16000 + * remember this, and keep incoming sample rate at 16000 */ + pa_log_debug("FastStream decoder detected SBC frequency %u, expected %u", sbc_info->sbc.frequency, sbc_info->frequency); + sbc_info->frequency = sbc_info->sbc.frequency; + } + } + + if ((sbc_info->frame_length & 1) && decoded < to_decode) { + ++decoded; + ++sbc_info->frame_length; + } + + pa_assert_fp((size_t) decoded <= to_decode); + pa_assert_fp((size_t) decoded == PA_MIN(sbc_info->frame_length, to_decode)); + + pa_assert_fp((size_t) written <= to_write); + + p += decoded; + to_decode -= decoded; + + d += written; + to_write -= written; + } + + /* XXX eat remainder, may need to fix this if input frames are split across packets */ + *processed = input_size; + + return d - output_buffer; +} + const pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_sbc = { .id = { A2DP_CODEC_SBC, 0, 0 }, - .support_backchannel = false, .can_be_supported = can_be_supported, .can_accept_capabilities = can_accept_capabilities, .choose_remote_endpoint = choose_remote_endpoint, @@ -964,7 +1374,6 @@ const pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_sbc = { const pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_sbc_xq_453 = { .id = { A2DP_CODEC_SBC, 0, 0 }, - .support_backchannel = false, .can_be_supported = can_be_supported, .can_accept_capabilities = can_accept_capabilities_xq, .choose_remote_endpoint = choose_remote_endpoint_xq, @@ -989,7 +1398,6 @@ const pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_sbc_xq_453 = { const pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_sbc_xq_512 = { .id = { A2DP_CODEC_SBC, 0, 0 }, - .support_backchannel = false, .can_be_supported = can_be_supported, .can_accept_capabilities = can_accept_capabilities_xq, .choose_remote_endpoint = choose_remote_endpoint_xq, @@ -1014,7 +1422,6 @@ const pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_sbc_xq_512 = { const pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_sbc_xq_552 = { .id = { A2DP_CODEC_SBC, 0, 0 }, - .support_backchannel = false, .can_be_supported = can_be_supported, .can_accept_capabilities = can_accept_capabilities_xq, .choose_remote_endpoint = choose_remote_endpoint_xq, @@ -1036,3 +1443,48 @@ const pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_sbc_xq_552 = { .decode_buffer = decode_buffer, }, }; + +/* FastStream codec is just SBC codec with fixed parameters. + * + * Sink stream parameters: + * 48.0kHz or 44.1kHz, + * Blocks 16, + * Sub-bands 8, + * Joint Stereo, + * Allocation method Loudness, + * Bitpool = 29 + * (data rate = 212kbps, packet size = (71+1)3 <= DM5 = 220, with 3 SBC frames). + * SBC frame size is 71 bytes, but FastStream is zero-padded to the even size (72). + * + * Source stream parameters: + * 16kHz, + * Mono, + * Blocks 16, + * Sub-bands 8, + * Allocation method Loudness, + * Bitpool = 32 + * (data rate = 72kbps, packet size = 723 <= DM5 = 220, with 3 SBC frames). + */ + +const pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_faststream = { + .id = { A2DP_CODEC_VENDOR, FASTSTREAM_VENDOR_ID, FASTSTREAM_CODEC_ID }, + .can_be_supported = can_be_supported, + .can_accept_capabilities = can_accept_capabilities_faststream, + .choose_remote_endpoint = choose_remote_endpoint_faststream, + .fill_capabilities = fill_capabilities_faststream, + .is_configuration_valid = is_configuration_valid_faststream, + .fill_preferred_configuration = fill_preferred_configuration_faststream, + .bt_codec = { + .name = "faststream", + .description = "FastStream", + .support_backchannel = true, + .init = init_faststream, + .deinit = deinit, + .reset = reset_faststream, + .get_read_block_size = get_read_block_size_faststream, + .get_write_block_size = get_write_block_size_faststream, + .get_encoded_block_size = get_encoded_block_size_faststream, + .encode_buffer = encode_buffer_faststream, + .decode_buffer = decode_buffer_faststream, + }, +}; diff --git a/src/modules/bluetooth/a2dp-codec-util.c b/src/modules/bluetooth/a2dp-codec-util.c index 7db025164..43cf34b2d 100644 --- a/src/modules/bluetooth/a2dp-codec-util.c +++ b/src/modules/bluetooth/a2dp-codec-util.c @@ -52,6 +52,7 @@ extern const pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_ldac_eqmid_hq; extern const pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_ldac_eqmid_sq; extern const pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_ldac_eqmid_mq; #endif +extern const pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_faststream; /* This is list of supported codecs. Their order is important. * Codec with lower index has higher priority. */ @@ -69,6 +70,7 @@ static const pa_a2dp_endpoint_conf *pa_a2dp_endpoint_configurations[] = { &pa_a2dp_endpoint_conf_sbc_xq_453, &pa_a2dp_endpoint_conf_sbc_xq_512, &pa_a2dp_endpoint_conf_sbc_xq_552, + &pa_a2dp_endpoint_conf_faststream, }; unsigned int pa_bluetooth_a2dp_endpoint_conf_count(void) { diff --git a/src/modules/bluetooth/bt-codec-api.h b/src/modules/bluetooth/bt-codec-api.h index 900ffe942..3ed47166a 100644 --- a/src/modules/bluetooth/bt-codec-api.h +++ b/src/modules/bluetooth/bt-codec-api.h @@ -26,6 +26,9 @@ typedef struct pa_bt_codec { /* Human readable codec description */ const char *description; + /* True if codec is bi-directional and supports backchannel */ + bool support_backchannel; + /* Initialize codec, returns codec info data and set sample_spec, * for_encoding is true when codec_info is used for encoding, * for_backchannel is true when codec_info is used for backchannel */ diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c index bac8ca4b2..f50521c59 100644 --- a/src/modules/bluetooth/module-bluez5-device.c +++ b/src/modules/bluetooth/module-bluez5-device.c @@ -1342,6 +1342,7 @@ static pa_direction_t get_profile_direction(pa_bluetooth_profile_t p) { /* Run from main thread */ static int transport_config(struct userdata *u) { + bool reverse_backchannel; pa_assert(u); pa_assert(u->transport); pa_assert(!u->bt_codec); @@ -1354,15 +1355,18 @@ static int transport_config(struct userdata *u) { /* reset encoder buffer contents */ u->encoder_buffer_used = 0; - if (get_profile_direction(u->profile) & PA_DIRECTION_OUTPUT) { - u->encoder_info = u->bt_codec->init(true, false, u->transport->config, u->transport->config_size, &u->encoder_sample_spec, u->core); + /* forward encoding direction */ + reverse_backchannel = u->bt_codec->support_backchannel && !(get_profile_direction(u->profile) & PA_DIRECTION_OUTPUT); + + if ((get_profile_direction(u->profile) & PA_DIRECTION_OUTPUT) || u->bt_codec->support_backchannel) { + u->encoder_info = u->bt_codec->init(true, reverse_backchannel, u->transport->config, u->transport->config_size, &u->encoder_sample_spec, u->core); if (!u->encoder_info) return -1; } - if (get_profile_direction(u->profile) & PA_DIRECTION_INPUT) { - u->decoder_info = u->bt_codec->init(false, false, u->transport->config, u->transport->config_size, &u->decoder_sample_spec, u->core); + if ((get_profile_direction(u->profile) & PA_DIRECTION_INPUT) || u->bt_codec->support_backchannel) { + u->decoder_info = u->bt_codec->init(false, reverse_backchannel, u->transport->config, u->transport->config_size, &u->decoder_sample_spec, u->core); if (!u->decoder_info) { if (u->encoder_info) { @@ -1420,11 +1424,11 @@ static int init_profile(struct userdata *u) { pa_assert(u->transport); - if (get_profile_direction (u->profile) & PA_DIRECTION_OUTPUT) + if ((get_profile_direction(u->profile) & PA_DIRECTION_OUTPUT) || u->bt_codec->support_backchannel) if (add_sink(u) < 0) r = -1; - if (get_profile_direction (u->profile) & PA_DIRECTION_INPUT) + if ((get_profile_direction(u->profile) & PA_DIRECTION_INPUT) || u->bt_codec->support_backchannel) if (add_source(u) < 0) r = -1; @@ -1625,13 +1629,15 @@ static void thread_func(void *userdata) { skip_bytes -= bytes_to_render; } - if (u->write_index > 0 && (get_profile_direction(u->profile) & PA_DIRECTION_OUTPUT)) { - size_t new_write_block_size = u->bt_codec->reduce_encoder_bitrate(u->encoder_info, u->write_link_mtu); - if (new_write_block_size) { - u->write_block_size = new_write_block_size; - handle_sink_block_size_change(u); + if (u->write_index > 0 && (get_profile_direction(u->profile) & PA_DIRECTION_OUTPUT || u->bt_codec->support_backchannel)) { + if (u->bt_codec->reduce_encoder_bitrate) { + size_t new_write_block_size = u->bt_codec->reduce_encoder_bitrate(u->encoder_info, u->write_link_mtu); + if (new_write_block_size) { + u->write_block_size = new_write_block_size; + handle_sink_block_size_change(u); + } + pa_gettimeofday(&tv_last_output_rate_change); } - pa_gettimeofday(&tv_last_output_rate_change); } } @@ -1674,7 +1680,7 @@ static void thread_func(void *userdata) { sleep_for = time_passed < next_write_at ? next_write_at - time_passed : 0; /* pa_log("Sleeping for %lu; time passed %lu, next write at %lu", (unsigned long) sleep_for, (unsigned long) time_passed, (unsigned long)next_write_at); */ - if ((get_profile_direction(u->profile) & PA_DIRECTION_OUTPUT) && u->write_memchunk.memblock == NULL) { + if ((get_profile_direction(u->profile) & PA_DIRECTION_OUTPUT || u->bt_codec->support_backchannel) && u->write_memchunk.memblock == NULL) { /* bt_write_buffer() is keeping up with input, try increasing bitrate */ if (u->bt_codec->increase_encoder_bitrate && pa_timeval_age(&tv_last_output_rate_change) >= u->device->output_rate_refresh_interval_ms * PA_USEC_PER_MSEC) { @@ -1906,10 +1912,10 @@ static pa_available_t get_port_availability(struct userdata *u, pa_direction_t d for (i = 0; i < PA_BLUETOOTH_PROFILE_COUNT; i++) { pa_bluetooth_transport *transport; - if (!(get_profile_direction(i) & direction)) + if (!(transport = u->device->transports[i])) continue; - if (!(transport = u->device->transports[i])) + if (!(get_profile_direction(i) & direction || (transport->bt_codec && transport->bt_codec->support_backchannel))) continue; switch(transport->state) { From 697a1a309aa870aa975da2e76a36bcc01fdd360f Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Mon, 6 Sep 2021 19:26:07 +0300 Subject: [PATCH 073/260] bluetooth: Use stereo sample spec for faststream backchannel Faststream backchannel decoder does not know whether incoming stream is mono or stereo before first packet is decoded, and some devices return stereo stream. As it is not easy to change source sample spec after source is created, use stereo sample spec always and perform conversion if mono stream is found. Part-of: --- src/modules/bluetooth/a2dp-codec-sbc.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/modules/bluetooth/a2dp-codec-sbc.c b/src/modules/bluetooth/a2dp-codec-sbc.c index 6c6f99bb8..e912ffb89 100644 --- a/src/modules/bluetooth/a2dp-codec-sbc.c +++ b/src/modules/bluetooth/a2dp-codec-sbc.c @@ -884,7 +884,7 @@ static void *init_faststream(bool for_encoding, bool for_backchannel, const uint pa_assert_not_reached(); } - sample_spec->channels = 1; + sample_spec->channels = 2; sbc_info->mode = SBC_MODE_MONO; sbc_info->initial_bitpool = sbc_info->min_bitpool = sbc_info->max_bitpool = 32; @@ -1275,9 +1275,10 @@ static size_t decode_buffer_faststream(void *codec_info, const uint8_t *input_bu size_t to_write, to_decode; pa_sample_spec decoded_sample_spec = { .format = PA_SAMPLE_S16LE, - .channels = 1, + .channels = 2, .rate = 16000U }; + uint8_t decode_buffer[4096]; p = input_buffer; to_decode = input_size; @@ -1291,25 +1292,37 @@ static size_t decode_buffer_faststream(void *codec_info, const uint8_t *input_bu decoded = sbc_decode(&sbc_info->sbc, p, to_decode, - d, to_write, + decode_buffer, sizeof(decode_buffer), &written); if (PA_UNLIKELY(decoded <= 0)) { pa_log_error("FastStream SBC decoding error (%li)", (long) decoded); decoded = PA_MIN(sbc_info->frame_length, to_decode); written = PA_MIN(sbc_info->codesize, to_write); - pa_silence_memory(d, written, &decoded_sample_spec); + pa_silence_memory(decode_buffer, written, &decoded_sample_spec); } else { /* Reset codesize and frame_length to values found by decoder */ sbc_info->codesize = sbc_get_codesize(&sbc_info->sbc); sbc_info->frame_length = sbc_get_frame_length(&sbc_info->sbc); + if (sbc_info->mode != sbc_info->sbc.mode) + sbc_info->mode = sbc_info->sbc.mode; + if (sbc_info->frequency != sbc_info->sbc.frequency) { /* some devices unexpectedly return SBC frequency different from 16000 * remember this, and keep incoming sample rate at 16000 */ pa_log_debug("FastStream decoder detected SBC frequency %u, expected %u", sbc_info->sbc.frequency, sbc_info->frequency); sbc_info->frequency = sbc_info->sbc.frequency; } + + if (sbc_info->sbc.mode == SBC_MODE_MONO) { + const void *interleave_buf[2] = {decode_buffer, decode_buffer}; + /* mono->stereo conversion needs to fit into remaining output space */ + written = PA_MIN(to_write / 2, written); + pa_interleave(interleave_buf, 2, d, pa_sample_size(&decoded_sample_spec), written / pa_sample_size(&decoded_sample_spec)); + written *= 2; + } else + memcpy(d, decode_buffer, written); } if ((sbc_info->frame_length & 1) && decoded < to_decode) { From 76e01b25f55fb0b82900681ba0616a34d1e4771f Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Wed, 8 Sep 2021 21:03:54 +0300 Subject: [PATCH 074/260] bluetooth: Handle fragmented faststream frames Incoming frames can span multiple packets, add support for this. Part-of: --- src/modules/bluetooth/a2dp-codec-sbc.c | 74 +++++++++++++++++++++----- 1 file changed, 61 insertions(+), 13 deletions(-) diff --git a/src/modules/bluetooth/a2dp-codec-sbc.c b/src/modules/bluetooth/a2dp-codec-sbc.c index e912ffb89..2c069cb6f 100644 --- a/src/modules/bluetooth/a2dp-codec-sbc.c +++ b/src/modules/bluetooth/a2dp-codec-sbc.c @@ -39,6 +39,8 @@ #define SBC_BITPOOL_DEC_STEP 5 #define SBC_BITPOOL_INC_STEP 1 +#define SBC_SYNCWORD 0x9C + struct sbc_info { sbc_t sbc; /* Codec data */ size_t codesize, frame_length; /* SBC Codesize, frame_length. We simply cache those values here */ @@ -54,6 +56,11 @@ struct sbc_info { uint8_t nr_blocks; uint8_t nr_subbands; + + /* Size of SBC frame fragment left over from previous decoding iteration */ + size_t frame_fragment_size; + /* Maximum SBC frame size is 512 bytes when SBC compression ratio > 1 */ + uint8_t frame_fragment[512]; }; static bool can_be_supported(bool for_encoding) { @@ -936,6 +943,9 @@ static int reset(void *codec_info) { struct sbc_info *sbc_info = (struct sbc_info *) codec_info; int ret; + /* forget last saved frame fragment */ + sbc_info->frame_fragment_size = 0; + ret = sbc_reinit(&sbc_info->sbc, 0); if (ret != 0) { pa_log_error("SBC reinitialization failed: %d", ret); @@ -1279,27 +1289,60 @@ static size_t decode_buffer_faststream(void *codec_info, const uint8_t *input_bu .rate = 16000U }; uint8_t decode_buffer[4096]; + uint8_t frame_buffer[4096]; - p = input_buffer; to_decode = input_size; + /* append input buffer to fragment left from previous decode call */ + if (sbc_info->frame_fragment_size) { + + if (sbc_info->frame_fragment_size + to_decode > sizeof(frame_buffer)) { + pa_log_debug("FastStream SBC input (saved + incoming) size %lu larger than buffer size %lu, input truncated to fit", + sbc_info->frame_fragment_size + to_decode, sizeof(frame_buffer)); + to_decode = sizeof(frame_buffer) - sbc_info->frame_fragment_size; + } + + memcpy(frame_buffer, sbc_info->frame_fragment, sbc_info->frame_fragment_size); + memcpy(frame_buffer + sbc_info->frame_fragment_size, input_buffer, to_decode); + + to_decode += sbc_info->frame_fragment_size; + p = frame_buffer; + + /* clear saved fragment */ + sbc_info->frame_fragment_size = 0; + } else + p = input_buffer; + d = output_buffer; to_write = output_size; while (PA_LIKELY(to_decode > 0 && to_write > 0)) { - size_t written; + size_t written = 0; ssize_t decoded; + /* skip to SBC sync word before attempting decode */ + if (*p != SBC_SYNCWORD) { + ++p; + --to_decode; + continue; + } + decoded = sbc_decode(&sbc_info->sbc, p, to_decode, decode_buffer, sizeof(decode_buffer), &written); if (PA_UNLIKELY(decoded <= 0)) { + /* sbc_decode returns -1 if input too short, + * break from loop to save this frame fragment for next decode iteration */ + if (decoded == -1) { + pa_log_debug("FastStream SBC decoding error (%li) input %lu is too short", (long) decoded, to_decode); + break; + } + + /* otherwise failed to decode frame, skip to next SBC sync word */ pa_log_error("FastStream SBC decoding error (%li)", (long) decoded); - decoded = PA_MIN(sbc_info->frame_length, to_decode); - written = PA_MIN(sbc_info->codesize, to_write); - pa_silence_memory(decode_buffer, written, &decoded_sample_spec); + decoded = 1; } else { /* Reset codesize and frame_length to values found by decoder */ sbc_info->codesize = sbc_get_codesize(&sbc_info->sbc); @@ -1325,14 +1368,7 @@ static size_t decode_buffer_faststream(void *codec_info, const uint8_t *input_bu memcpy(d, decode_buffer, written); } - if ((sbc_info->frame_length & 1) && decoded < to_decode) { - ++decoded; - ++sbc_info->frame_length; - } - pa_assert_fp((size_t) decoded <= to_decode); - pa_assert_fp((size_t) decoded == PA_MIN(sbc_info->frame_length, to_decode)); - pa_assert_fp((size_t) written <= to_write); p += decoded; @@ -1342,7 +1378,19 @@ static size_t decode_buffer_faststream(void *codec_info, const uint8_t *input_bu to_write -= written; } - /* XXX eat remainder, may need to fix this if input frames are split across packets */ + if (to_decode) { + if (to_decode > sizeof(sbc_info->frame_fragment)) { + pa_log_debug("FastStream remaining SBC fragment size %lu larger than buffer size %lu, remainder truncated to fit", + to_decode, sizeof(sbc_info->frame_fragment)); + p += to_decode - sizeof(sbc_info->frame_fragment); + to_decode = sizeof(sbc_info->frame_fragment); + } + + pa_log_debug("FastStream saving SBC fragment size %lu for next decoding iteration", to_decode); + memcpy(sbc_info->frame_fragment, p, to_decode); + sbc_info->frame_fragment_size = to_decode; + } + *processed = input_size; return d - output_buffer; From f2b748e851668acc67a8dcc190ff8ba822fa034e Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Fri, 10 Sep 2021 23:21:09 +0300 Subject: [PATCH 075/260] bluetooth: Add 20dB boost for faststream source volume Some devices unexpectedly return stereo backchannel stream with wrong frequency, and volume of backchannel stream appears too low. If this happens, boost source volume by 20dB. Part-of: --- src/modules/bluetooth/a2dp-codec-sbc.c | 19 ++++++++++++ src/modules/bluetooth/bt-codec-api.h | 3 ++ src/modules/bluetooth/module-bluez5-device.c | 31 ++++++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/src/modules/bluetooth/a2dp-codec-sbc.c b/src/modules/bluetooth/a2dp-codec-sbc.c index 2c069cb6f..5476697f8 100644 --- a/src/modules/bluetooth/a2dp-codec-sbc.c +++ b/src/modules/bluetooth/a2dp-codec-sbc.c @@ -57,6 +57,7 @@ struct sbc_info { uint8_t nr_blocks; uint8_t nr_subbands; + bool boost_source_volume; /* Size of SBC frame fragment left over from previous decoding iteration */ size_t frame_fragment_size; /* Maximum SBC frame size is 512 bytes when SBC compression ratio > 1 */ @@ -943,6 +944,9 @@ static int reset(void *codec_info) { struct sbc_info *sbc_info = (struct sbc_info *) codec_info; int ret; + /* forget about source volume boost */ + sbc_info->boost_source_volume = false; + /* forget last saved frame fragment */ sbc_info->frame_fragment_size = 0; @@ -1356,6 +1360,10 @@ static size_t decode_buffer_faststream(void *codec_info, const uint8_t *input_bu * remember this, and keep incoming sample rate at 16000 */ pa_log_debug("FastStream decoder detected SBC frequency %u, expected %u", sbc_info->sbc.frequency, sbc_info->frequency); sbc_info->frequency = sbc_info->sbc.frequency; + + /* volume is too low for known devices with unexpected source SBC frequency */ + pa_log_debug("FastStream decoder requesting 20dB boost for source volume"); + sbc_info->boost_source_volume = true; } if (sbc_info->sbc.mode == SBC_MODE_MONO) { @@ -1396,6 +1404,16 @@ static size_t decode_buffer_faststream(void *codec_info, const uint8_t *input_bu return d - output_buffer; } +/* Boost sink backchannel mic volume by 20dB as it appears too quiet */ +double get_source_output_volume_factor_dB_faststream(void *codec_info) { + struct sbc_info *sbc_info = (struct sbc_info *) codec_info; + + if (sbc_info->boost_source_volume) + return 20.; + + return 1.0; +} + const pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_sbc = { .id = { A2DP_CODEC_SBC, 0, 0 }, .can_be_supported = can_be_supported, @@ -1547,5 +1565,6 @@ const pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_faststream = { .get_encoded_block_size = get_encoded_block_size_faststream, .encode_buffer = encode_buffer_faststream, .decode_buffer = decode_buffer_faststream, + .get_source_output_volume_factor_dB = get_source_output_volume_factor_dB_faststream, }, }; diff --git a/src/modules/bluetooth/bt-codec-api.h b/src/modules/bluetooth/bt-codec-api.h index 3ed47166a..700c28753 100644 --- a/src/modules/bluetooth/bt-codec-api.h +++ b/src/modules/bluetooth/bt-codec-api.h @@ -67,4 +67,7 @@ typedef struct pa_bt_codec { * returns size of filled ouput_buffer and set processed to size of * processed input_buffer */ size_t (*decode_buffer)(void *codec_info, const uint8_t *input_buffer, size_t input_size, uint8_t *output_buffer, size_t output_size, size_t *processed); + + /* Get volume factor which needs to be applied to output samples */ + double (*get_source_output_volume_factor_dB)(void *codec_info); } pa_bt_codec; diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c index f50521c59..ab1bc098e 100644 --- a/src/modules/bluetooth/module-bluez5-device.c +++ b/src/modules/bluetooth/module-bluez5-device.c @@ -116,6 +116,8 @@ struct userdata { pa_hook_slot *sink_volume_changed_slot; pa_hook_slot *source_volume_changed_slot; + pa_hook_slot *source_output_new_hook_slot; + pa_bluetooth_discovery *discovery; pa_bluetooth_device *device; pa_bluetooth_transport *transport; @@ -2755,6 +2757,30 @@ static int device_process_msg(pa_msgobject *obj, int code, void *data, int64_t o return 0; } +/* Run from main thread */ +static pa_hook_result_t a2dp_source_output_fixate_hook_callback(pa_core *c, pa_source_output_new_data *new_data, struct userdata *u) { + double volume_factor_dB; + pa_cvolume cv; + + pa_assert(c); + pa_assert(new_data); + pa_assert(u); + + /* When transport is released, there is no decoder and no codec */ + if (!u->bt_codec || !u->decoder_info) + return PA_HOOK_OK; + + if (!u->bt_codec->get_source_output_volume_factor_dB) + return PA_HOOK_OK; + + volume_factor_dB = u->bt_codec->get_source_output_volume_factor_dB(u->decoder_info); + + pa_cvolume_set(&cv, u->decoder_sample_spec.channels, pa_sw_volume_from_dB(volume_factor_dB)); + pa_source_output_new_data_apply_volume_factor_source(new_data, &cv); + + return PA_HOOK_OK; +} + int pa__init(pa_module* m) { struct userdata *u; const char *path; @@ -2836,6 +2862,8 @@ int pa__init(pa_module* m) { u->transport_source_volume_changed_slot = pa_hook_connect(pa_bluetooth_discovery_hook(u->discovery, PA_BLUETOOTH_HOOK_TRANSPORT_SOURCE_VOLUME_CHANGED), PA_HOOK_NORMAL, (pa_hook_cb_t) transport_source_volume_changed_cb, u); + u->source_output_new_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], PA_HOOK_EARLY, (pa_hook_cb_t) a2dp_source_output_fixate_hook_callback, u); + if (add_card(u) < 0) goto fail; @@ -2899,6 +2927,9 @@ void pa__done(pa_module *m) { stop_thread(u); + if (u->source_output_new_hook_slot) + pa_hook_slot_free(u->source_output_new_hook_slot); + if (u->device_connection_changed_slot) pa_hook_slot_free(u->device_connection_changed_slot); From 3f9455411c90d2b2d1043c47ee24185fabb8e401 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Wed, 31 Aug 2022 21:26:55 +1000 Subject: [PATCH 076/260] Propagate return value from pa_pstream_attach_memfd_shmid Using wine, The mmap call in shm_attach sometimes fails with ENOMEM which isn't propagated up the call stack. Signed-off-by: Alistair Leslie-Hughes Part-of: --- src/pulsecore/native-common.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pulsecore/native-common.c b/src/pulsecore/native-common.c index 282a4ed3b..e59807385 100644 --- a/src/pulsecore/native-common.c +++ b/src/pulsecore/native-common.c @@ -64,7 +64,8 @@ int pa_common_command_register_memfd_shmid(pa_pstream *p, pa_pdispatch *pd, uint if (version < 31 || pa_tagstruct_getu32(t, &shm_id) < 0 || !pa_tagstruct_eof(t)) goto finish; - pa_pstream_attach_memfd_shmid(p, shm_id, ancil->fds[0]); + if (pa_pstream_attach_memfd_shmid(p, shm_id, ancil->fds[0])) + goto finish; ret = 0; finish: From 3349e1c471f16f46251a51acfc1740cdf012a098 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 21 Oct 2022 12:30:34 +0200 Subject: [PATCH 077/260] sndfile: handle sndfiles with s24 format Samples with s24 format should be read with the readf_int read function instead of the raw function. This fixes playback of flac/wav with s24 sample format. Part-of: --- src/pulsecore/sndfile-util.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pulsecore/sndfile-util.c b/src/pulsecore/sndfile-util.c index b6cc65ecd..e978d622c 100644 --- a/src/pulsecore/sndfile-util.c +++ b/src/pulsecore/sndfile-util.c @@ -51,11 +51,11 @@ int pa_sndfile_read_sample_spec(SNDFILE *sf, pa_sample_spec *ss) { ss->format = PA_SAMPLE_S16NE; break; - case SF_FORMAT_PCM_24: - ss->format = PA_SAMPLE_S24NE; - break; - case SF_FORMAT_PCM_32: + case SF_FORMAT_PCM_24: + /* note that libsndfile will convert 24 bits samples to 32 bits + * when using the sf_readf_int function, which will be selected + * by setting the format to s32. */ ss->format = PA_SAMPLE_S32NE; break; From e650c2b33e4fefc0589751b3958bd3b5d3b423ac Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Thu, 3 Nov 2022 09:22:48 +1100 Subject: [PATCH 078/260] Ensure fds are closed when exec functions are used. When usng shm_open, FD_CLOEXEC is set explicitly. However when using memfd_create, we must pass the MFD_CLOEXEC flag to ensure the same fcntl value (FD_CLOEXEC) is set. Fixes #1394 Part-of: --- src/pulsecore/shm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pulsecore/shm.c b/src/pulsecore/shm.c index e464f6bce..ff54dcb59 100644 --- a/src/pulsecore/shm.c +++ b/src/pulsecore/shm.c @@ -164,7 +164,7 @@ static int sharedmem_create(pa_shm *m, pa_mem_type_t type, size_t size, mode_t m #endif #ifdef HAVE_MEMFD case PA_MEM_TYPE_SHARED_MEMFD: - fd = memfd_create("pulseaudio", MFD_ALLOW_SEALING); + fd = memfd_create("pulseaudio", MFD_ALLOW_SEALING|MFD_CLOEXEC); break; #endif default: From 3c63f8e6dca855177d9fb75b735976ff3c7a88fb Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Thu, 24 Nov 2022 02:26:02 +0300 Subject: [PATCH 079/260] backend-native: Fix stack corruption reading RFCOMM AT+BIA= response On-stack buffer size is too short for sscanf to read AT+BIA= and AT+BAC= response strings which have variable length. Fix this by replacing sscanf with proper copy of input string. Fixes: cca0d6937 ("bluetooth: add AT+BIA support") Part-of: --- src/modules/bluetooth/backend-native.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c index bda9c7fa0..86bdbec60 100644 --- a/src/modules/bluetooth/backend-native.c +++ b/src/modules/bluetooth/backend-native.c @@ -617,7 +617,7 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf struct transport_data *trd = t->userdata; pa_bluetooth_backend *b = trd->backend; int indicator, mode, val; - char str[5]; + char *str; const char *r; size_t len; const char *state = NULL; @@ -635,9 +635,10 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf c->state = 1; return true; - } else if (sscanf(buf, "AT+BIA=%s", str) == 1) { + } else if (pa_startswith(buf, "AT+BIA=")) { /* Indicators start with index 1 and follow the order of the AT+CIND=? response */ + str = pa_xstrdup(buf + 7); for (indicator = 1; (r = pa_split_in_place(str, ",", &len, &state)); indicator++) { /* Ignore updates to mandatory indicators which are always ON */ if (indicator == CIND_CALL_INDICATOR @@ -656,21 +657,25 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf else { pa_log_error("Unable to parse indicator of AT+BIA command: %s", buf); rfcomm_write_response(fd, "ERROR"); + pa_xfree(str); return false; } } + pa_xfree(str); return true; - } else if (sscanf(buf, "AT+BAC=%3s", str) == 1) { + } else if (pa_startswith(buf, "AT+BAC=")) { c->support_msbc = false; /* check if codec id 2 (mSBC) is in the list of supported codecs */ + str = pa_xstrdup(buf + 7); while ((r = pa_split_in_place(str, ",", &len, &state))) { if (len == 1 && r[0] == '2') { c->support_msbc = true; break; } } + pa_xfree(str); c->support_codec_negotiation = true; From 37c72c20720d6f7fefeeb151f5e10c2cd0dda30e Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Sun, 27 Nov 2022 22:30:45 +0300 Subject: [PATCH 080/260] module-combine-sink: Do not set up rate adjustment timer at load time Rate adjustment timer is set up when combine sink is resumed and relased when combine sink is suspended. Do not create this timer again while module is loaded to prevent duplicate effort causing assertion in time_callback. Part-of: --- src/modules/module-combine-sink.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/modules/module-combine-sink.c b/src/modules/module-combine-sink.c index f98f4820b..4b7690183 100644 --- a/src/modules/module-combine-sink.c +++ b/src/modules/module-combine-sink.c @@ -1711,9 +1711,6 @@ int pa__init(pa_module*m) { PA_IDXSET_FOREACH(o, u->outputs, idx) output_verify(o); - if (u->adjust_time > 0) - u->time_event = pa_core_rttime_new(m->core, pa_rtclock_now() + u->adjust_time, time_callback, u); - pa_modargs_free(ma); return 0; From 0cbbc408aee2b5f2c42280d24dc615405387b5b1 Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Sun, 27 Nov 2022 19:39:23 +0300 Subject: [PATCH 081/260] module-combine-sink: Suspend while unloading to fix crash moving sinks Part-of: --- src/modules/module-combine-sink.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/modules/module-combine-sink.c b/src/modules/module-combine-sink.c index 4b7690183..2ccd9eb13 100644 --- a/src/modules/module-combine-sink.c +++ b/src/modules/module-combine-sink.c @@ -1733,6 +1733,9 @@ void pa__done(pa_module*m) { if (!(u = m->userdata)) return; + if (u->sink && PA_SINK_IS_LINKED(u->sink->state)) + pa_sink_suspend(u->sink, true, PA_SUSPEND_UNAVAILABLE); + pa_strlist_free(u->unlinked_slaves); if (u->sink_put_slot) From e4517da353b86a527f443afa112a4773c018d7e9 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Tue, 6 Dec 2022 09:32:55 +1100 Subject: [PATCH 082/260] pactl: Stop a crash when setting the volume which is out of range Part-of: --- src/utils/pactl.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/utils/pactl.c b/src/utils/pactl.c index 9e343954f..d3736bc48 100644 --- a/src/utils/pactl.c +++ b/src/utils/pactl.c @@ -1870,6 +1870,7 @@ static void get_sink_volume_callback(pa_context *c, const pa_sink_info *i, int i static void set_sink_volume_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) { pa_cvolume cv; + pa_operation *o; if (is_last < 0) { pa_log(_("Failed to get sink information: %s"), pa_strerror(pa_context_errno(c))); @@ -1885,7 +1886,13 @@ static void set_sink_volume_callback(pa_context *c, const pa_sink_info *i, int i cv = i->volume; fill_volume(&cv, i->channel_map.channels); - pa_operation_unref(pa_context_set_sink_volume_by_name(c, sink_name, &cv, simple_callback, NULL)); + o = pa_context_set_sink_volume_by_name(c, sink_name, &cv, simple_callback, NULL); + if (o) + pa_operation_unref(o); + else { + pa_log(_("Failed to set sink volume: %s"), pa_strerror(pa_context_errno(c))); + complete_action(); + } } static void get_source_mute_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) { @@ -1929,6 +1936,7 @@ static void get_source_volume_callback(pa_context *c, const pa_source_info *i, i static void set_source_volume_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) { pa_cvolume cv; + pa_operation *o; if (is_last < 0) { pa_log(_("Failed to get source information: %s"), pa_strerror(pa_context_errno(c))); @@ -1944,7 +1952,13 @@ static void set_source_volume_callback(pa_context *c, const pa_source_info *i, i cv = i->volume; fill_volume(&cv, i->channel_map.channels); - pa_operation_unref(pa_context_set_source_volume_by_name(c, source_name, &cv, simple_callback, NULL)); + o = pa_context_set_source_volume_by_name(c, source_name, &cv, simple_callback, NULL); + if (o) + pa_operation_unref(o); + else { + pa_log(_("Failed to set source volume: %s"), pa_strerror(pa_context_errno(c))); + complete_action(); + } } static void get_sink_input_volume_callback(pa_context *c, const pa_sink_input_info *i, int is_last, void *userdata) { From 47a6918739cb06dafa970d0b528bed1951d95039 Mon Sep 17 00:00:00 2001 From: Shunsuke Shimizu Date: Mon, 29 Aug 2022 04:13:55 +0900 Subject: [PATCH 083/260] build-sys: Fix macOS build * Enable macOS specific modules (module-bonjour-publish, module-coreaudio-detect and module-coreaudio-device) * Correctly set `PA_SOEXT` (.so, .dylib and .dll) * Build `poll-posix.c` and `semaphore-osx.c` * Drop linker flag `-Wl,-z,nodelete` on Darwin * Drop linker flag `-Wl,--no-undefined` on Darwin * Prefer to `clock_gettime` over compat impl for old Darwin * Disable SCM credential on Darwin Part-of: --- meson.build | 10 ++++++++-- src/meson.build | 9 +++++++-- src/modules/meson.build | 21 +++++++++++++++++---- src/pulse/meson.build | 12 ++++++++---- src/pulsecore/core-rtclock.c | 25 ++++++++++++------------- src/pulsecore/creds.h | 2 +- 6 files changed, 53 insertions(+), 26 deletions(-) diff --git a/meson.build b/meson.build index 9f47b2f02..b678bb531 100644 --- a/meson.build +++ b/meson.build @@ -150,7 +150,13 @@ cdata.set_quoted('PA_MACHINE_ID', join_paths(sysconfdir, 'machine-id')) cdata.set_quoted('PA_MACHINE_ID_FALLBACK', join_paths(localstatedir, 'lib', 'dbus', 'machine-id')) cdata.set_quoted('PA_SRCDIR', join_paths(meson.current_source_dir(), 'src')) cdata.set_quoted('PA_BUILDDIR', meson.current_build_dir()) -cdata.set_quoted('PA_SOEXT', '.so') +if host_machine.system() == 'windows' + cdata.set_quoted('PA_SOEXT', '.dll') +elif host_machine.system() == 'darwin' + cdata.set_quoted('PA_SOEXT', '.dylib') +else + cdata.set_quoted('PA_SOEXT', '.so') +endif cdata.set_quoted('PA_DEFAULT_CONFIG_DIR', pulsesysconfdir) cdata.set('PA_DEFAULT_CONFIG_DIR_UNQUOTED', pulsesysconfdir) cdata.set_quoted('PA_BINARY', join_paths(bindir, 'pulseaudio')) @@ -426,7 +432,7 @@ cdata.set('MESON_BUILD', 1) # so we request the nodelete flag to be enabled. # On other systems, we don't really know how to do that, but it's welcome if somebody can tell. # Windows doesn't support this flag. -if host_machine.system() != 'windows' +if host_machine.system() != 'windows' and host_machine.system() != 'darwin' nodelete_link_args = ['-Wl,-z,nodelete'] else nodelete_link_args = [] diff --git a/src/meson.build b/src/meson.build index 9efb561d8..2069d2803 100644 --- a/src/meson.build +++ b/src/meson.build @@ -182,9 +182,14 @@ if host_machine.system() == 'windows' else libpulsecommon_sources += [ 'pulsecore/mutex-posix.c', - 'pulsecore/semaphore-posix.c', - 'pulsecore/thread-posix.c' + 'pulsecore/poll-posix.c', + 'pulsecore/thread-posix.c', ] + if host_machine.system() == 'darwin' + libpulsecommon_sources += ['pulsecore/semaphore-osx.c'] + else + libpulsecommon_sources += ['pulsecore/semaphore-posix.c'] + endif endif # FIXME: Do SIMD things diff --git a/src/modules/meson.build b/src/modules/meson.build index 1e12569dc..3636ce0de 100644 --- a/src/modules/meson.build +++ b/src/modules/meson.build @@ -8,15 +8,12 @@ all_modules = [ [ 'module-always-sink', 'module-always-sink.c' ], [ 'module-always-source', 'module-always-source.c' ], [ 'module-augment-properties', 'module-augment-properties.c' ], -# [ 'module-bonjour-publish', 'macosx/module-bonjour-publish.c' ], [ 'module-card-restore', 'module-card-restore.c' ], [ 'module-cli', 'module-cli.c', [], [], [], libcli ], [ 'module-cli-protocol-tcp', 'module-protocol-stub.c', [], ['-DUSE_PROTOCOL_CLI', '-DUSE_TCP_SOCKETS'], [], libprotocol_cli ], [ 'module-cli-protocol-unix', 'module-protocol-stub.c', [], ['-DUSE_PROTOCOL_CLI', '-DUSE_UNIX_SOCKETS'], [], libprotocol_cli ], [ 'module-combine', 'module-combine.c' ], [ 'module-combine-sink', 'module-combine-sink.c', [], [], [libatomic_ops_dep] ], -# [ 'module-coreaudio-detect', 'macosx/module-coreaudio-detect.c' ], -# [ 'module-coreaudio-device', 'macosx/module-coreaudio-device.c' ], [ 'module-default-device-restore', 'module-default-device-restore.c', [], [], [], libprotocol_native ], [ 'module-detect', 'module-detect.c' ], [ 'module-device-manager', 'module-device-manager.c', [], [], [], libprotocol_native ], @@ -78,6 +75,16 @@ if host_machine.system() != 'windows' ] endif +if host_machine.system() == 'darwin' + bonjour_dep = dependency('appleframeworks', modules : ['CoreFoundation']) + coreaudio_dep = dependency('appleframeworks', modules : ['CoreAudio']) + all_modules += [ + [ 'module-bonjour-publish', 'macosx/module-bonjour-publish.c', [], [], [bonjour_dep] ], + [ 'module-coreaudio-detect', 'macosx/module-coreaudio-detect.c', [], [], [coreaudio_dep] ], + [ 'module-coreaudio-device', 'macosx/module-coreaudio-device.c', [], [], [coreaudio_dep] ], + ] +endif + # Modules enabled by headers if cc.has_header('linux/input.h') @@ -298,6 +305,12 @@ all_modules += [ # FIXME: meson doesn't support multiple RPATH arguments currently rpath_dirs = join_paths(privlibdir) + ':' + join_paths(modlibexecdir) +if host_machine.system() != 'windows' and host_machine.system() != 'darwin' + no_undefined_args = ['-Wl,--no-undefined'] +else + no_undefined_args = [] +endif + foreach m : all_modules name = m[0] sources = m[1] @@ -315,7 +328,7 @@ foreach m : all_modules install_rpath : rpath_dirs, install_dir : modlibexecdir, dependencies : [thread_dep, libpulse_dep, libpulsecommon_dep, libpulsecore_dep, libintl_dep, platform_dep, platform_socket_dep] + extra_deps, - link_args : [nodelete_link_args, '-Wl,--no-undefined' ], + link_args : [nodelete_link_args, no_undefined_args], link_with : extra_libs, name_prefix : '', implicit_include_directories : false) diff --git a/src/pulse/meson.build b/src/pulse/meson.build index 1b82c807c..40d407963 100644 --- a/src/pulse/meson.build +++ b/src/pulse/meson.build @@ -70,11 +70,15 @@ if glib_dep.found() libpulse_headers += 'glib-mainloop.h' endif -run_target('update-map-file', - command : [ join_paths(meson.source_root(), 'scripts/generate-map-file.sh'), 'map-file', - [ libpulse_headers, 'simple.h', join_paths(meson.build_root(), 'src', 'pulse', 'version.h') ] ]) +if host_machine.system() != 'windows' and host_machine.system() != 'darwin' + run_target('update-map-file', + command : [ join_paths(meson.source_root(), 'scripts/generate-map-file.sh'), 'map-file', + [ libpulse_headers, 'simple.h', join_paths(meson.build_root(), 'src', 'pulse', 'version.h') ] ]) -versioning_link_args = '-Wl,-version-script=' + join_paths(meson.source_root(), 'src', 'pulse', 'map-file') + versioning_link_args = ['-Wl,-version-script=' + join_paths(meson.source_root(), 'src', 'pulse', 'map-file')] +else + versioning_link_args = [] +endif libpulse = shared_library('pulse', libpulse_sources, diff --git a/src/pulsecore/core-rtclock.c b/src/pulsecore/core-rtclock.c index 2c2e28631..d0cf15731 100644 --- a/src/pulsecore/core-rtclock.c +++ b/src/pulsecore/core-rtclock.c @@ -65,19 +65,7 @@ pa_usec_t pa_rtclock_age(const struct timeval *tv) { struct timeval *pa_rtclock_get(struct timeval *tv) { -#if defined(OS_IS_DARWIN) - uint64_t val, abs_time = mach_absolute_time(); - Nanoseconds nanos; - - nanos = AbsoluteToNanoseconds(*(AbsoluteTime *) &abs_time); - val = *(uint64_t *) &nanos; - - tv->tv_sec = val / PA_NSEC_PER_SEC; - tv->tv_usec = (val % PA_NSEC_PER_SEC) / PA_NSEC_PER_USEC; - - return tv; - -#elif defined(HAVE_CLOCK_GETTIME) +#if defined(HAVE_CLOCK_GETTIME) struct timespec ts; #ifdef CLOCK_MONOTONIC @@ -97,6 +85,17 @@ struct timeval *pa_rtclock_get(struct timeval *tv) { tv->tv_sec = ts.tv_sec; tv->tv_usec = ts.tv_nsec / PA_NSEC_PER_USEC; + return tv; +#elif defined(OS_IS_DARWIN) + uint64_t val, abs_time = mach_absolute_time(); + Nanoseconds nanos; + + nanos = AbsoluteToNanoseconds(*(AbsoluteTime *) &abs_time); + val = *(uint64_t *) &nanos; + + tv->tv_sec = val / PA_NSEC_PER_SEC; + tv->tv_usec = (val % PA_NSEC_PER_SEC) / PA_NSEC_PER_USEC; + return tv; #elif defined(OS_IS_WIN32) if (counter_freq > 0) { diff --git a/src/pulsecore/creds.h b/src/pulsecore/creds.h index b599b569c..acfdd9d43 100644 --- a/src/pulsecore/creds.h +++ b/src/pulsecore/creds.h @@ -34,7 +34,7 @@ typedef struct pa_creds pa_creds; typedef struct pa_cmsg_ancil_data pa_cmsg_ancil_data; -#if defined(SCM_CREDENTIALS) || defined(SCM_CREDS) +#if (defined(SCM_CREDENTIALS) || defined(SCM_CREDS)) && !defined(OS_IS_DARWIN) #define HAVE_CREDS 1 From 89ce6321bd19452097392ddfb416bc51a280b63e Mon Sep 17 00:00:00 2001 From: Mart Raudsepp Date: Wed, 30 Nov 2022 09:25:22 +0200 Subject: [PATCH 084/260] proplist-util: Don't assume gdkx is there as gtk could be built without it Part-of: --- src/pulsecore/proplist-util.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/pulsecore/proplist-util.c b/src/pulsecore/proplist-util.c index 16ea9e006..1330ef5ef 100644 --- a/src/pulsecore/proplist-util.c +++ b/src/pulsecore/proplist-util.c @@ -51,10 +51,12 @@ static const gchar* _g_get_application_name(void) PA_GCC_WEAKREF(g_get_applicati #if defined(HAVE_GTK) && defined(PA_GCC_WEAKREF) #pragma GCC diagnostic ignored "-Wstrict-prototypes" #include -#include static const gchar* _gtk_window_get_default_icon_name(void) PA_GCC_WEAKREF(gtk_window_get_default_icon_name); +#ifdef GDK_WINDOWING_X11 +#include static Display *_gdk_display PA_GCC_WEAKREF(gdk_display); #endif +#endif #include "proplist-util.h" @@ -89,6 +91,7 @@ static void add_gtk_properties(pa_proplist *p) { pa_proplist_sets(p, PA_PROP_APPLICATION_ICON_NAME, t); } +#ifdef GDK_WINDOWING_X11 if (!pa_proplist_contains(p, PA_PROP_WINDOW_X11_DISPLAY)) if (&_gdk_display && _gdk_display) { const char *t; @@ -99,6 +102,7 @@ static void add_gtk_properties(pa_proplist *p) { pa_proplist_sets(p, PA_PROP_WINDOW_X11_DISPLAY, t); } +#endif #endif } From 96bd4e57b5b02dc04b61528033f283f5fea7e723 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Wed, 14 Dec 2022 13:27:12 +1100 Subject: [PATCH 085/260] pulsecore: Set errno before calling read Part-of: --- src/pulsecore/core-util.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index c383a61c0..5d2bae92f 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -407,6 +407,7 @@ finish: * by the caller. */ ssize_t pa_read(int fd, void *buf, size_t count, int *type) { + errno = 0; #ifdef OS_IS_WIN32 if (!type || *type == 0) { From c3eae5d00cb79bd897049483126e75bb48a69cd1 Mon Sep 17 00:00:00 2001 From: flyingOwl Date: Fri, 30 Dec 2022 00:16:03 +0100 Subject: [PATCH 086/260] time-smoother-2: Fix time calculation by comparing timestamps This fixes the rare case of resume_time being bigger than time_stamp. Which happens sometimes when a gstreamer client is quickly seeking through a media file. The resulting integer underflow then causes a huge value in current_time which will break the playback. Part-of: --- src/pulsecore/time-smoother_2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pulsecore/time-smoother_2.c b/src/pulsecore/time-smoother_2.c index ea7ec1b36..46cc5e9cc 100644 --- a/src/pulsecore/time-smoother_2.c +++ b/src/pulsecore/time-smoother_2.c @@ -307,7 +307,8 @@ pa_usec_t pa_smoother_2_get(pa_smoother_2 *s, pa_usec_t time_stamp) { /* If we are initializing, add the time since resume to the card time at pause_time */ else if (s->init) { current_time += (s->pause_time - s->start_time - s->time_offset - s->fixup_time) * s->time_factor; - current_time += (time_stamp - s->resume_time) * s->time_factor; + if (time_stamp > s->resume_time) + current_time += (time_stamp - s->resume_time) * s->time_factor; /* Smoother is running, calculate current sound card time */ } else From 33129c88dc7a8d18b7f0aa8ef563c50a7904d00c Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Thu, 19 Jan 2023 21:30:19 +0300 Subject: [PATCH 087/260] backend-native: Fix parsing comma-delimited response Incoming RFCOMM string has extra end-of-command terminating character which breaks both AT+BIA= and AT+BAC= parsers which only expect a comma. This leads to error parsing last element of response in both cases and could prevent detecting mSBC availability if mSBC codec id comes last, e.g. AT+BIA=1,2 Fix this by additionally checking for delimiters in both parsers. Fixes: 3c63f8e6d ("backend-native: Fix stack corruption reading RFCOMM AT+BIA= response") Part-of: --- src/modules/bluetooth/backend-native.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c index 86bdbec60..829d7bf82 100644 --- a/src/modules/bluetooth/backend-native.c +++ b/src/modules/bluetooth/backend-native.c @@ -639,7 +639,7 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf /* Indicators start with index 1 and follow the order of the AT+CIND=? response */ str = pa_xstrdup(buf + 7); - for (indicator = 1; (r = pa_split_in_place(str, ",", &len, &state)); indicator++) { + for (indicator = 1; (r = pa_split_in_place(str, ",\r\n", &len, &state)); indicator++) { /* Ignore updates to mandatory indicators which are always ON */ if (indicator == CIND_CALL_INDICATOR || indicator == CIND_CALL_SETUP_INDICATOR @@ -669,7 +669,7 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf /* check if codec id 2 (mSBC) is in the list of supported codecs */ str = pa_xstrdup(buf + 7); - while ((r = pa_split_in_place(str, ",", &len, &state))) { + while ((r = pa_split_in_place(str, ",\r\n", &len, &state))) { if (len == 1 && r[0] == '2') { c->support_msbc = true; break; From 94dd7b4b7b01470d09102402482866ff89037f42 Mon Sep 17 00:00:00 2001 From: Georg Chini Date: Sat, 7 Jan 2023 19:45:17 +0100 Subject: [PATCH 088/260] stream-interaction: Extend trigger groups to module-role-cork For module-role-ducking, trigger and ducking groups were introduced some years ago. This patch extends the functionality to module-role-cork, so that trigger and cork roles may now contain "/" separated groups. Part-of: --- src/modules/stream-interaction.c | 54 ++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/src/modules/stream-interaction.c b/src/modules/stream-interaction.c index 993b4c3b2..b2602f5aa 100644 --- a/src/modules/stream-interaction.c +++ b/src/modules/stream-interaction.c @@ -423,6 +423,9 @@ int pa_stream_interaction_init(pa_module *m, const char* const v_modargs[]) { bool global = false; bool source_trigger = false; uint32_t i = 0; + uint32_t group_count_tr = 0; + uint32_t group_count_du = 0; + uint32_t group_count_vol = 0; pa_assert(m); @@ -441,30 +444,28 @@ int pa_stream_interaction_init(pa_module *m, const char* const v_modargs[]) { u->n_groups = 1; + roles = pa_modargs_get_value(ma, "trigger_roles", NULL); + if (roles) { + const char *split_state = NULL; + char *n = NULL; + while ((n = pa_split(roles, "/", &split_state))) { + group_count_tr++; + pa_xfree(n); + } + } + roles = pa_modargs_get_value(ma, u->duck ? "ducking_roles" : "cork_roles", NULL); + if (roles) { + const char *split_state = NULL; + char *n = NULL; + while ((n = pa_split(roles, "/", &split_state))) { + group_count_du++; + pa_xfree(n); + } + } + if (u->duck) { const char *volumes; - uint32_t group_count_tr = 0; - uint32_t group_count_du = 0; - uint32_t group_count_vol = 0; - roles = pa_modargs_get_value(ma, "trigger_roles", NULL); - if (roles) { - const char *split_state = NULL; - char *n = NULL; - while ((n = pa_split(roles, "/", &split_state))) { - group_count_tr++; - pa_xfree(n); - } - } - roles = pa_modargs_get_value(ma, "ducking_roles", NULL); - if (roles) { - const char *split_state = NULL; - char *n = NULL; - while ((n = pa_split(roles, "/", &split_state))) { - group_count_du++; - pa_xfree(n); - } - } volumes = pa_modargs_get_value(ma, "volume", NULL); if (volumes) { const char *split_state = NULL; @@ -480,11 +481,16 @@ int pa_stream_interaction_init(pa_module *m, const char* const v_modargs[]) { pa_log("Invalid number of groups"); goto fail; } - - if (group_count_tr > 0) - u->n_groups = group_count_tr; + } else { + if ((group_count_tr > 1 || group_count_du > 1) && (group_count_tr != group_count_du)) { + pa_log("Invalid number of groups"); + goto fail; + } } + if (group_count_tr > 0) + u->n_groups = group_count_tr; + u->groups = pa_xnew0(struct group*, u->n_groups); for (i = 0; i < u->n_groups; i++) { u->groups[i] = pa_xnew0(struct group, 1); From 6473e9ed0e3fc3c9be4d6d3df93183f44a0dcb85 Mon Sep 17 00:00:00 2001 From: Georg Chini Date: Sun, 8 Jan 2023 13:33:25 +0100 Subject: [PATCH 089/260] stream-interaction: Fix regression when a trigger role is also a cork role If the same role is named in trigger_roles and cork_roles, a stream with that role will crash PA. This patch fixes the crash and re-introduces the old behavior, so that for example specifying trigger_roles=alarm, phone and cork_roles=alarm, multimedia means that a phone stream will cork alarm and multimedia streams while an alarm stream will only cork multimedia streams. Part-of: --- src/modules/stream-interaction.c | 35 +++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/src/modules/stream-interaction.c b/src/modules/stream-interaction.c index b2602f5aa..a6440087c 100644 --- a/src/modules/stream-interaction.c +++ b/src/modules/stream-interaction.c @@ -100,7 +100,7 @@ static const char *get_trigger_role(struct userdata *u, pa_object *stream, struc return NULL; } -static const char *find_trigger_stream(struct userdata *u, pa_object *device, pa_object *ignore_stream, struct group *g) { +static const char *find_trigger_stream(struct userdata *u, pa_object *current_stream, pa_object *device, pa_object *ignore_stream, struct group *g) { pa_object *j; uint32_t idx; const char *trigger_role; @@ -108,6 +108,23 @@ static const char *find_trigger_stream(struct userdata *u, pa_object *device, pa pa_assert(u); pa_object_assert_ref(device); + /* If the current stream is a trigger stream, return the role of this stream, otherwise + * return the role of the first trigger stream that is found on the device. */ + + trigger_role = get_trigger_role(u, current_stream, g); + if (GET_DEVICE_FROM_STREAM(current_stream) == device && current_stream != ignore_stream && trigger_role) { + + if (pa_sink_isinstance(device)) { + if (!PA_SINK_INPUT(current_stream)->muted && + PA_SINK_INPUT(current_stream)->state != PA_SINK_INPUT_CORKED) + return trigger_role; + } else { + if (!PA_SOURCE_OUTPUT(current_stream)->muted && + PA_SOURCE_OUTPUT(current_stream)->state != PA_SOURCE_OUTPUT_CORKED) + return trigger_role; + } + } + PA_IDXSET_FOREACH(j, pa_sink_isinstance(device) ? PA_SINK(device)->inputs : PA_SOURCE(device)->outputs, idx) { if (j == ignore_stream) continue; @@ -129,7 +146,7 @@ static const char *find_trigger_stream(struct userdata *u, pa_object *device, pa return NULL; } -static const char *find_global_trigger_stream(struct userdata *u, pa_object *ignore_stream, struct group *g) { +static const char *find_global_trigger_stream(struct userdata *u, pa_object *current_stream, pa_object *ignore_stream, struct group *g) { const char *trigger_role = NULL; pa_sink *sink; pa_source *source; @@ -137,16 +154,20 @@ static const char *find_global_trigger_stream(struct userdata *u, pa_object *ign pa_assert(u); + /* Check device of current stream first in case the current stream is a trigger stream. */ + if ((trigger_role = find_trigger_stream(u, current_stream, GET_DEVICE_FROM_STREAM(current_stream), ignore_stream, g))) + return trigger_role; + /* Find any trigger role among the sink-inputs and source-outputs. */ PA_IDXSET_FOREACH(sink, u->core->sinks, idx) - if ((trigger_role = find_trigger_stream(u, PA_OBJECT(sink), ignore_stream, g))) + if ((trigger_role = find_trigger_stream(u, current_stream, PA_OBJECT(sink), ignore_stream, g))) break; if (!u->source_trigger || trigger_role) return trigger_role; PA_IDXSET_FOREACH(source, u->core->sources, idx) - if ((trigger_role = find_trigger_stream(u, PA_OBJECT(source), ignore_stream, g))) + if ((trigger_role = find_trigger_stream(u, current_stream, PA_OBJECT(source), ignore_stream, g))) break; return trigger_role; @@ -204,7 +225,7 @@ static inline void apply_interaction_to_sink(struct userdata *u, pa_sink *s, con role = "no_role"; PA_IDXSET_FOREACH(interaction_role, g->interaction_roles, role_idx) { - if ((trigger = pa_streq(role, interaction_role))) + if ((trigger = (pa_streq(interaction_role, role) && (!get_trigger_role(u, PA_OBJECT(j), g) || !pa_safe_streq(new_trigger, role))))) break; if ((trigger = (pa_streq(interaction_role, "any_role") && !get_trigger_role(u, PA_OBJECT(j), g)))) break; @@ -289,10 +310,10 @@ static pa_hook_result_t process(struct userdata *u, pa_object *stream, bool crea for (j = 0; j < u->n_groups; j++) { if (u->global) { - trigger_role = find_global_trigger_stream(u, create ? NULL : stream, u->groups[j]); + trigger_role = find_global_trigger_stream(u, stream, create ? NULL : stream, u->groups[j]); apply_interaction_global(u, trigger_role, create ? NULL : (pa_sink_input_isinstance(stream) ? PA_SINK_INPUT(stream) : NULL), new_stream, u->groups[j]); } else { - trigger_role = find_trigger_stream(u, GET_DEVICE_FROM_STREAM(stream), create ? NULL : stream, u->groups[j]); + trigger_role = find_trigger_stream(u, stream, GET_DEVICE_FROM_STREAM(stream), create ? NULL : stream, u->groups[j]); if (pa_sink_input_isinstance(stream)) apply_interaction_to_sink(u, PA_SINK_INPUT(stream)->sink, trigger_role, create ? NULL : PA_SINK_INPUT(stream), new_stream, u->groups[j]); } From f8b90105824ac66a30e56efb32a44dc896f2b2c5 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Mon, 2 Jan 2023 21:05:15 +1100 Subject: [PATCH 090/260] rtp-send: Use getaddrinfo to improve support for ipv6. inet_pton isn't guarantee to support IPV6 address when a scope has been specified. Using getaddrinfo instead, we can safely pass through INET6+scope and have it translated to a usable address. Part-of: --- src/modules/rtp/module-rtp-send.c | 42 +++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c index fd5b63abe..e917105c7 100644 --- a/src/modules/rtp/module-rtp-send.c +++ b/src/modules/rtp/module-rtp-send.c @@ -26,6 +26,9 @@ #include #include #include +#ifdef HAVE_NETDB_H +#include +#endif #include #include @@ -338,6 +341,44 @@ int pa__init(pa_module*m) { if (dst_addr == NULL) dst_addr = pa_modargs_get_value(ma, "destination_ip", DEFAULT_DESTINATION_IP); +#if defined(HAVE_GETADDRINFO) + { + struct addrinfo *dst_addrinfo = NULL; + struct addrinfo hints; + + pa_zero(hints); + + hints.ai_flags = AI_NUMERICHOST; + if (getaddrinfo(dst_addr, NULL, &hints, &dst_addrinfo) != 0) { + pa_log("Invalid destination '%s'", dst_addr); + goto fail; + } + + af = dst_addrinfo->ai_family; + if (af == AF_INET) { + memcpy(&dst_sa4, dst_addrinfo->ai_addr, dst_addrinfo->ai_addrlen); + dst_sa4.sin_port = htons((uint16_t) port); + dst_sap_sa4 = dst_sa4; + dst_sap_sa4.sin_port = htons(SAP_PORT); + } +#ifdef HAVE_IPV6 + else if (af == AF_INET6) { + memcpy(&dst_sa6, dst_addrinfo->ai_addr, dst_addrinfo->ai_addrlen); + dst_sa6.sin6_port = htons((uint16_t) port); + dst_sap_sa6 = dst_sa6; + dst_sap_sa6.sin6_port = htons(SAP_PORT); + } +#endif + else + { + freeaddrinfo(dst_addrinfo); + pa_log("Invalid destination '%s'", dst_addr); + goto fail; + } + + freeaddrinfo(dst_addrinfo); + } +#else if (inet_pton(AF_INET, dst_addr, &dst_sa4.sin_addr) > 0) { dst_sa4.sin_family = af = AF_INET; dst_sa4.sin_port = htons((uint16_t) port); @@ -357,6 +398,7 @@ int pa__init(pa_module*m) { pa_log("Invalid destination '%s'", dst_addr); goto fail; } +#endif /* HAVE_GETADDRINFO */ if ((fd = pa_socket_cloexec(af, SOCK_DGRAM, 0)) < 0) { pa_log("socket() failed: %s", pa_cstrerror(errno)); From 8152f39603d1c1235c1944c75220ae6d3fef3493 Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Mon, 23 Jan 2023 08:55:04 +0300 Subject: [PATCH 091/260] alsa-util: Dump probed rates Part-of: --- src/modules/alsa/alsa-util.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c index 9d464a8ac..9f35cb20f 100644 --- a/src/modules/alsa/alsa-util.c +++ b/src/modules/alsa/alsa-util.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "alsa-util.h" #include "alsa-mixer.h" @@ -1406,6 +1407,23 @@ char *pa_alsa_get_reserve_name(const char *device) { return pa_sprintf_malloc("Audio%i", i); } +static void dump_supported_rates(unsigned int* values) +{ + pa_strbuf *buf; + char *str; + int i; + + buf = pa_strbuf_new(); + + for (i = 0; values[i]; i++) { + pa_strbuf_printf(buf, " %u", values[i]); + } + + str = pa_strbuf_to_string_free(buf); + pa_log_debug("Supported rates:%s", str); + pa_xfree(str); +} + unsigned int *pa_alsa_get_supported_rates(snd_pcm_t *pcm, unsigned int fallback_rate) { static unsigned int all_rates[] = { 8000, 11025, 12000, 16000, 22050, 24000, @@ -1454,6 +1472,7 @@ unsigned int *pa_alsa_get_supported_rates(snd_pcm_t *pcm, unsigned int fallback_ rates[1] = 0; } + dump_supported_rates(rates); return rates; } From 86c5fbab5778685e19b5a4a9b8eb04ca90dff780 Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Sun, 5 Feb 2023 19:49:10 +0300 Subject: [PATCH 092/260] alsa-util: Add more standard sample rates. Part-of: --- src/modules/alsa/alsa-util.c | 3 ++- src/pulse/sample.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c index 9f35cb20f..fd30f18bd 100644 --- a/src/modules/alsa/alsa-util.c +++ b/src/modules/alsa/alsa-util.c @@ -1430,7 +1430,8 @@ unsigned int *pa_alsa_get_supported_rates(snd_pcm_t *pcm, unsigned int fallback_ 32000, 44100, 48000, 64000, 88200, 96000, 128000, 176400, 192000, - 384000 }; + 352800, 384000, + 705600, 768000 }; bool supported[PA_ELEMENTSOF(all_rates)] = { false, }; snd_pcm_hw_params_t *hwparams; unsigned int i, j, n, *rates = NULL; diff --git a/src/pulse/sample.h b/src/pulse/sample.h index 35346a865..65c0c5d6b 100644 --- a/src/pulse/sample.h +++ b/src/pulse/sample.h @@ -128,7 +128,7 @@ PA_C_DECL_BEGIN #define PA_CHANNELS_MAX 32U /** Maximum allowed sample rate */ -#define PA_RATE_MAX (48000U*8U) +#define PA_RATE_MAX (48000U*16U) /** Sample format */ typedef enum pa_sample_format { From 3e5db72ab759a33063e5af26f4b48ec3be1baed5 Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Mon, 6 Feb 2023 09:38:45 +0300 Subject: [PATCH 093/260] bluetooth: Amend writeout to send more initial frames When bluetooth transport has both both sink and source, pulseaudio would synchronize writing out frames with reading frames from peer to make fair schedule of reads and writes. Pulseaudio allows two blocks of data to be sent to peer before synchronizing writes with reads just in case that peer implements similar write schedule. It could happen that first blocks are still missed by peer, which would cause pulseaudio writes to stall waiting for first frames from peer. Fix this by allowing more data frames out until data from peer is actually received. Closes: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/issues/1424 Part-of: --- src/modules/bluetooth/module-bluez5-device.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c index ab1bc098e..dc6809ce5 100644 --- a/src/modules/bluetooth/module-bluez5-device.c +++ b/src/modules/bluetooth/module-bluez5-device.c @@ -1549,8 +1549,8 @@ static void thread_func(void *userdata) { writable = true; /* If we have a source, we let the source determine the timing - * for the sink */ - if (have_source) { + * for the sink unless peer has not sent any data yet */ + if (have_source && u->read_index > 0) { /* If the stream is writable, send some data if necessary */ if (writable) { @@ -1663,6 +1663,12 @@ static void thread_func(void *userdata) { goto fail; if (result) { + if (have_source && u->read_index <= 0) { + /* We have a source but peer has not sent any data yet, log this */ + if (pa_log_ratelimit(PA_LOG_DEBUG)) + pa_log_debug("Still no data received from source, sent one more block to sink"); + } + writable = false; have_written = true; } From 6ae3961001fec306bf8ca8f6eac0aceb27946fbb Mon Sep 17 00:00:00 2001 From: Georg Chini Date: Mon, 30 Jan 2023 09:37:35 +0100 Subject: [PATCH 094/260] tunnel-sink-new: Fix hang when used in combination with module-combine-sink When tunnel-sink-new was used in combination with module-combine-sink, PA would hang because the main thread was blocked waiting for the execution of the latency snapshot message. The message would never be processed because the rtpoll associated with the control_inq of module-combine-sink was never run. This patch fixes the problem by running the rtpoll in the thread function to process incoming messages. Though there are no users of the rtpoll for module-tunnel-source-new, the same change is applied there. Part-of: --- src/modules/module-tunnel-sink-new.c | 21 +++++++++++++-------- src/modules/module-tunnel-source-new.c | 15 +++++++++++---- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/modules/module-tunnel-sink-new.c b/src/modules/module-tunnel-sink-new.c index 3cea25a90..0b91ce266 100644 --- a/src/modules/module-tunnel-sink-new.c +++ b/src/modules/module-tunnel-sink-new.c @@ -253,9 +253,14 @@ static void thread_func(void *userdata) { pa_log_error("Could not write data into the stream ... ret = %i", ret); u->thread_mainloop_api->quit(u->thread_mainloop_api, TUNNEL_THREAD_FAILED_MAINLOOP); } - } } + + /* Run the rtpoll to process messages that other modules (module-combine-sink, + * module-loopback and module-rtp-recv) may have placed in the queue. */ + pa_rtpoll_set_timer_relative(u->rtpoll, 0); + if (pa_rtpoll_run(u->rtpoll) < 0) + goto fail; } fail: /* send a message to the ctl thread to ask it to either terminate us, or @@ -696,13 +701,13 @@ static int do_init(pa_module *m) { u->msg = pa_msgobject_new(tunnel_msg); u->msg->parent.process_msg = tunnel_process_msg; - /* The rtpoll created here is never run. It is only necessary to avoid crashes - * when module-tunnel-sink-new is used together with module-loopback or - * module-combine-sink. Both modules base their asyncmsq on the rtpoll provided - * by the sink. module-loopback and combine-sink only work because they call - * pa_asyncmsq_process_one() themselves. module_rtp_recv also uses the rtpoll, - * but never calls pa_asyncmsq_process_one(), so it will not work in combination - * with module-tunnel-sink-new. */ + /* The rtpoll created here is only run for the sake of module-combine-sink. It must + * exist to avoid crashes when module-tunnel-sink-new is used together with + * module-loopback or module-combine-sink. Both modules base their asyncmsgq on the + * rtpoll provided by the sink. module-loopback and combine-sink only work because + * they call pa_asyncmsq_process_one() themselves. module-combine-sink does this + * however only for the audio_inq, so without running the rtpoll, messages placed + * in control_inq would never be executed. */ u->rtpoll = pa_rtpoll_new(); default_sink_name = pa_sprintf_malloc("tunnel-sink-new.%s", remote_server); diff --git a/src/modules/module-tunnel-source-new.c b/src/modules/module-tunnel-source-new.c index b96137a24..d75fe9e6b 100644 --- a/src/modules/module-tunnel-source-new.c +++ b/src/modules/module-tunnel-source-new.c @@ -270,6 +270,11 @@ static void thread_func(void *userdata) { if (u->new_data) read_new_samples(u); + + /* Run the rtpoll to process messages that other modules may have placed in the queue. */ + pa_rtpoll_set_timer_relative(u->rtpoll, 0); + if (pa_rtpoll_run(u->rtpoll) < 0) + goto fail; } fail: /* send a message to the ctl thread to ask it to either terminate us, or @@ -668,10 +673,12 @@ static int do_init(pa_module *m) { u->msg = pa_msgobject_new(tunnel_msg); u->msg->parent.process_msg = tunnel_process_msg; - /* The rtpoll created here is never run. It is only necessary to avoid crashes - * when module-tunnel-source-new is used together with module-loopback. - * module-loopback bases the asyncmsq on the rtpoll provided by the source and - * only works because it calls pa_asyncmsq_process_one(). */ + /* The rtpoll created here must curently only exist to avoid crashes when + * the module is used together with module-loopback. Because module-loopback + * runs pa_asyncmsgq_process_one() from the pop callback, the rtpoll need not + * be run. We will do so anyway for potential modules similar to + * module-combine-sink that use the rtpoll of the underlying source for + * message exchange. */ u->rtpoll = pa_rtpoll_new(); default_source_name = pa_sprintf_malloc("tunnel-source-new.%s", remote_server); From 1cfa7378236b3cf9daf3be09d3227b92df69cc53 Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Wed, 8 Feb 2023 03:24:59 +0300 Subject: [PATCH 095/260] resampler: Fix oversized memblock pushed from resampler The assumption that the format enum is ordered by size is not valid for quite some time, since 24bit formats were appended to format enum later than 32bit formats. This causes resampler to produce properly aligned memblock of size larger than maximum mempool block size if input format is 24bit and output format is 32bit. Oversized block is getting split by `pa_pstream_send_memblock()` into parts of size not exceeding maximum mempool block size. This usually works well but for 32ch 32bit 48000Hz stream the frame alignment is 128 bytes and maximum mempool block size value is multiple of 64 but not 128 bytes, therefore resulting parts are misaligned. On receiving side this causes extra allocation of 128 byte chunk while `mcalign` helper reassembles properly aligned frame out of second block of misaligned size. While first and second properly aligned frames are retrieved successfully from `mcalign` helper, third retrieved frame would end up with properly aligned size but misaligned memblock index (in this example, that would be 64 bytes.) Attempt to push a chunk with misaligned memblock index causes assertion failure Assertion 'uchunk->index % bq->base == 0' failed at memblockq.c:289, function pa_memblockq_push(). Aborting. Fix oversized block issue by checking proper size of format instead of enum value. Fixes: a67c21f09 ("merge 'lennart' branch back into trunk.") Part-of: --- src/pulsecore/resampler.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c index b035f67ed..ba18c92c4 100644 --- a/src/pulsecore/resampler.c +++ b/src/pulsecore/resampler.c @@ -613,9 +613,13 @@ size_t pa_resampler_max_block_size(pa_resampler *r) { * conversion */ max_ss.channels = (uint8_t) (PA_MAX(r->i_ss.channels, r->o_ss.channels)); - /* We silently assume that the format enum is ordered by size */ - max_ss.format = PA_MAX(r->i_ss.format, r->o_ss.format); - max_ss.format = PA_MAX(max_ss.format, r->work_format); + max_ss.format = r->i_ss.format; + + if (pa_sample_size_of_format(max_ss.format) < pa_sample_size_of_format(r->o_ss.format)) + max_ss.format = r->o_ss.format; + + if (pa_sample_size_of_format(max_ss.format) < pa_sample_size_of_format(r->work_format)) + max_ss.format = r->work_format; max_ss.rate = PA_MAX(r->i_ss.rate, r->o_ss.rate); From f44cb36374a6b72e33b03b555771137042aaf6b2 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Wed, 25 Jan 2023 17:04:51 +1100 Subject: [PATCH 096/260] rtp-send: Use getaddrinfo to improve support for ipv6 on source address Part-of: --- src/modules/rtp/module-rtp-send.c | 37 +++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c index e917105c7..ce05360d5 100644 --- a/src/modules/rtp/module-rtp-send.c +++ b/src/modules/rtp/module-rtp-send.c @@ -319,6 +319,42 @@ int pa__init(pa_module*m) { src_addr = pa_modargs_get_value(ma, "source_ip", DEFAULT_SOURCE_IP); +#if defined(HAVE_GETADDRINFO) + { + struct addrinfo *src_addrinfo = NULL; + struct addrinfo hints; + + pa_zero(hints); + + hints.ai_flags = AI_NUMERICHOST; + if (getaddrinfo(src_addr, NULL, &hints, &src_addrinfo) != 0) { + pa_log("Invalid source '%s'", src_addr); + goto fail; + } + + af = src_addrinfo->ai_family; + if (af == AF_INET) { + memcpy(&src_sa4, src_addrinfo->ai_addr, src_addrinfo->ai_addrlen); + src_sa4.sin_port = htons(0); + src_sap_sa4 = src_sa4; + } +#ifdef HAVE_IPV6 + else if (af == AF_INET6) { + memcpy(&src_sa6, src_addrinfo->ai_addr, src_addrinfo->ai_addrlen); + src_sa6.sin6_port = htons(0); + src_sap_sa6 = src_sa6; + } +#endif + else + { + freeaddrinfo(src_addrinfo); + pa_log("Invalid source '%s'", src_addr); + goto fail; + } + + freeaddrinfo(src_addrinfo); + } +#else if (inet_pton(AF_INET, src_addr, &src_sa4.sin_addr) > 0) { src_sa4.sin_family = af = AF_INET; src_sa4.sin_port = htons(0); @@ -336,6 +372,7 @@ int pa__init(pa_module*m) { pa_log("Invalid source address '%s'", src_addr); goto fail; } +#endif /* HAVE_GETADDRINFO */ dst_addr = pa_modargs_get_value(ma, "destination", NULL); if (dst_addr == NULL) From 5cefef591ef6c0fd1c514202b0fcfbe466cab873 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Thu, 26 Jan 2023 08:37:20 +1100 Subject: [PATCH 097/260] rtp-recv: Use getaddrinfo to improve support for ipv6. Part-of: --- src/modules/rtp/module-rtp-recv.c | 38 +++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c index a67a993d1..9babf00cb 100644 --- a/src/modules/rtp/module-rtp-recv.c +++ b/src/modules/rtp/module-rtp-recv.c @@ -29,6 +29,9 @@ #include #include #include +#ifdef HAVE_NETDB_H +#include +#endif #include #include @@ -677,9 +680,13 @@ static void check_death_event_cb(pa_mainloop_api *m, pa_time_event *t, const str int pa__init(pa_module*m) { struct userdata *u; pa_modargs *ma = NULL; +#if defined(HAVE_GETADDRINFO) + struct addrinfo *sap_addrinfo = NULL; +#else struct sockaddr_in sa4; #ifdef HAVE_IPV6 struct sockaddr_in6 sa6; +#endif #endif struct sockaddr *sa; socklen_t salen; @@ -696,6 +703,27 @@ int pa__init(pa_module*m) { sap_address = pa_modargs_get_value(ma, "sap_address", DEFAULT_SAP_ADDRESS); +#if defined(HAVE_GETADDRINFO) + { + struct addrinfo hints; + char *service; + + pa_zero(hints); + + service = pa_sprintf_malloc("%d", htons(SAP_PORT)); + + hints.ai_flags = AI_NUMERICHOST; + if (getaddrinfo(sap_address, service, &hints, &sap_addrinfo) != 0) { + pa_xfree(service); + pa_log("Invalid SAP address '%s'", sap_address); + goto fail; + } + pa_xfree(service); + + sa = sap_addrinfo->ai_addr; + salen = sap_addrinfo->ai_addrlen; + } +#else if (inet_pton(AF_INET, sap_address, &sa4.sin_addr) > 0) { sa4.sin_family = AF_INET; sa4.sin_port = htons(SAP_PORT); @@ -712,6 +740,7 @@ int pa__init(pa_module*m) { pa_log("Invalid SAP address '%s'", sap_address); goto fail; } +#endif latency_msec = DEFAULT_LATENCY_MSEC; if (pa_modargs_get_value_u32(ma, "latency_msec", &latency_msec) < 0 || latency_msec < 1 || latency_msec > 300000) { @@ -739,9 +768,18 @@ int pa__init(pa_module*m) { pa_modargs_free(ma); +#if defined(HAVE_GETADDRINFO) + freeaddrinfo(sap_addrinfo); +#endif + return 0; fail: +#if defined(HAVE_GETADDRINFO) + if (sap_addrinfo) + freeaddrinfo(sap_addrinfo); +#endif + if (ma) pa_modargs_free(ma); From 5830e03036f51fc06687e61be000708b464a094e Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Thu, 9 Feb 2023 23:15:55 +0300 Subject: [PATCH 098/260] bluetooth: Do not attempt decoding too short faststream packet data Looks like sbc_decode() would seldom access more than specified input length bytes from input buffer if input length is less than expected frame size. Fix potential access past allocated memory by checking if input contains complete frame before calling sbc_decode() Part-of: --- src/modules/bluetooth/a2dp-codec-sbc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/modules/bluetooth/a2dp-codec-sbc.c b/src/modules/bluetooth/a2dp-codec-sbc.c index 5476697f8..1306c79f2 100644 --- a/src/modules/bluetooth/a2dp-codec-sbc.c +++ b/src/modules/bluetooth/a2dp-codec-sbc.c @@ -1331,6 +1331,11 @@ static size_t decode_buffer_faststream(void *codec_info, const uint8_t *input_bu continue; } + if (to_decode < sbc_info->frame_length) { + pa_log_debug("FastStream SBC input %lu is too short (expected frame length %lu)", to_decode, sbc_info->frame_length); + break; + } + decoded = sbc_decode(&sbc_info->sbc, p, to_decode, decode_buffer, sizeof(decode_buffer), From 300db779224625144d6279d230c2daa857c967d8 Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Thu, 9 Feb 2023 13:28:29 +0300 Subject: [PATCH 099/260] pstream: Pass frame size to keep split memblock parts aligned `pa_pstream_send_memblock()` would split incoming memblock into parts not exceeding maximum pool block size. To make sure split parts of memblock are still frame-aligned add new `align` arg to `pa_pstream_send_memblock`, find out required alignment from stream sample format and pass it there. Bump default alignment to 256 which is good up to 32bit 64ch frames. Part-of: --- src/modules/module-tunnel.c | 2 +- src/pulse/stream.c | 4 ++-- src/pulsecore/protocol-native.c | 4 ++-- src/pulsecore/pstream.c | 11 ++++++++++- src/pulsecore/pstream.h | 2 +- 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/modules/module-tunnel.c b/src/modules/module-tunnel.c index 61f427bd3..ab094ba4e 100644 --- a/src/modules/module-tunnel.c +++ b/src/modules/module-tunnel.c @@ -676,7 +676,7 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse * IO thread context where the rest of the messages are * dispatched. Yeah, ugly, but I am a lazy bastard. */ - pa_pstream_send_memblock(u->pstream, u->channel, 0, PA_SEEK_RELATIVE, chunk); + pa_pstream_send_memblock(u->pstream, u->channel, 0, PA_SEEK_RELATIVE, chunk, pa_frame_size(&u->sink->sample_spec)); u->receive_counter += chunk->length; diff --git a/src/pulse/stream.c b/src/pulse/stream.c index 0aa627396..3585b27e8 100644 --- a/src/pulse/stream.c +++ b/src/pulse/stream.c @@ -1535,7 +1535,7 @@ int pa_stream_write_ext_free( s->write_memblock = NULL; s->write_data = NULL; - pa_pstream_send_memblock(s->context->pstream, s->channel, offset, seek, &chunk); + pa_pstream_send_memblock(s->context->pstream, s->channel, offset, seek, &chunk, pa_frame_size(&s->sample_spec)); pa_memblock_unref(chunk.memblock); } else { @@ -1569,7 +1569,7 @@ int pa_stream_write_ext_free( pa_memblock_release(chunk.memblock); } - pa_pstream_send_memblock(s->context->pstream, s->channel, t_offset, t_seek, &chunk); + pa_pstream_send_memblock(s->context->pstream, s->channel, t_offset, t_seek, &chunk, pa_frame_size(&s->sample_spec)); t_offset = 0; t_seek = PA_SEEK_RELATIVE; diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 672182fbc..1342dee10 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -1260,7 +1260,7 @@ static void native_connection_send_memblock(pa_native_connection *c) { if (schunk.length > r->buffer_attr.fragsize) schunk.length = r->buffer_attr.fragsize; - pa_pstream_send_memblock(c->pstream, r->index, 0, PA_SEEK_RELATIVE, &schunk); + pa_pstream_send_memblock(c->pstream, r->index, 0, PA_SEEK_RELATIVE, &schunk, pa_memblockq_get_base(r->memblockq)); pa_memblockq_drop(r->memblockq, schunk.length); pa_memblock_unref(schunk.memblock); @@ -2535,7 +2535,7 @@ static void setup_srbchannel(pa_native_connection *c, pa_mem_type_t shm_type) { mc.memblock = srbt.memblock; mc.index = 0; mc.length = pa_memblock_get_length(srbt.memblock); - pa_pstream_send_memblock(c->pstream, 0, 0, 0, &mc); + pa_pstream_send_memblock(c->pstream, 0, 0, 0, &mc, 0); c->srbpending = srb; return; diff --git a/src/pulsecore/pstream.c b/src/pulsecore/pstream.c index 7147b776a..ff62f464b 100644 --- a/src/pulsecore/pstream.c +++ b/src/pulsecore/pstream.c @@ -82,6 +82,10 @@ typedef uint32_t pa_pstream_descriptor[PA_PSTREAM_DESCRIPTOR_MAX]; */ #define FRAME_SIZE_MAX_ALLOW (1024*1024*16) +/* Default memblock alignment used with pa_pstream_send_memblock() + */ +#define DEFAULT_PSTREAM_MEMBLOCK_ALIGN (256) + PA_STATIC_FLIST_DECLARE(items, 0, pa_xfree); struct item_info { @@ -475,7 +479,7 @@ void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, pa_cmsg_ancil_data p->mainloop->defer_enable(p->defer_event, 1); } -void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa_seek_mode_t seek_mode, const pa_memchunk *chunk) { +void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa_seek_mode_t seek_mode, const pa_memchunk *chunk, size_t align) { size_t length, idx; size_t bsm; @@ -492,6 +496,11 @@ void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa bsm = pa_mempool_block_size_max(p->mempool); + if (align == 0) + align = DEFAULT_PSTREAM_MEMBLOCK_ALIGN; + + bsm = (bsm / align) * align; + while (length > 0) { struct item_info *i; size_t n; diff --git a/src/pulsecore/pstream.h b/src/pulsecore/pstream.h index 2bff270ad..88bdca4cc 100644 --- a/src/pulsecore/pstream.h +++ b/src/pulsecore/pstream.h @@ -51,7 +51,7 @@ void pa_pstream_unlink(pa_pstream *p); int pa_pstream_attach_memfd_shmid(pa_pstream *p, unsigned shm_id, int memfd_fd); void pa_pstream_send_packet(pa_pstream*p, pa_packet *packet, pa_cmsg_ancil_data *ancil_data); -void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk); +void pa_pstream_send_memblock(pa_pstream*p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, size_t align); void pa_pstream_send_release(pa_pstream *p, uint32_t block_id); void pa_pstream_send_revoke(pa_pstream *p, uint32_t block_id); From 9e85059c64e27e75678cac35c14965e98c1d83dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ataberk=20=C3=96zen?= Date: Sun, 20 Nov 2022 15:52:47 +0300 Subject: [PATCH 100/260] alsa-profiles: import Asus Xonar SE profile from pipewire Part-of: --- src/modules/alsa/90-pulseaudio.rules | 3 + .../mixer/profile-sets/asus-xonar-se.conf | 93 +++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 src/modules/alsa/mixer/profile-sets/asus-xonar-se.conf diff --git a/src/modules/alsa/90-pulseaudio.rules b/src/modules/alsa/90-pulseaudio.rules index d26843169..cce25b251 100644 --- a/src/modules/alsa/90-pulseaudio.rules +++ b/src/modules/alsa/90-pulseaudio.rules @@ -175,6 +175,9 @@ ATTRS{idVendor}=="1395", ATTRS{idProduct}=="0300", ENV{PULSE_PROFILE_SET}="usb-g # Sennheiser GSP 670 USB headset ATTRS{idVendor}=="1395", ATTRS{idProduct}=="008a", ENV{PULSE_PROFILE_SET}="usb-gaming-headset.conf" +# Asus Xonar SE +ATTRS{idVendor}=="0b05", ATTRS{idProduct}=="189d", ENV{PULSE_PROFILE_SET}="asus-xonar-se.conf" + GOTO="pulseaudio_end" LABEL="pulseaudio_check_pci" diff --git a/src/modules/alsa/mixer/profile-sets/asus-xonar-se.conf b/src/modules/alsa/mixer/profile-sets/asus-xonar-se.conf new file mode 100644 index 000000000..3e42ea311 --- /dev/null +++ b/src/modules/alsa/mixer/profile-sets/asus-xonar-se.conf @@ -0,0 +1,93 @@ +# This file is part of PulseAudio. +# +# PulseAudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2.1 of the +# License, or (at your option) any later version. +# +# PulseAudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with PulseAudio; if not, see . + +; ASUS Xonar SE card. +; This card has two devices for each rear and front panel jacks. +; +; See default.conf for an explanation on the directives used here. + +[General] +auto-profiles = yes + +[Mapping analog-stereo-front] +description = Analog Stereo Front +device-strings = hw:%f,1 +channel-map = left,right +paths-output = analog-output analog-output-headphones +paths-input = analog-input-mic analog-input-headphone-mic analog-input-headset-mic +priority = 15 + +[Mapping analog-stereo-rear] +description = Analog Stereo Rear +device-strings = hw:%f,0 +channel-map = left,right +paths-output = analog-output analog-output-speaker +paths-input = analog-input analog-input-mic analog-input-linein +priority = 14 + +[Mapping analog-surround-21] +device-strings = surround21:%f +channel-map = front-left,front-right,lfe +paths-output = analog-output-speaker +priority = 13 +direction = output + +[Mapping analog-surround-40] +device-strings = surround40:%f +channel-map = front-left,front-right,rear-left,rear-right +paths-output = analog-output-speaker +priority = 12 +direction = output + +[Mapping analog-surround-41] +device-strings = surround41:%f +channel-map = front-left,front-right,rear-left,rear-right,lfe +paths-output = analog-output-speaker +priority = 13 +direction = output + +[Mapping analog-surround-50] +device-strings = surround50:%f +channel-map = front-left,front-right,rear-left,rear-right,front-center +paths-output = analog-output-speaker +priority = 12 +direction = output + +[Mapping analog-surround-51] +device-strings = surround51:%f +channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe +paths-output = analog-output-speaker +priority = 13 +direction = output + +[Mapping iec958-stereo] +device-strings = iec958:%f +channel-map = left,right +paths-output = iec958-stereo-output +priority = 5 + +[Mapping iec958-ac3-surround-40] +device-strings = a52:%f +channel-map = front-left,front-right,rear-left,rear-right +paths-output = iec958-stereo-output +priority = 2 +direction = output + +[Mapping iec958-ac3-surround-51] +device-strings = a52:%f +channel-map = front-left,front-right,rear-left,rear-right,front-center,lfe +paths-output = iec958-stereo-output +priority = 3 +direction = output From b8e2198d34da2e085b469d7e3a472cbdaec9e5b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ataberk=20=C3=96zen?= Date: Mon, 20 Feb 2023 18:37:36 +0300 Subject: [PATCH 101/260] alsa-profiles: rename mappings for Xonar SE Remove descriptions as well. Part-of: --- src/modules/alsa/mixer/profile-sets/asus-xonar-se.conf | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/modules/alsa/mixer/profile-sets/asus-xonar-se.conf b/src/modules/alsa/mixer/profile-sets/asus-xonar-se.conf index 3e42ea311..2bb00a4b2 100644 --- a/src/modules/alsa/mixer/profile-sets/asus-xonar-se.conf +++ b/src/modules/alsa/mixer/profile-sets/asus-xonar-se.conf @@ -21,16 +21,14 @@ [General] auto-profiles = yes -[Mapping analog-stereo-front] -description = Analog Stereo Front +[Mapping analog-stereo-headset] device-strings = hw:%f,1 channel-map = left,right paths-output = analog-output analog-output-headphones paths-input = analog-input-mic analog-input-headphone-mic analog-input-headset-mic priority = 15 -[Mapping analog-stereo-rear] -description = Analog Stereo Rear +[Mapping analog-stereo] device-strings = hw:%f,0 channel-map = left,right paths-output = analog-output analog-output-speaker From aed52c507f345d0b5c4cd2b1d2c58dae2d904b53 Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Wed, 22 Feb 2023 01:19:24 +0300 Subject: [PATCH 102/260] alsa-util: Perform format and rate detection before setting HW params Perform detection of supported sample format and rates just after device is opened, before `snd_pcm_hw_params()` is called for the first time. This fixes a problem where device restricts available sample rates after HW params are set preventing sample rate detection (seen with UAC2 devices and kernel 6.1.9) Bug: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/issues/1414 Bug: https://github.com/alsa-project/alsa-lib/issues/119 Part-of: --- src/modules/alsa/alsa-mixer.c | 2 +- src/modules/alsa/alsa-sink.c | 14 +++++++++----- src/modules/alsa/alsa-source.c | 8 +++----- src/modules/alsa/alsa-ucm.c | 2 +- src/modules/alsa/alsa-util.c | 24 ++++++++++++++++++++++++ src/modules/alsa/alsa-util.h | 8 ++++++++ 6 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c index 49c39687c..c272e392b 100644 --- a/src/modules/alsa/alsa-mixer.c +++ b/src/modules/alsa/alsa-mixer.c @@ -5074,7 +5074,7 @@ static snd_pcm_t* mapping_open_pcm(pa_alsa_mapping *m, handle = pa_alsa_open_by_template( m->device_strings, dev_id, NULL, &try_ss, &try_map, mode, &try_period_size, - &try_buffer_size, 0, NULL, NULL, exact_channels); + &try_buffer_size, 0, NULL, NULL, NULL, NULL, exact_channels); if (handle && !exact_channels && m->channel_map.channels != try_map.channels) { char buf[PA_CHANNEL_MAP_SNPRINT_MAX]; pa_log_debug("Channel map for mapping '%s' permanently changed to '%s'", m->name, diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c index b249df680..ca22f195f 100644 --- a/src/modules/alsa/alsa-sink.c +++ b/src/modules/alsa/alsa-sink.c @@ -2527,7 +2527,9 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca &ss, &map, SND_PCM_STREAM_PLAYBACK, &period_frames, &buffer_frames, tsched_frames, - &b, &d, mapping))) + &b, &d, + &u->supported_formats, &u->supported_rates, + mapping))) goto fail; } else if ((dev_id = pa_modargs_get_value(ma, "device_id", NULL))) { @@ -2541,7 +2543,9 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca &ss, &map, SND_PCM_STREAM_PLAYBACK, &period_frames, &buffer_frames, tsched_frames, - &b, &d, profile_set, &mapping))) + &b, &d, + &u->supported_formats, &u->supported_rates, + profile_set, &mapping))) goto fail; } else { @@ -2552,7 +2556,9 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca &ss, &map, SND_PCM_STREAM_PLAYBACK, &period_frames, &buffer_frames, tsched_frames, - &b, &d, false))) + &b, &d, + &u->supported_formats, &u->supported_rates, + false))) goto fail; } @@ -2598,13 +2604,11 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca u->verified_sample_spec = ss; - u->supported_formats = pa_alsa_get_supported_formats(u->pcm_handle, ss.format); if (!u->supported_formats) { pa_log_error("Failed to find any supported sample formats."); goto fail; } - u->supported_rates = pa_alsa_get_supported_rates(u->pcm_handle, ss.rate); if (!u->supported_rates) { pa_log_error("Failed to find any supported sample rates."); goto fail; diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c index ef8b12c32..d88c47f1f 100644 --- a/src/modules/alsa/alsa-source.c +++ b/src/modules/alsa/alsa-source.c @@ -2218,7 +2218,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p &ss, &map, SND_PCM_STREAM_CAPTURE, &period_frames, &buffer_frames, tsched_frames, - &b, &d, mapping))) + &b, &d, &u->supported_formats, &u->supported_rates, mapping))) goto fail; } else if ((dev_id = pa_modargs_get_value(ma, "device_id", NULL))) { @@ -2232,7 +2232,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p &ss, &map, SND_PCM_STREAM_CAPTURE, &period_frames, &buffer_frames, tsched_frames, - &b, &d, profile_set, &mapping))) + &b, &d, &u->supported_formats, &u->supported_rates, profile_set, &mapping))) goto fail; } else { @@ -2243,7 +2243,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p &ss, &map, SND_PCM_STREAM_CAPTURE, &period_frames, &buffer_frames, tsched_frames, - &b, &d, false))) + &b, &d, &u->supported_formats, &u->supported_rates, false))) goto fail; } @@ -2279,13 +2279,11 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p u->verified_sample_spec = ss; - u->supported_formats = pa_alsa_get_supported_formats(u->pcm_handle, ss.format); if (!u->supported_formats) { pa_log_error("Failed to find any supported sample formats."); goto fail; } - u->supported_rates = pa_alsa_get_supported_rates(u->pcm_handle, ss.rate); if (!u->supported_rates) { pa_log_error("Failed to find any supported sample rates."); goto fail; diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c index e75756f53..744e7aae1 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -2026,7 +2026,7 @@ static snd_pcm_t* mapping_open_pcm(pa_alsa_ucm_config *ucm, pa_alsa_mapping *m, try_buffer_size = ucm->core->default_n_fragments * try_period_size; pcm = pa_alsa_open_by_device_string(m->device_strings[0], NULL, &try_ss, - &try_map, mode, &try_period_size, &try_buffer_size, 0, NULL, NULL, exact_channels); + &try_map, mode, &try_period_size, &try_buffer_size, 0, NULL, NULL, NULL, NULL, exact_channels); if (pcm) { if (!exact_channels) diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c index fd30f18bd..b631c870c 100644 --- a/src/modules/alsa/alsa-util.c +++ b/src/modules/alsa/alsa-util.c @@ -523,6 +523,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto( snd_pcm_uframes_t tsched_size, bool *use_mmap, bool *use_tsched, + pa_sample_format_t **query_supported_formats, + unsigned int **query_supported_rates, pa_alsa_profile_set *ps, pa_alsa_mapping **mapping) { @@ -561,6 +563,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto( tsched_size, use_mmap, use_tsched, + query_supported_formats, + query_supported_rates, m); if (pcm_handle) { @@ -588,6 +592,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto( tsched_size, use_mmap, use_tsched, + query_supported_formats, + query_supported_rates, m); if (pcm_handle) { @@ -612,6 +618,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto( tsched_size, use_mmap, use_tsched, + query_supported_formats, + query_supported_rates, false); pa_xfree(d); @@ -632,6 +640,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_mapping( snd_pcm_uframes_t tsched_size, bool *use_mmap, bool *use_tsched, + pa_sample_format_t **query_supported_formats, + unsigned int **query_supported_rates, pa_alsa_mapping *m) { snd_pcm_t *pcm_handle; @@ -661,6 +671,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_mapping( tsched_size, use_mmap, use_tsched, + query_supported_formats, + query_supported_rates, pa_channel_map_valid(&m->channel_map) /* Query the channel count if we don't know what we want */); if (!pcm_handle) @@ -684,6 +696,8 @@ snd_pcm_t *pa_alsa_open_by_device_string( snd_pcm_uframes_t tsched_size, bool *use_mmap, bool *use_tsched, + pa_sample_format_t **query_supported_formats, + unsigned int **query_supported_rates, bool require_exact_channel_number) { int err; @@ -711,6 +725,12 @@ snd_pcm_t *pa_alsa_open_by_device_string( pa_log_debug("Managed to open %s", d); + if (query_supported_formats) + *query_supported_formats = pa_alsa_get_supported_formats(pcm_handle, ss->format); + + if (query_supported_rates) + *query_supported_rates = pa_alsa_get_supported_rates(pcm_handle, ss->rate); + if ((err = pa_alsa_set_hw_params( pcm_handle, ss, @@ -784,6 +804,8 @@ snd_pcm_t *pa_alsa_open_by_template( snd_pcm_uframes_t tsched_size, bool *use_mmap, bool *use_tsched, + pa_sample_format_t **query_supported_formats, + unsigned int **query_supported_rates, bool require_exact_channel_number) { snd_pcm_t *pcm_handle; @@ -805,6 +827,8 @@ snd_pcm_t *pa_alsa_open_by_template( tsched_size, use_mmap, use_tsched, + query_supported_formats, + query_supported_rates, require_exact_channel_number); pa_xfree(d); diff --git a/src/modules/alsa/alsa-util.h b/src/modules/alsa/alsa-util.h index 2eed3eac3..c65801104 100644 --- a/src/modules/alsa/alsa-util.h +++ b/src/modules/alsa/alsa-util.h @@ -67,6 +67,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_auto( snd_pcm_uframes_t tsched_size, bool *use_mmap, /* modified at return */ bool *use_tsched, /* modified at return */ + pa_sample_format_t **query_supported_formats, /* modified at return */ + unsigned int **query_supported_rates, /* modified at return */ pa_alsa_profile_set *ps, pa_alsa_mapping **mapping); /* modified at return */ @@ -82,6 +84,8 @@ snd_pcm_t *pa_alsa_open_by_device_id_mapping( snd_pcm_uframes_t tsched_size, bool *use_mmap, /* modified at return */ bool *use_tsched, /* modified at return */ + pa_sample_format_t **query_supported_formats, /* modified at return */ + unsigned int **query_supported_rates, /* modified at return */ pa_alsa_mapping *mapping); /* Opens the explicit ALSA device */ @@ -96,6 +100,8 @@ snd_pcm_t *pa_alsa_open_by_device_string( snd_pcm_uframes_t tsched_size, bool *use_mmap, /* modified at return */ bool *use_tsched, /* modified at return */ + pa_sample_format_t **query_supported_formats, /* modified at return */ + unsigned int **query_supported_rates, /* modified at return */ bool require_exact_channel_number); /* Opens the explicit ALSA device with a fallback list */ @@ -111,6 +117,8 @@ snd_pcm_t *pa_alsa_open_by_template( snd_pcm_uframes_t tsched_size, bool *use_mmap, /* modified at return */ bool *use_tsched, /* modified at return */ + pa_sample_format_t **query_supported_formats, /* modified at return */ + unsigned int **query_supported_rates, /* modified at return */ bool require_exact_channel_number); void pa_alsa_dump(pa_log_level_t level, snd_pcm_t *pcm); From 5ab2b9cb0e32190c3ea12b0f4cb7533d7340bbf1 Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Wed, 22 Feb 2023 01:50:22 +0300 Subject: [PATCH 103/260] alsa-util: Fix pa_alsa_get_supported_formats fallback. Looks like original intention was to scan over sample formats supported by PA, but code does the scan by list of alsa formats. Reverse the map and adjust fallback case which now can use the same map. Part-of: --- src/modules/alsa/alsa-util.c | 62 ++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c index b631c870c..d3c092f52 100644 --- a/src/modules/alsa/alsa-util.c +++ b/src/modules/alsa/alsa-util.c @@ -1502,35 +1502,35 @@ unsigned int *pa_alsa_get_supported_rates(snd_pcm_t *pcm, unsigned int fallback_ } pa_sample_format_t *pa_alsa_get_supported_formats(snd_pcm_t *pcm, pa_sample_format_t fallback_format) { - static const snd_pcm_format_t format_trans_to_pa[] = { - [SND_PCM_FORMAT_U8] = PA_SAMPLE_U8, - [SND_PCM_FORMAT_A_LAW] = PA_SAMPLE_ALAW, - [SND_PCM_FORMAT_MU_LAW] = PA_SAMPLE_ULAW, - [SND_PCM_FORMAT_S16_LE] = PA_SAMPLE_S16LE, - [SND_PCM_FORMAT_S16_BE] = PA_SAMPLE_S16BE, - [SND_PCM_FORMAT_FLOAT_LE] = PA_SAMPLE_FLOAT32LE, - [SND_PCM_FORMAT_FLOAT_BE] = PA_SAMPLE_FLOAT32BE, - [SND_PCM_FORMAT_S32_LE] = PA_SAMPLE_S32LE, - [SND_PCM_FORMAT_S32_BE] = PA_SAMPLE_S32BE, - [SND_PCM_FORMAT_S24_3LE] = PA_SAMPLE_S24LE, - [SND_PCM_FORMAT_S24_3BE] = PA_SAMPLE_S24BE, - [SND_PCM_FORMAT_S24_LE] = PA_SAMPLE_S24_32LE, - [SND_PCM_FORMAT_S24_BE] = PA_SAMPLE_S24_32BE, + static const snd_pcm_format_t format_trans_to_pcm[] = { + [PA_SAMPLE_U8] = SND_PCM_FORMAT_U8, + [PA_SAMPLE_ALAW] = SND_PCM_FORMAT_A_LAW, + [PA_SAMPLE_ULAW] = SND_PCM_FORMAT_MU_LAW, + [PA_SAMPLE_S16LE] = SND_PCM_FORMAT_S16_LE, + [PA_SAMPLE_S16BE] = SND_PCM_FORMAT_S16_BE, + [PA_SAMPLE_FLOAT32LE] = SND_PCM_FORMAT_FLOAT_LE, + [PA_SAMPLE_FLOAT32BE] = SND_PCM_FORMAT_FLOAT_BE, + [PA_SAMPLE_S32LE] = SND_PCM_FORMAT_S32_LE, + [PA_SAMPLE_S32BE] = SND_PCM_FORMAT_S32_BE, + [PA_SAMPLE_S24LE] = SND_PCM_FORMAT_S24_3LE, + [PA_SAMPLE_S24BE] = SND_PCM_FORMAT_S24_3BE, + [PA_SAMPLE_S24_32LE] = SND_PCM_FORMAT_S24_LE, + [PA_SAMPLE_S24_32BE] = SND_PCM_FORMAT_S24_BE, }; - static const snd_pcm_format_t all_formats[] = { - SND_PCM_FORMAT_U8, - SND_PCM_FORMAT_A_LAW, - SND_PCM_FORMAT_MU_LAW, - SND_PCM_FORMAT_S16_LE, - SND_PCM_FORMAT_S16_BE, - SND_PCM_FORMAT_FLOAT_LE, - SND_PCM_FORMAT_FLOAT_BE, - SND_PCM_FORMAT_S32_LE, - SND_PCM_FORMAT_S32_BE, - SND_PCM_FORMAT_S24_3LE, - SND_PCM_FORMAT_S24_3BE, - SND_PCM_FORMAT_S24_LE, - SND_PCM_FORMAT_S24_BE, + static const pa_sample_format_t all_formats[] = { + PA_SAMPLE_U8, + PA_SAMPLE_ALAW, + PA_SAMPLE_ULAW, + PA_SAMPLE_S16LE, + PA_SAMPLE_S16BE, + PA_SAMPLE_FLOAT32LE, + PA_SAMPLE_FLOAT32BE, + PA_SAMPLE_S32LE, + PA_SAMPLE_S32BE, + PA_SAMPLE_S24LE, + PA_SAMPLE_S24BE, + PA_SAMPLE_S24_32LE, + PA_SAMPLE_S24_32BE, }; bool supported[PA_ELEMENTSOF(all_formats)] = { false, @@ -1548,7 +1548,7 @@ pa_sample_format_t *pa_alsa_get_supported_formats(snd_pcm_t *pcm, pa_sample_form } for (i = 0, n = 0; i < PA_ELEMENTSOF(all_formats); i++) { - if (snd_pcm_hw_params_test_format(pcm, hwparams, all_formats[i]) == 0) { + if (snd_pcm_hw_params_test_format(pcm, hwparams, format_trans_to_pcm[all_formats[i]]) == 0) { supported[i] = true; n++; } @@ -1559,7 +1559,7 @@ pa_sample_format_t *pa_alsa_get_supported_formats(snd_pcm_t *pcm, pa_sample_form for (i = 0, j = 0; i < PA_ELEMENTSOF(all_formats); i++) { if (supported[i]) - formats[j++] = format_trans_to_pa[all_formats[i]]; + formats[j++] = all_formats[i]; } formats[j] = PA_SAMPLE_MAX; @@ -1567,7 +1567,7 @@ pa_sample_format_t *pa_alsa_get_supported_formats(snd_pcm_t *pcm, pa_sample_form formats = pa_xnew(pa_sample_format_t, 2); formats[0] = fallback_format; - if ((ret = snd_pcm_hw_params_set_format(pcm, hwparams, format_trans_to_pa[formats[0]])) < 0) { + if ((ret = snd_pcm_hw_params_set_format(pcm, hwparams, format_trans_to_pcm[formats[0]])) < 0) { pa_log_debug("snd_pcm_hw_params_set_format() failed: %s", pa_alsa_strerror(ret)); pa_xfree(formats); return NULL; From 15e76a69bfa5cc5cd90e9b6913c1b9ea366ff5ee Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Wed, 8 Feb 2023 10:39:26 +0300 Subject: [PATCH 104/260] memblockq: Drop check for chunk index alignment, require aligned length There is no requirement for chunk index to be aligned, we only need chunk length to be multiple of sample frame size. Fixes: 6434853b0 ("memblockq: Do not allow non-frame indices in the memblock queue") Fixes: 22827a5e1 ("protocol-native: Fail if trying to push unaligned memblock into queue") Part-of: --- src/pulsecore/memblockq.c | 1 - src/pulsecore/protocol-native.c | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c index b132dd318..69e2147c8 100644 --- a/src/pulsecore/memblockq.c +++ b/src/pulsecore/memblockq.c @@ -286,7 +286,6 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) { pa_assert(uchunk->index + uchunk->length <= pa_memblock_get_length(uchunk->memblock)); pa_assert(uchunk->length % bq->base == 0); - pa_assert(uchunk->index % bq->base == 0); if (!can_push(bq, uchunk->length)) return -1; diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 1342dee10..98b8795d9 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -5068,9 +5068,9 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o playback_stream *ps = PLAYBACK_STREAM(stream); size_t frame_size = pa_frame_size(&ps->sink_input->sample_spec); - if (chunk->index % frame_size != 0 || chunk->length % frame_size != 0) { - pa_log_warn("Client sent non-aligned memblock: index %d, length %d, frame size: %d", - (int) chunk->index, (int) chunk->length, (int) frame_size); + if (chunk->length % frame_size != 0) { + pa_log_warn("Client sent non-aligned memblock: length %d, frame size: %d", + (int) chunk->length, (int) frame_size); return; } From 39b6a4c1236ccb9f826ce5c58f258b72eb06740e Mon Sep 17 00:00:00 2001 From: Biswapriyo Nath Date: Thu, 16 Mar 2023 13:05:44 +0530 Subject: [PATCH 105/260] meson: Add DEF file to export APIs in Windows This helps to export correct APIs for compiler toolchain which does not support version script file. For example, mingw clang. The APIs in libpulse.def are similar with map-file except those are in pulse-simple and pulse-mainloop-glib. Those are exported in different shared library in Windows platform. Part-of: --- scripts/generate-map-file.sh | 13 +- src/pulse/libpulse.def | 379 +++++++++++++++++++++++++++++++++++ src/pulse/meson.build | 6 +- 3 files changed, 393 insertions(+), 5 deletions(-) create mode 100644 src/pulse/libpulse.def diff --git a/scripts/generate-map-file.sh b/scripts/generate-map-file.sh index ce843af34..2c8f015ac 100755 --- a/scripts/generate-map-file.sh +++ b/scripts/generate-map-file.sh @@ -17,7 +17,14 @@ print_map_file() { echo "};" } -TARGET_FILE=$1 -shift +print_def_file() { + echo "EXPORTS" + ctags -I ${CTAGS_IDENTIFIER_LIST} -f - --c-kinds=p "$@" | awk '/^pa_/ && !/(^pa_glib_|^pa_simple_)/ { print $1 }' | sort +} -cd "${MESON_SOURCE_ROOT}/${MESON_SUBDIR}" && print_map_file "$@" > ${TARGET_FILE} +MAP_FILE=$1 +DEF_FILE=$2 +shift 2 + +cd "${MESON_SOURCE_ROOT}/${MESON_SUBDIR}" && print_map_file "$@" > ${MAP_FILE} +cd "${MESON_SOURCE_ROOT}/${MESON_SUBDIR}" && print_def_file "$@" > ${DEF_FILE} diff --git a/src/pulse/libpulse.def b/src/pulse/libpulse.def new file mode 100644 index 000000000..e3e67cb5a --- /dev/null +++ b/src/pulse/libpulse.def @@ -0,0 +1,379 @@ +EXPORTS +pa_ascii_filter +pa_ascii_valid +pa_bytes_per_second +pa_bytes_snprint +pa_bytes_to_usec +pa_channel_map_can_balance +pa_channel_map_can_fade +pa_channel_map_can_lfe_balance +pa_channel_map_compatible +pa_channel_map_equal +pa_channel_map_has_position +pa_channel_map_init +pa_channel_map_init_auto +pa_channel_map_init_extend +pa_channel_map_init_mono +pa_channel_map_init_stereo +pa_channel_map_mask +pa_channel_map_parse +pa_channel_map_snprint +pa_channel_map_superset +pa_channel_map_to_name +pa_channel_map_to_pretty_name +pa_channel_map_valid +pa_channel_position_from_string +pa_channel_position_to_pretty_string +pa_channel_position_to_string +pa_channels_valid +pa_context_add_autoload +pa_context_connect +pa_context_disconnect +pa_context_drain +pa_context_errno +pa_context_exit_daemon +pa_context_get_autoload_info_by_index +pa_context_get_autoload_info_by_name +pa_context_get_autoload_info_list +pa_context_get_card_info_by_index +pa_context_get_card_info_by_name +pa_context_get_card_info_list +pa_context_get_client_info +pa_context_get_client_info_list +pa_context_get_index +pa_context_get_module_info +pa_context_get_module_info_list +pa_context_get_protocol_version +pa_context_get_sample_info_by_index +pa_context_get_sample_info_by_name +pa_context_get_sample_info_list +pa_context_get_server +pa_context_get_server_info +pa_context_get_server_protocol_version +pa_context_get_sink_info_by_index +pa_context_get_sink_info_by_name +pa_context_get_sink_info_list +pa_context_get_sink_input_info +pa_context_get_sink_input_info_list +pa_context_get_source_info_by_index +pa_context_get_source_info_by_name +pa_context_get_source_info_list +pa_context_get_source_output_info +pa_context_get_source_output_info_list +pa_context_get_state +pa_context_get_tile_size +pa_context_is_local +pa_context_is_pending +pa_context_kill_client +pa_context_kill_sink_input +pa_context_kill_source_output +pa_context_load_cookie_from_file +pa_context_load_module +pa_context_move_sink_input_by_index +pa_context_move_sink_input_by_name +pa_context_move_source_output_by_index +pa_context_move_source_output_by_name +pa_context_new +pa_context_new_with_proplist +pa_context_play_sample +pa_context_play_sample_with_proplist +pa_context_proplist_remove +pa_context_proplist_update +pa_context_ref +pa_context_remove_autoload_by_index +pa_context_remove_autoload_by_name +pa_context_remove_sample +pa_context_rttime_new +pa_context_rttime_restart +pa_context_send_message_to_object +pa_context_set_card_profile_by_index +pa_context_set_card_profile_by_name +pa_context_set_default_sink +pa_context_set_default_source +pa_context_set_event_callback +pa_context_set_name +pa_context_set_port_latency_offset +pa_context_set_sink_input_mute +pa_context_set_sink_input_volume +pa_context_set_sink_mute_by_index +pa_context_set_sink_mute_by_name +pa_context_set_sink_port_by_index +pa_context_set_sink_port_by_name +pa_context_set_sink_volume_by_index +pa_context_set_sink_volume_by_name +pa_context_set_source_mute_by_index +pa_context_set_source_mute_by_name +pa_context_set_source_output_mute +pa_context_set_source_output_volume +pa_context_set_source_port_by_index +pa_context_set_source_port_by_name +pa_context_set_source_volume_by_index +pa_context_set_source_volume_by_name +pa_context_set_state_callback +pa_context_set_subscribe_callback +pa_context_stat +pa_context_subscribe +pa_context_suspend_sink_by_index +pa_context_suspend_sink_by_name +pa_context_suspend_source_by_index +pa_context_suspend_source_by_name +pa_context_unload_module +pa_context_unref +pa_cvolume_avg +pa_cvolume_avg_mask +pa_cvolume_channels_equal_to +pa_cvolume_compatible +pa_cvolume_compatible_with_channel_map +pa_cvolume_dec +pa_cvolume_equal +pa_cvolume_get_balance +pa_cvolume_get_fade +pa_cvolume_get_lfe_balance +pa_cvolume_get_position +pa_cvolume_inc +pa_cvolume_inc_clamp +pa_cvolume_init +pa_cvolume_max +pa_cvolume_max_mask +pa_cvolume_merge +pa_cvolume_min +pa_cvolume_min_mask +pa_cvolume_remap +pa_cvolume_scale +pa_cvolume_scale_mask +pa_cvolume_set +pa_cvolume_set_balance +pa_cvolume_set_fade +pa_cvolume_set_lfe_balance +pa_cvolume_set_position +pa_cvolume_snprint +pa_cvolume_snprint_verbose +pa_cvolume_valid +pa_direction_to_string +pa_direction_valid +pa_encoding_from_string +pa_encoding_to_string +pa_ext_device_manager_delete +pa_ext_device_manager_enable_role_device_priority_routing +pa_ext_device_manager_read +pa_ext_device_manager_reorder_devices_for_role +pa_ext_device_manager_set_device_description +pa_ext_device_manager_set_subscribe_cb +pa_ext_device_manager_subscribe +pa_ext_device_manager_test +pa_ext_device_restore_read_formats +pa_ext_device_restore_read_formats_all +pa_ext_device_restore_save_formats +pa_ext_device_restore_set_subscribe_cb +pa_ext_device_restore_subscribe +pa_ext_device_restore_test +pa_ext_stream_restore_delete +pa_ext_stream_restore_read +pa_ext_stream_restore_set_subscribe_cb +pa_ext_stream_restore_subscribe +pa_ext_stream_restore_test +pa_ext_stream_restore_write +pa_format_info_copy +pa_format_info_free +pa_format_info_free_string_array +pa_format_info_from_sample_spec +pa_format_info_from_string +pa_format_info_get_channel_map +pa_format_info_get_channels +pa_format_info_get_prop_int +pa_format_info_get_prop_int_array +pa_format_info_get_prop_int_range +pa_format_info_get_prop_string +pa_format_info_get_prop_string_array +pa_format_info_get_prop_type +pa_format_info_get_rate +pa_format_info_get_sample_format +pa_format_info_is_compatible +pa_format_info_is_pcm +pa_format_info_new +pa_format_info_set_channel_map +pa_format_info_set_channels +pa_format_info_set_prop_int +pa_format_info_set_prop_int_array +pa_format_info_set_prop_int_range +pa_format_info_set_prop_string +pa_format_info_set_prop_string_array +pa_format_info_set_rate +pa_format_info_set_sample_format +pa_format_info_snprint +pa_format_info_to_sample_spec +pa_format_info_valid +pa_frame_size +pa_get_binary_name +pa_get_fqdn +pa_get_home_dir +pa_get_host_name +pa_get_library_version +pa_get_user_name +pa_gettimeofday +pa_locale_to_utf8 +pa_mainloop_api_once +pa_mainloop_dispatch +pa_mainloop_free +pa_mainloop_get_api +pa_mainloop_get_retval +pa_mainloop_iterate +pa_mainloop_new +pa_mainloop_poll +pa_mainloop_prepare +pa_mainloop_quit +pa_mainloop_run +pa_mainloop_set_poll_func +pa_mainloop_wakeup +pa_msleep +pa_operation_cancel +pa_operation_get_state +pa_operation_ref +pa_operation_set_state_callback +pa_operation_unref +pa_parse_sample_format +pa_path_get_filename +pa_proplist_clear +pa_proplist_contains +pa_proplist_copy +pa_proplist_equal +pa_proplist_free +pa_proplist_from_string +pa_proplist_get +pa_proplist_gets +pa_proplist_isempty +pa_proplist_iterate +pa_proplist_key_valid +pa_proplist_new +pa_proplist_set +pa_proplist_setf +pa_proplist_setp +pa_proplist_sets +pa_proplist_size +pa_proplist_to_string +pa_proplist_to_string_sep +pa_proplist_unset +pa_proplist_unset_many +pa_proplist_update +pa_rtclock_now +pa_sample_format_is_be +pa_sample_format_is_le +pa_sample_format_to_string +pa_sample_format_valid +pa_sample_rate_valid +pa_sample_size +pa_sample_size_of_format +pa_sample_spec_equal +pa_sample_spec_init +pa_sample_spec_snprint +pa_sample_spec_valid +pa_signal_done +pa_signal_free +pa_signal_init +pa_signal_new +pa_signal_set_destroy +pa_stream_begin_write +pa_stream_cancel_write +pa_stream_connect_playback +pa_stream_connect_record +pa_stream_connect_upload +pa_stream_cork +pa_stream_disconnect +pa_stream_drain +pa_stream_drop +pa_stream_finish_upload +pa_stream_flush +pa_stream_get_buffer_attr +pa_stream_get_channel_map +pa_stream_get_context +pa_stream_get_device_index +pa_stream_get_device_name +pa_stream_get_format_info +pa_stream_get_index +pa_stream_get_latency +pa_stream_get_monitor_stream +pa_stream_get_sample_spec +pa_stream_get_state +pa_stream_get_time +pa_stream_get_timing_info +pa_stream_get_underflow_index +pa_stream_is_corked +pa_stream_is_suspended +pa_stream_new +pa_stream_new_extended +pa_stream_new_with_proplist +pa_stream_peek +pa_stream_prebuf +pa_stream_proplist_remove +pa_stream_proplist_update +pa_stream_readable_size +pa_stream_ref +pa_stream_set_buffer_attr +pa_stream_set_buffer_attr_callback +pa_stream_set_event_callback +pa_stream_set_latency_update_callback +pa_stream_set_monitor_stream +pa_stream_set_moved_callback +pa_stream_set_name +pa_stream_set_overflow_callback +pa_stream_set_read_callback +pa_stream_set_started_callback +pa_stream_set_state_callback +pa_stream_set_suspended_callback +pa_stream_set_underflow_callback +pa_stream_set_write_callback +pa_stream_trigger +pa_stream_unref +pa_stream_update_sample_rate +pa_stream_update_timing_info +pa_stream_writable_size +pa_stream_write +pa_stream_write_ext_free +pa_strerror +pa_sw_cvolume_divide +pa_sw_cvolume_divide_scalar +pa_sw_cvolume_multiply +pa_sw_cvolume_multiply_scalar +pa_sw_cvolume_snprint_dB +pa_sw_volume_divide +pa_sw_volume_from_dB +pa_sw_volume_from_linear +pa_sw_volume_multiply +pa_sw_volume_snprint_dB +pa_sw_volume_to_dB +pa_sw_volume_to_linear +pa_thread_make_realtime +pa_threaded_mainloop_accept +pa_threaded_mainloop_free +pa_threaded_mainloop_get_api +pa_threaded_mainloop_get_retval +pa_threaded_mainloop_in_thread +pa_threaded_mainloop_lock +pa_threaded_mainloop_new +pa_threaded_mainloop_once_unlocked +pa_threaded_mainloop_set_name +pa_threaded_mainloop_signal +pa_threaded_mainloop_start +pa_threaded_mainloop_stop +pa_threaded_mainloop_unlock +pa_threaded_mainloop_wait +pa_timeval_add +pa_timeval_age +pa_timeval_cmp +pa_timeval_diff +pa_timeval_load +pa_timeval_store +pa_timeval_sub +pa_usec_to_bytes +pa_utf8_filter +pa_utf8_to_locale +pa_utf8_valid +pa_volume_snprint +pa_volume_snprint_verbose +pa_xfree +pa_xmalloc +pa_xmalloc0 +pa_xmemdup +pa_xrealloc +pa_xstrdup +pa_xstrndup diff --git a/src/pulse/meson.build b/src/pulse/meson.build index 40d407963..c132630f3 100644 --- a/src/pulse/meson.build +++ b/src/pulse/meson.build @@ -72,7 +72,7 @@ endif if host_machine.system() != 'windows' and host_machine.system() != 'darwin' run_target('update-map-file', - command : [ join_paths(meson.source_root(), 'scripts/generate-map-file.sh'), 'map-file', + command : [ join_paths(meson.source_root(), 'scripts/generate-map-file.sh'), 'map-file', 'libpulse.def', [ libpulse_headers, 'simple.h', join_paths(meson.build_root(), 'src', 'pulse', 'version.h') ] ]) versioning_link_args = ['-Wl,-version-script=' + join_paths(meson.source_root(), 'src', 'pulse', 'map-file')] @@ -90,7 +90,9 @@ libpulse = shared_library('pulse', install : true, install_rpath : privlibdir, dependencies : [libm_dep, thread_dep, libpulsecommon_dep, dbus_dep, dl_dep, iconv_dep, libintl_dep, platform_dep, platform_socket_dep, libatomic_ops_dep], - implicit_include_directories : false) + implicit_include_directories : false, + vs_module_defs : 'libpulse.def', +) libpulse_dep = declare_dependency(link_with: libpulse) From 3aaeb5113d2cec907bd101df22bb28b1a1b8394d Mon Sep 17 00:00:00 2001 From: Georg Chini Date: Sat, 11 Mar 2023 18:05:26 +0100 Subject: [PATCH 106/260] switch-on-connect: Do not overwrite user configured default sink/source Currently module-switch-on-connect overwrites the default sink or source that the user has configured. This means that when the overwritten default sink or source becomes unavailable, the new default will be chosen based on priority and the default will not return to the originally configured value. This patch solves the issue by introducing new core variables for the sink or source chosen by the policy module which have higher priority than the user configured defaults. Part-of: --- src/modules/module-switch-on-connect.c | 8 +- src/pulsecore/core.c | 125 +++++++++++++++++++++++-- src/pulsecore/core.h | 9 ++ 3 files changed, 131 insertions(+), 11 deletions(-) diff --git a/src/modules/module-switch-on-connect.c b/src/modules/module-switch-on-connect.c index 950ecbee2..edbab078a 100644 --- a/src/modules/module-switch-on-connect.c +++ b/src/modules/module-switch-on-connect.c @@ -100,7 +100,7 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void* /* No default sink, nothing to move away, just set the new default */ if (!c->default_sink) { - pa_core_set_configured_default_sink(c, sink->name); + pa_core_set_policy_default_sink(c, sink->name); return PA_HOOK_OK; } @@ -116,7 +116,7 @@ static pa_hook_result_t sink_put_hook_callback(pa_core *c, pa_sink *sink, void* } /* Actually do the switch to the new sink */ - pa_core_set_configured_default_sink(c, sink->name); + pa_core_set_policy_default_sink(c, sink->name); return PA_HOOK_OK; } @@ -160,7 +160,7 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, /* No default source, nothing to move away, just set the new default */ if (!c->default_source) { - pa_core_set_configured_default_source(c, source->name); + pa_core_set_policy_default_source(c, source->name); return PA_HOOK_OK; } @@ -176,7 +176,7 @@ static pa_hook_result_t source_put_hook_callback(pa_core *c, pa_source *source, } /* Actually do the switch to the new source */ - pa_core_set_configured_default_source(c, source->name); + pa_core_set_policy_default_source(c, source->name); return PA_HOOK_OK; } diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c index 132f08bbb..df7b72461 100644 --- a/src/pulsecore/core.c +++ b/src/pulsecore/core.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "core.h" @@ -149,6 +150,10 @@ pa_core* pa_core_new(pa_mainloop_api *m, bool shared, bool enable_memfd, size_t c->default_source = NULL; c->default_sink = NULL; + c->configured_default_source = NULL; + c->configured_default_sink = NULL; + c->policy_default_source = NULL; + c->policy_default_sink = NULL; c->default_sample_spec.format = PA_SAMPLE_S16NE; c->default_sample_spec.rate = 44100; @@ -261,6 +266,8 @@ static void core_free(pa_object *o) { pa_assert(!c->default_sink); pa_xfree(c->configured_default_source); pa_xfree(c->configured_default_sink); + pa_xfree(c->policy_default_source); + pa_xfree(c->policy_default_sink); pa_silence_cache_done(&c->silence_cache); pa_mempool_unref(c->mempool); @@ -271,6 +278,36 @@ static void core_free(pa_object *o) { pa_xfree(c); } +static bool is_sink_available(pa_core *core, const char *sink_name) { + pa_sink *sink; + + if (!(sink = pa_namereg_get(core, sink_name, PA_NAMEREG_SINK))) + return false; + + if (!PA_SINK_IS_LINKED(sink->state)) + return false; + + if (sink->active_port && sink->active_port->available == PA_AVAILABLE_NO) + return false; + + return true; +} + +static bool is_source_available(pa_core *core, const char *source_name) { + pa_source *source; + + if (!(source = pa_namereg_get(core, source_name, PA_NAMEREG_SOURCE))) + return false; + + if (!PA_SOURCE_IS_LINKED(source->state)) + return false; + + if (source->active_port && source->active_port->available == PA_AVAILABLE_NO) + return false; + + return true; +} + void pa_core_set_configured_default_sink(pa_core *core, const char *sink) { char *old_sink; @@ -278,13 +315,21 @@ void pa_core_set_configured_default_sink(pa_core *core, const char *sink) { old_sink = pa_xstrdup(core->configured_default_sink); - if (pa_safe_streq(sink, old_sink)) + /* The default sink was overwritten by the policy default sink, but the user is + * now setting a new default manually. Clear the policy default sink. */ + if (core->policy_default_sink && is_sink_available(core, core->policy_default_sink)) { + pa_xfree(core->policy_default_sink); + core->policy_default_sink = NULL; + + } else if (pa_safe_streq(sink, old_sink)) goto finish; pa_xfree(core->configured_default_sink); core->configured_default_sink = pa_xstrdup(sink); - pa_log_info("configured_default_sink: %s -> %s", - old_sink ? old_sink : "(unset)", sink ? sink : "(unset)"); + if (!pa_safe_streq(sink, old_sink)) { + pa_log_info("configured_default_sink: %s -> %s", + old_sink ? old_sink : "(unset)", sink ? sink : "(unset)"); + } pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SERVER | PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX); pa_core_update_default_sink(core); @@ -300,12 +345,64 @@ void pa_core_set_configured_default_source(pa_core *core, const char *source) { old_source = pa_xstrdup(core->configured_default_source); - if (pa_safe_streq(source, old_source)) + /* The default source was overwritten by the policy default source, but the user is + * now setting a new default manually. Clear the policy default source. */ + if (core->policy_default_source && is_source_available(core, core->policy_default_source)) { + pa_xfree(core->policy_default_source); + core->policy_default_source = NULL; + + } else if (pa_safe_streq(source, old_source)) goto finish; pa_xfree(core->configured_default_source); core->configured_default_source = pa_xstrdup(source); - pa_log_info("configured_default_source: %s -> %s", + if (!pa_safe_streq(source, old_source)) { + pa_log_info("configured_default_source: %s -> %s", + old_source ? old_source : "(unset)", source ? source : "(unset)"); + } + pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SERVER | PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX); + + pa_core_update_default_source(core); + +finish: + pa_xfree(old_source); +} + +void pa_core_set_policy_default_sink(pa_core *core, const char *sink) { + char *old_sink; + + pa_assert(core); + + old_sink = pa_xstrdup(core->policy_default_sink); + + if (pa_safe_streq(sink, old_sink)) + goto finish; + + pa_xfree(core->policy_default_sink); + core->policy_default_sink = pa_xstrdup(sink); + pa_log_info("policy_default_sink: %s -> %s", + old_sink ? old_sink : "(unset)", sink ? sink : "(unset)"); + pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SERVER | PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX); + + pa_core_update_default_sink(core); + +finish: + pa_xfree(old_sink); +} + +void pa_core_set_policy_default_source(pa_core *core, const char *source) { + char *old_source; + + pa_assert(core); + + old_source = pa_xstrdup(core->policy_default_source); + + if (pa_safe_streq(source, old_source)) + goto finish; + + pa_xfree(core->policy_default_source); + core->policy_default_source = pa_xstrdup(source); + pa_log_info("policy_default_source: %s -> %s", old_source ? old_source : "(unset)", source ? source : "(unset)"); pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SERVER | PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX); @@ -331,7 +428,14 @@ static int compare_sinks(pa_sink *a, pa_sink *b) { && (!a->active_port || a->active_port->available != PA_AVAILABLE_NO)) return 1; - /* The configured default sink is preferred over any other sink. */ + /* The policy default sink is preferred over any other sink. */ + if (pa_safe_streq(b->name, core->policy_default_sink)) + return -1; + if (pa_safe_streq(a->name, core->policy_default_sink)) + return 1; + + /* The configured default sink is preferred over any other sink + * except the policy default sink. */ if (pa_safe_streq(b->name, core->configured_default_sink)) return -1; if (pa_safe_streq(a->name, core->configured_default_sink)) @@ -412,7 +516,14 @@ static int compare_sources(pa_source *a, pa_source *b) { && (!a->active_port || a->active_port->available != PA_AVAILABLE_NO)) return 1; - /* The configured default source is preferred over any other source. */ + /* The policy default source is preferred over any other source. */ + if (pa_safe_streq(b->name, core->policy_default_source)) + return -1; + if (pa_safe_streq(a->name, core->policy_default_source)) + return 1; + + /* The configured default source is preferred over any other source + * except the policy default source. */ if (pa_safe_streq(b->name, core->configured_default_source)) return -1; if (pa_safe_streq(a->name, core->configured_default_source)) diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h index 118dcf291..7ac06f5d7 100644 --- a/src/pulsecore/core.h +++ b/src/pulsecore/core.h @@ -176,6 +176,13 @@ struct pa_core { char *configured_default_sink; char *configured_default_source; + /* The default sink/source set by some policy module. This will override + * the user configured default sink/source, so that the default will + * return to the user configured sink/source once the sink/source set by + * the policy module is no longer available. */ + char *policy_default_sink; + char *policy_default_source; + /* The effective default sink/source. If no sink or source is explicitly * configured as the default, we pick the device that ranks highest * according to the compare_sinks() and compare_sources() functions in @@ -249,6 +256,8 @@ pa_core* pa_core_new(pa_mainloop_api *m, bool shared, bool enable_memfd, size_t void pa_core_set_configured_default_sink(pa_core *core, const char *sink); void pa_core_set_configured_default_source(pa_core *core, const char *source); +void pa_core_set_policy_default_sink(pa_core *core, const char *sink); +void pa_core_set_policy_default_source(pa_core *core, const char *source); /* These should be called whenever something changes that may affect the * default sink or source choice. From b382a00f8bf937e6825892ea0c971c99018dc466 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Thu, 24 Jun 2021 11:03:27 +0300 Subject: [PATCH 107/260] alsa-ucm: Add enable, disable, status helpers for modifiers These are mostly the same as the device helpers added in c83b34516929 ("alsa-ucm: Add enable, disable, status helpers for devices"), but for modifiers instead. Signed-off-by: Alper Nebi Yasak Part-of: --- src/modules/alsa/alsa-ucm.c | 68 +++++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 14 deletions(-) diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c index 744e7aae1..ecf296442 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -702,6 +702,57 @@ static int ucm_get_modifiers(pa_alsa_ucm_verb *verb, snd_use_case_mgr_t *uc_mgr) return 0; }; +static long ucm_modifier_status(pa_alsa_ucm_config *ucm, pa_alsa_ucm_modifier *mod) { + const char *mod_name = pa_proplist_gets(mod->proplist, PA_ALSA_PROP_UCM_NAME); + char *modstatus; + long status = 0; + + modstatus = pa_sprintf_malloc("_modstatus/%s", mod_name); + if (snd_use_case_geti(ucm->ucm_mgr, modstatus, &status) < 0) { + pa_log_debug("Failed to get status for UCM modifier %s", mod_name); + status = -1; + } + pa_xfree(modstatus); + + return status; +} + +static int ucm_modifier_disable(pa_alsa_ucm_config *ucm, pa_alsa_ucm_modifier *mod) { + const char *mod_name = pa_proplist_gets(mod->proplist, PA_ALSA_PROP_UCM_NAME); + + /* We don't need to disable modifiers that are already disabled */ + if (ucm_modifier_status(ucm, mod) == 0) { + pa_log_debug("UCM modifier %s is already disabled", mod_name); + return 0; + } + + pa_log_debug("Disabling UCM modifier %s", mod_name); + if (snd_use_case_set(ucm->ucm_mgr, "_dismod", mod_name) < 0) { + pa_log("Failed to disable UCM modifier %s", mod_name); + return -1; + } + + return 0; +} + +static int ucm_modifier_enable(pa_alsa_ucm_config *ucm, pa_alsa_ucm_modifier *mod) { + const char *mod_name = pa_proplist_gets(mod->proplist, PA_ALSA_PROP_UCM_NAME); + + /* We don't need to enable modifiers that are already enabled */ + if (ucm_modifier_status(ucm, mod) > 0) { + pa_log_debug("UCM modifier %s is already enabled", mod_name); + return 0; + } + + pa_log_debug("Enabling UCM modifier %s", mod_name); + if (snd_use_case_set(ucm->ucm_mgr, "_enamod", mod_name) < 0) { + pa_log("Failed to enable UCM modifier %s", mod_name); + return -1; + } + + return 0; +} + static void add_role_to_device(pa_alsa_ucm_device *dev, const char *dev_name, const char *role_name, const char *role) { const char *cur = pa_proplist_gets(dev->proplist, role_name); @@ -2298,12 +2349,7 @@ void pa_alsa_ucm_roled_stream_begin(pa_alsa_ucm_config *ucm, const char *role, p PA_LLIST_FOREACH(mod, ucm->active_verb->modifiers) { if ((mod->action_direction == dir) && (pa_streq(mod->media_role, role))) { if (mod->enabled_counter == 0) { - const char *mod_name = pa_proplist_gets(mod->proplist, PA_ALSA_PROP_UCM_NAME); - - pa_log_info("Enable ucm modifier %s", mod_name); - if (snd_use_case_set(ucm->ucm_mgr, "_enamod", mod_name) < 0) { - pa_log("Failed to enable ucm modifier %s", mod_name); - } + ucm_modifier_enable(ucm, mod); } mod->enabled_counter++; @@ -2323,14 +2369,8 @@ void pa_alsa_ucm_roled_stream_end(pa_alsa_ucm_config *ucm, const char *role, pa_ if ((mod->action_direction == dir) && (pa_streq(mod->media_role, role))) { mod->enabled_counter--; - if (mod->enabled_counter == 0) { - const char *mod_name = pa_proplist_gets(mod->proplist, PA_ALSA_PROP_UCM_NAME); - - pa_log_info("Disable ucm modifier %s", mod_name); - if (snd_use_case_set(ucm->ucm_mgr, "_dismod", mod_name) < 0) { - pa_log("Failed to disable ucm modifier %s", mod_name); - } - } + if (mod->enabled_counter == 0) + ucm_modifier_disable(ucm, mod); break; } From b74269016c1f7babcdd69d33f20cedbe33fe3124 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 29 Jun 2022 15:37:18 +0300 Subject: [PATCH 108/260] alsa-ucm: Disable old modifiers when switching profiles of same verb While switching profiles of the same UCM verb, existing code first disables devices that are only on the first profile to avoid conflicts. However, it only disables devices, not modifiers. Even worse, modifiers which have PlaybackPCM/CapturePCM are incorrectly treated as devices and result in a segmentation fault. Check what we are disabling, and call the appropriate disable function for both devices and modifiers. Modifiers are disabled before devices, because _dismod calls fail when the modifier's supported devices are disabled. Signed-off-by: Alper Nebi Yasak Part-of: --- src/modules/alsa/alsa-ucm.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c index ecf296442..785b23453 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -1498,15 +1498,28 @@ int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, pa_card *card, pa_alsa_prof } } else if (ucm->active_verb) { - /* Disable devices not in new profile */ + /* Disable modifiers not in new profile. Has to be done before + * devices, because _dismod fails if a modifier's supported + * devices are disabled. */ PA_IDXSET_FOREACH(map, old_profile->input_mappings, idx) if (new_profile && !pa_idxset_contains(new_profile->input_mappings, map)) - if (ucm_device_disable(ucm, map->ucm_context.ucm_device) < 0) + if (map->ucm_context.ucm_modifier && ucm_modifier_disable(ucm, map->ucm_context.ucm_modifier) < 0) ret = -1; PA_IDXSET_FOREACH(map, old_profile->output_mappings, idx) if (new_profile && !pa_idxset_contains(new_profile->output_mappings, map)) - if (ucm_device_disable(ucm, map->ucm_context.ucm_device) < 0) + if (map->ucm_context.ucm_modifier && ucm_modifier_disable(ucm, map->ucm_context.ucm_modifier) < 0) + ret = -1; + + /* Disable devices not in new profile */ + PA_IDXSET_FOREACH(map, old_profile->input_mappings, idx) + if (new_profile && !pa_idxset_contains(new_profile->input_mappings, map)) + if (map->ucm_context.ucm_device && ucm_device_disable(ucm, map->ucm_context.ucm_device) < 0) + ret = -1; + + PA_IDXSET_FOREACH(map, old_profile->output_mappings, idx) + if (new_profile && !pa_idxset_contains(new_profile->output_mappings, map)) + if (map->ucm_context.ucm_device && ucm_device_disable(ucm, map->ucm_context.ucm_device) < 0) ret = -1; } ucm->active_verb = verb; From 45509ff9bc92345fef4ecf1003bee6fe632c3bcb Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Fri, 19 Aug 2022 19:52:56 +0300 Subject: [PATCH 109/260] alsa-ucm: Consider devices using the same PCM as incompatible Although it's a valid UCM configuration to have multiple devices using the same PlaybackPCM or CapturePCM, it's unclear how PulseAudio should handle the cases where multiple of these devices are enabled. Some options I can think of are: - Merge all devices sharing the same PCM into the same mapping, open only one PCM substream for this mapping, and add 'combination ports' that enable combinations of the devices. This has been the case until recently, although the combination port logic was broken. A problem with this is that we can't independently control device volumes. We most likely cannot use hardware volumes either. - Have one mapping for each device in the same profile, and open one PCM substream for each mapping. This is the current state, and it fails when there are fewer substreams than devices. Otherwise it works, but it's still confusing, as sound directed to a device-specific mapping might end up playing at multiple devices. - Make multiple profiles each with combinations of upto-substream-count devices, and have one mapping/substream per device. This still causes the confusion mentioned above. And it's likely that the substream count will almost always be one, where this case degenerates into the last one. - Have one mapping for each device in the same profile, but open only one PCM substream. I assume this is possible with software mixing, but it is still confusing like the above, and probably less performant. - Generate multiple profiles each with one of the shared-PCM devices, again with one mapping/substream for that one device. The trade-off with this is that we can't use multiple of these devices at the same time. However, this doesn't have the output device confusion, combination port's volume problems, or the substream count limitation. This patch takes a short-cut to achieve the last option, by considering shared-PCM devices implicitly conflicting with each other. Signed-off-by: Alper Nebi Yasak Part-of: --- src/modules/alsa/alsa-ucm.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c index 785b23453..50a7cd8d8 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -1279,6 +1279,7 @@ void pa_alsa_ucm_add_port( } static bool devset_supports_device(pa_idxset *devices, pa_alsa_ucm_device *dev) { + const char *sink, *sink2, *source, *source2; pa_alsa_ucm_device *d; uint32_t idx; @@ -1302,12 +1303,26 @@ static bool devset_supports_device(pa_idxset *devices, pa_alsa_ucm_device *dev) if (!pa_idxset_issubset(devices, dev->supported_devices)) return false; - /* Must not be unsupported by any selected device */ - PA_IDXSET_FOREACH(d, devices, idx) + sink = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_SINK); + source = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_SOURCE); + + PA_IDXSET_FOREACH(d, devices, idx) { + /* Must not be unsupported by any selected device */ if (!pa_idxset_isempty(d->supported_devices)) if (!pa_idxset_contains(d->supported_devices, dev)) return false; + /* PlaybackPCM must not be the same as any selected device */ + sink2 = pa_proplist_gets(d->proplist, PA_ALSA_PROP_UCM_SINK); + if (sink && sink2 && pa_streq(sink, sink2)) + return false; + + /* CapturePCM must not be the same as any selected device */ + source2 = pa_proplist_gets(d->proplist, PA_ALSA_PROP_UCM_SOURCE); + if (source && source2 && pa_streq(source, source2)) + return false; + } + return true; } From 7005eafee305dfac5c314cee0d0109c2a472ffd1 Mon Sep 17 00:00:00 2001 From: Alper Nebi Yasak Date: Wed, 25 Jan 2023 01:31:56 +0300 Subject: [PATCH 110/260] alsa-ucm: Fix more instances of profile-verb conflation The ucm_get_device_property() function adds to each UCM device's playback_volumes (or capture_volumes) hash map an associated volume mixer keyed with the UCM verb. These key-value pairs are then iterated over in various places which assume the key is a profile name. This assumption is no longer true since we can generate multiple profiles to use conflicting devices. A previous commit 45278904167f ("alsa-ucm: Stop conflating profile name with UCM verb name") fixes some instances of this assumption, but misses the relation explained above. Fix more instances of misleading "profile"s where the UCM verb name is actually meant. Fixes: 45278904167f ("alsa-ucm: Stop conflating profile name with UCM verb name") Signed-off-by: Alper Nebi Yasak Part-of: --- src/modules/alsa/alsa-ucm.c | 32 ++++++++++++++++---------------- src/modules/alsa/alsa-ucm.h | 4 ++-- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c index 50a7cd8d8..1cdd140c6 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -898,7 +898,7 @@ int pa_alsa_ucm_query_profiles(pa_alsa_ucm_config *ucm, int card_index) { free((void *)value); } - /* get a list of all UCM verbs (profiles) for this card */ + /* get a list of all UCM verbs for this card */ num_verbs = snd_use_case_verb_list(ucm->ucm_mgr, &verb_list); if (num_verbs < 0) { pa_log("UCM verb list not found for %s", card_name); @@ -1020,16 +1020,16 @@ static void set_eld_devices(pa_hashmap *hash) } } -static void update_mixer_paths(pa_hashmap *ports, const char *profile_name) { +static void update_mixer_paths(pa_hashmap *ports, const char *verb_name) { pa_device_port *port; pa_alsa_ucm_port_data *data; void *state; /* select volume controls on ports */ PA_HASHMAP_FOREACH(port, ports, state) { - pa_log_info("Updating mixer path for %s: %s", profile_name, port->name); + pa_log_info("Updating mixer path for %s: %s", verb_name, port->name); data = PA_DEVICE_PORT_DATA(port); - data->path = pa_hashmap_get(data->paths, profile_name); + data->path = pa_hashmap_get(data->paths, verb_name); } } @@ -1039,7 +1039,7 @@ static void probe_volumes(pa_hashmap *hash, bool is_sink, snd_pcm_t *pcm_handle, pa_alsa_ucm_port_data *data; pa_alsa_ucm_device *dev; snd_mixer_t *mixer_handle; - const char *profile, *mdev; + const char *verb_name, *mdev; void *state, *state2; PA_HASHMAP_FOREACH(port, hash, state) { @@ -1052,16 +1052,16 @@ static void probe_volumes(pa_hashmap *hash, bool is_sink, snd_pcm_t *pcm_handle, goto fail; } - PA_HASHMAP_FOREACH_KV(profile, path, data->paths, state2) { + PA_HASHMAP_FOREACH_KV(verb_name, path, data->paths, state2) { if (pa_alsa_path_probe(path, NULL, mixer_handle, ignore_dB) < 0) { pa_log_warn("Could not probe path: %s, using s/w volume", path->name); - pa_hashmap_remove(data->paths, profile); + pa_hashmap_remove(data->paths, verb_name); } else if (!path->has_volume && !path->has_mute) { pa_log_warn("Path %s is not a volume or mute control", path->name); - pa_hashmap_remove(data->paths, profile); + pa_hashmap_remove(data->paths, verb_name); } else pa_log_debug("Set up h/w %s using '%s' for %s:%s", path->has_volume ? "volume" : "mute", - path->name, profile, port->name); + path->name, verb_name, port->name); } } @@ -1191,7 +1191,7 @@ void pa_alsa_ucm_add_port( char *name, *desc; const char *dev_name; const char *direction; - const char *profile; + const char *verb_name; pa_alsa_ucm_device *dev; pa_alsa_ucm_port_data *data; pa_alsa_ucm_volume *vol; @@ -1232,7 +1232,7 @@ void pa_alsa_ucm_add_port( pa_hashmap_put(ports, port->name, port); pa_log_debug("Add port %s: %s", port->name, port->description); - PA_HASHMAP_FOREACH_KV(profile, vol, is_sink ? dev->playback_volumes : dev->capture_volumes, state) { + PA_HASHMAP_FOREACH_KV(verb_name, vol, is_sink ? dev->playback_volumes : dev->capture_volumes, state) { pa_alsa_path *path = pa_alsa_path_synthesize(vol->mixer_elem, is_sink ? PA_ALSA_DIRECTION_OUTPUT : PA_ALSA_DIRECTION_INPUT); @@ -1245,7 +1245,7 @@ void pa_alsa_ucm_add_port( e->volume_use = PA_ALSA_VOLUME_MERGE; } - pa_hashmap_put(data->paths, pa_xstrdup(profile), path); + pa_hashmap_put(data->paths, pa_xstrdup(verb_name), path); /* Add path also to already created empty path set */ if (is_sink) @@ -1449,8 +1449,8 @@ void pa_alsa_ucm_add_ports( /* now set up volume paths if any */ probe_volumes(*p, is_sink, pcm_handle, context->ucm->mixers, ignore_dB); - /* probe_volumes() removes per-profile paths from ports if probing them - * fails. The path for the current profile is cached in + /* probe_volumes() removes per-verb paths from ports if probing them + * fails. The path for the current verb is cached in * pa_alsa_ucm_port_data.path, which is not cleared by probe_volumes() if * the path gets removed, so we have to call update_mixer_paths() here to * unset the cached path if needed. */ @@ -1539,7 +1539,7 @@ int pa_alsa_ucm_set_profile(pa_alsa_ucm_config *ucm, pa_card *card, pa_alsa_prof } ucm->active_verb = verb; - update_mixer_paths(card->ports, profile_name); + update_mixer_paths(card->ports, verb_name); return ret; } @@ -2247,7 +2247,7 @@ pa_alsa_profile_set* pa_alsa_ucm_add_profile_set(pa_alsa_ucm_config *ucm, pa_cha ps->profiles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); ps->decibel_fixes = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func); - /* create a profile for each verb */ + /* create profiles for each verb */ PA_LLIST_FOREACH(verb, ucm->verbs) { const char *verb_name; const char *verb_desc; diff --git a/src/modules/alsa/alsa-ucm.h b/src/modules/alsa/alsa-ucm.h index 0f596ef0c..543eefe0f 100644 --- a/src/modules/alsa/alsa-ucm.h +++ b/src/modules/alsa/alsa-ucm.h @@ -276,9 +276,9 @@ struct pa_alsa_ucm_port_data { pa_alsa_ucm_device *device; - /* profile name -> pa_alsa_path for volume control */ + /* verb name -> pa_alsa_path for volume control */ pa_hashmap *paths; - /* Current path, set when activating profile */ + /* Current path, set when activating verb */ pa_alsa_path *path; /* ELD info */ From 3e038c6d88129feeb7deaac6d853b5451170d288 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Thu, 17 Nov 2022 18:36:17 +0900 Subject: [PATCH 111/260] alsa: ucm: Fix spurious mixer path removal on initial profile set The code that removes the mixer path if probing fails can be called in the path that sets a non-off device profile on hotplug *before* card->active_profile is updated, which results in spuriously removing the mixer path. By this point, context->ucm->active_verb would be set to the same as the profile name, so we can use that instead to avoid the issue. On Apple Silicon machines with the UCM profiles in the Asahi Linux repo, this manifests as the headphones jack having hardware volume controls *only* if PA is started with headphones connected and until they are disconnected. Hotplugs end up triggering the bad codepath, and it falls back to software volume (which is particularly a problem when the hardware volume happens to be very low or 0 at that point). Fixes: a9cc1373e2a7 ("alsa: ucm - update the mixer path also after volume probe") Signed-off-by: Hector Martin Part-of: --- src/modules/alsa/alsa-ucm.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c index 1cdd140c6..bb9438f79 100644 --- a/src/modules/alsa/alsa-ucm.c +++ b/src/modules/alsa/alsa-ucm.c @@ -1454,8 +1454,11 @@ void pa_alsa_ucm_add_ports( * pa_alsa_ucm_port_data.path, which is not cleared by probe_volumes() if * the path gets removed, so we have to call update_mixer_paths() here to * unset the cached path if needed. */ - if (card->active_profile) - update_mixer_paths(*p, card->active_profile->name); + if (context->ucm->active_verb) { + const char *verb_name; + verb_name = pa_proplist_gets(context->ucm->active_verb->proplist, PA_ALSA_PROP_UCM_NAME); + update_mixer_paths(*p, verb_name); + } /* then set property PA_PROP_DEVICE_INTENDED_ROLES */ merged_roles = pa_xstrdup(pa_proplist_gets(proplist, PA_PROP_DEVICE_INTENDED_ROLES)); From 25bfdb3ab8ae25d477927ff24c3ca4d2d4e81246 Mon Sep 17 00:00:00 2001 From: Weijia Wang Date: Wed, 22 Mar 2023 20:09:38 +0200 Subject: [PATCH 112/260] echo-cancel: Fix macOS build Signed-off-by: Weijia Wang Part-of: --- src/modules/echo-cancel/meson.build | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/modules/echo-cancel/meson.build b/src/modules/echo-cancel/meson.build index 3b998364e..94420c289 100644 --- a/src/modules/echo-cancel/meson.build +++ b/src/modules/echo-cancel/meson.build @@ -3,7 +3,8 @@ # even conditional ones). # This library requires a symbol from module-echo-cancel, hence we need -# '-Wl,--unresolved-symbols=ignore-in-object-files' otherwise it fails +# '-Wl,--unresolved-symbols=ignore-in-object-files', or +# '-Wl,-undefined,dynamic_lookup' on macOS, otherwise it fails # at link time. add_languages('cpp') @@ -12,12 +13,18 @@ libwebrtc_util_sources = [ 'webrtc.cc' ] +if host_machine.system() == 'darwin' + ignore_unresolved_symbols_link_args = ['-Wl,-undefined,dynamic_lookup'] +else + ignore_unresolved_symbols_link_args = ['-Wl,--unresolved-symbols=ignore-in-object-files'] +endif + libwebrtc_util = shared_library('webrtc-util', libwebrtc_util_sources, cpp_args : [pa_c_args, server_c_args], include_directories : [configinc, topinc], dependencies : [libpulse_dep, libpulsecommon_dep, libpulsecore_dep, libatomic_ops_dep, webrtc_dep, libintl_dep], - link_args : [nodelete_link_args, '-Wl,--unresolved-symbols=ignore-in-object-files'], + link_args : [nodelete_link_args, ignore_unresolved_symbols_link_args], install : true, install_rpath : privlibdir, install_dir : modlibexecdir, From 86e9c901289d2e1a3c2c6cb5885294a829f3eb27 Mon Sep 17 00:00:00 2001 From: Georg Chini Date: Mon, 20 Mar 2023 21:35:10 +0100 Subject: [PATCH 113/260] pactl, pacmd: Allow to unset the configured default sink or source Currently there is no way to unset the default sink or source once it was configured manually by the user. This patch introduces the special name @NONE@, which can be used with the pacmd or pactl set-default-sink and set-default-source commands to unset the user configured default. When the default is unset, pulseaudio will return to the standard default sink or source selection mechanism based on priority. Part-of: --- man/pactl.1.xml.in | 8 ++++++-- man/pulse-cli-syntax.5.xml.in | 6 ++++-- src/pulsecore/cli-command.c | 8 ++++++-- src/pulsecore/protocol-native.c | 28 +++++++++++++++++++--------- 4 files changed, 35 insertions(+), 15 deletions(-) diff --git a/man/pactl.1.xml.in b/man/pactl.1.xml.in index d4eb03458..ca365dc23 100644 --- a/man/pactl.1.xml.in +++ b/man/pactl.1.xml.in @@ -174,7 +174,9 @@ License along with PulseAudio; if not, see .