Projects
Essentials
pipewire-aptx
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 61
View file
pipewire-aptx.changes
Changed
@@ -1,4 +1,9 @@ ------------------------------------------------------------------- +Wed Jan 7 20:28:17 UTC 2026 - Bjørn Lie <zaitor@opensuse.org> + +- Update to version 1.5.84 + +------------------------------------------------------------------- Sat Nov 15 13:00:32 UTC 2025 - Bjørn Lie <zaitor@opensuse.org> - Update to version 1.5.83
View file
pipewire-aptx.spec
Changed
@@ -8,7 +8,7 @@ %define minimum_version 1.5.0 Name: pipewire-aptx -Version: 1.5.83 +Version: 1.5.84 Release: 0 Summary: PipeWire Bluetooth aptX codec plugin License: MIT
View file
_service:download_files:pipewire-1.5.83.tar.bz2/NEWS -> _service:download_files:pipewire-1.5.84.tar.bz2/NEWS
Changed
@@ -1,16 +1,61 @@ -# PipeWire 1.5.83 (2025-11-06) +# PipeWire 1.5.84 (2025-11-27) -This is the third 1.6 release candidate that is API and ABI +This is the fourth 1.6 release candidate that is API and ABI compatible with previous 1.4.x, 1.2.x and 1.0.x releases. Changes since the last pre-release: ## Highlights - - Include the NEWS and updated version number. + - Capabilities wer added to improve negotiation over links. + - The audio resampler now has a configurable window function to better + tune the resampler quality. A kaiser and blackman window was added + and the default parameters were tuned. + - Various small fixes and improvements. + +## PipeWire + - Capabilities and PeerCapabilities were added to exchange key/value + pairs between consumer and producer right after a link is made. This + can be used to detect how the negotiation of formats and buffers + should be done. + +## Modules + - Avoid segfaults in RTP source. (#4970) + - The AVB module has seen some improvements. + +## Pulse-server + - @NONE@ can now be used to clear the default sink/source. + +## SPA + - Support longer convolver filenames and also support inline + IRs. + - The audio resampler window function is now selectable and + configurable. A kaiser window and blackman window was added + and the default qualities were tweaked to improve quality. + - The filter-graph convolver latency is now set by default to + something more sensible. (0 by default and N/2 for hilbert). + (#4980) + +## Bluetooth + - Better xrun and error handling for iso streams. + - The +CNUM reply was fixed. + - The CIEC call status was fixed. (#1744) + - Add BAP context metadata to improve compatibility. + - Improve compatiblity with Creative Zen Hybrid Pro by releasing + transports simultaneously. Older versions: +# PipeWire 1.5.83 (2025-11-06) + +This is the third 1.6 release candidate that is API and ABI +compatible with previous 1.4.x, 1.2.x and 1.0.x releases. + +Changes since the last pre-release: + +## Highlights + - Include the NEWS and updated version number. + # PipeWire 1.5.82 (2025-11-06) This is the second 1.6 release candidate that is API and ABI
View file
_service:download_files:pipewire-1.5.83.tar.bz2/doc/dox/config/pipewire-client.conf.5.md -> _service:download_files:pipewire-1.5.84.tar.bz2/doc/dox/config/pipewire-client.conf.5.md
Changed
@@ -59,6 +59,14 @@ #node.autoconnect = true #resample.disable = false #resample.quality = 4 + #resample.window = exp # blackman kaiser + #resample.cutoff = 0.0 + #resample.n-taps = 0 + #resample.param.exp.A = 0.0 + #resample.param.blackman.alpha = 0.0 + #resample.param.kaiser.alpha = 0.0 + #resample.param.kaiser.stopband-attenuation = 0.0 + #resample.param.kaiser.transition-bandwidth = 0.0 #monitor.channel-volumes = false #channelmix.disable = false #channelmix.min-volume = 0.0
View file
_service:download_files:pipewire-1.5.83.tar.bz2/doc/dox/config/pipewire-props.7.md -> _service:download_files:pipewire-1.5.84.tar.bz2/doc/dox/config/pipewire-props.7.md
Changed
@@ -558,6 +558,41 @@ Disable the resampler entirely. The node will only be able to negotiate with the graph when the samplerates are compatible. +@PAR@ node-prop resample.window = exp +The resampler window function to use. By default an exponential window function is used +that gives a good balance between complexitiy and quality. + +You can also specify a blackman or kaiser window, both with different tradeoffs. + +@PAR@ node-prop resample.cutoff = 0.0 +The resampler cutoff frequency. A value of 0.0 will use a predefined value based on +the resampler quality. + +@PAR@ node-prop resample.n-taps = 0 +The resampler number of taps. A value of 0 will use a predefined value based on +the resampler quality or other window function parameters. + +@PAR@ node-prop resample.param.exp.A = 0.0 +The A parameter for the exponential window function. A value of 0.0 will use a predefined +value based on the quality when the exp window is in use. + +@PAR@ node-prop resample.param.blackman.alpha = 0.0 +The alpha value of the blackman function. A value of 0.0 will use a predefined +value based on the quality when the blackman window is in use. + +@PAR@ node-prop resample.param.kaiser.stopband-attenuation = 0.0 +The kaiser window stopband attenuation parameter. A default value of 0.0 will use a +predefined value based on the quality. + +@PAR@ node-prop resample.param.kaiser.transition-bandwidth = 0.0 +The kaiser window transition bandwidth parameter. A default value of 0.0 will use a +predefined value based on the quality. + +@PAR@ node-prop resample.param.kaiser.alpha = 0.0 +The kaiser window alpha parameter. A default value of 0.0 will calculate an alpha value +based on the stopband-attenuation and transition-bandwidth parameters. + + ## Channel Mixer Parameters Source, sinks, capture and playback streams can apply channel mixing on the incoming signal.
View file
_service:download_files:pipewire-1.5.83.tar.bz2/doc/dox/internals/protocol.dox -> _service:download_files:pipewire-1.5.84.tar.bz2/doc/dox/internals/protocol.dox
Changed
@@ -1130,6 +1130,8 @@ |<----------------------------------------| | ClientNode::PortSetMixInfo | mixer inputs for each linked port |<----------------------------------------| + | ClientNode::PortSetParam | PeerCapability of the ports + |<----------------------------------------| | ClientNode::PortSetParam | Latency of the ports |<----------------------------------------| | ClientNode::SetActivation | activation of port peers
View file
_service:download_files:pipewire-1.5.83.tar.bz2/meson.build -> _service:download_files:pipewire-1.5.84.tar.bz2/meson.build
Changed
@@ -1,5 +1,5 @@ project('pipewire', 'c' , - version : '1.5.83', + version : '1.5.84', license : 'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' , meson_version : '>= 0.61.1', default_options : 'warning_level=3',
View file
_service:download_files:pipewire-1.5.83.tar.bz2/po/sl.po -> _service:download_files:pipewire-1.5.84.tar.bz2/po/sl.po
Changed
@@ -9,16 +9,16 @@ "Project-Id-Version: PipeWire master\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/-/" "issues\n" -"POT-Creation-Date: 2025-09-11 03:34+0000\n" -"PO-Revision-Date: 2025-09-11 11:47+0200\n" +"POT-Creation-Date: 2025-11-04 03:33+0000\n" +"PO-Revision-Date: 2025-11-08 15:23+0100\n" "Last-Translator: Martin Srebotnjak <miles@filmsi.net>\n" "Language-Team: Slovenian <gnome-si@googlegroups.com>\n" "Language: sl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100>=3 && " -"n%100<=4 ? 2 : 3);\n" +"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100>=3 && n" +"%100<=4 ? 2 : 3);\n" "X-Generator: Poedit 2.2.1\n" #: src/daemon/pipewire.c:29 @@ -57,7 +57,7 @@ msgid "Dummy Output" msgstr "Lažni izhod" -#: src/modules/module-pulse-tunnel.c:760 +#: src/modules/module-pulse-tunnel.c:761 #, c-format msgid "Tunnel for %s@%s" msgstr "Prehod za %s@%s" @@ -76,7 +76,7 @@ msgid "%s on %s" msgstr "%s na %s" -#: src/tools/pw-cat.c:1084 +#: src/tools/pw-cat.c:1096 #, c-format msgid "" "%s options <file>|-\n" @@ -92,7 +92,7 @@ "\n" "</file>\n" -#: src/tools/pw-cat.c:1091 +#: src/tools/pw-cat.c:1103 #, c-format msgid "" " -R, --remote Remote daemon name\n" @@ -129,7 +129,7 @@ " -P --properties Nastavi lastnosti vozlišča\n" "\n" -#: src/tools/pw-cat.c:1109 +#: src/tools/pw-cat.c:1121 #, c-format msgid "" " --rate Sample rate (req. for rec) (default " @@ -167,12 +167,12 @@ " -q --quality Kakovost prevzorčenja (0 - 15) " "(privzeto %d)\n" " -a, --raw neobdelan način (RAW)\n" -" -M, --force-midi Vsili zapis midi, eden izmed " -"\"midi\" ali \"ump\" (privzeto ump)\n" +" -M, --force-midi Vsili zapis midi, eden izmed \"midi" +"\" ali \"ump\" (privzeto ump)\n" " -n, --sample-count ŠTEVEC Ustavi po ŠTEVEC vzorcih\n" "\n" -#: src/tools/pw-cat.c:1129 +#: src/tools/pw-cat.c:1141 msgid "" " -p, --playback Playback mode\n" " -r, --record Recording mode\n" @@ -212,203 +212,203 @@ " -m, --monitor Spremljaj dejavnosti\n" "\n" -#: spa/plugins/alsa/acp/acp.c:351 +#: spa/plugins/alsa/acp/acp.c:361 msgid "Pro Audio" msgstr "Profesionalni zvok" -#: spa/plugins/alsa/acp/acp.c:527 spa/plugins/alsa/acp/alsa-mixer.c:4635 -#: spa/plugins/bluez5/bluez5-device.c:1974 +#: spa/plugins/alsa/acp/acp.c:537 spa/plugins/alsa/acp/alsa-mixer.c:4699 +#: spa/plugins/bluez5/bluez5-device.c:1976 msgid "Off" msgstr "Izklopljeno" -#: spa/plugins/alsa/acp/acp.c:610 +#: spa/plugins/alsa/acp/acp.c:620 #, c-format msgid "%s ALSA UCM error" msgstr "%s napaka ALSA UCM" -#: spa/plugins/alsa/acp/alsa-mixer.c:2652 +#: spa/plugins/alsa/acp/alsa-mixer.c:2721 msgid "Input" msgstr "Vhod" -#: spa/plugins/alsa/acp/alsa-mixer.c:2653 +#: spa/plugins/alsa/acp/alsa-mixer.c:2722 msgid "Docking Station Input" msgstr "Vhod priklopne postaje" -#: spa/plugins/alsa/acp/alsa-mixer.c:2654 +#: spa/plugins/alsa/acp/alsa-mixer.c:2723 msgid "Docking Station Microphone" msgstr "Mikrofon priklopne postaje" -#: spa/plugins/alsa/acp/alsa-mixer.c:2655 +#: spa/plugins/alsa/acp/alsa-mixer.c:2724 msgid "Docking Station Line In" msgstr "Linijski vhod priklopne postaje" -#: spa/plugins/alsa/acp/alsa-mixer.c:2656 -#: spa/plugins/alsa/acp/alsa-mixer.c:2747 +#: spa/plugins/alsa/acp/alsa-mixer.c:2725 +#: spa/plugins/alsa/acp/alsa-mixer.c:2816 msgid "Line In" msgstr "Linijski vhod" -#: spa/plugins/alsa/acp/alsa-mixer.c:2657 -#: spa/plugins/alsa/acp/alsa-mixer.c:2741 -#: spa/plugins/bluez5/bluez5-device.c:2372 +#: spa/plugins/alsa/acp/alsa-mixer.c:2726 +#: spa/plugins/alsa/acp/alsa-mixer.c:2810 +#: spa/plugins/bluez5/bluez5-device.c:2374 msgid "Microphone" msgstr "Mikrofon" -#: spa/plugins/alsa/acp/alsa-mixer.c:2658 -#: spa/plugins/alsa/acp/alsa-mixer.c:2742 +#: spa/plugins/alsa/acp/alsa-mixer.c:2727 +#: spa/plugins/alsa/acp/alsa-mixer.c:2811 msgid "Front Microphone" msgstr "Sprednji mikrofon" -#: spa/plugins/alsa/acp/alsa-mixer.c:2659 -#: spa/plugins/alsa/acp/alsa-mixer.c:2743 +#: spa/plugins/alsa/acp/alsa-mixer.c:2728 +#: spa/plugins/alsa/acp/alsa-mixer.c:2812 msgid "Rear Microphone" msgstr "Zadnji mikrofon" -#: spa/plugins/alsa/acp/alsa-mixer.c:2660 +#: spa/plugins/alsa/acp/alsa-mixer.c:2729 msgid "External Microphone" msgstr "Zunanji mikrofon" -#: spa/plugins/alsa/acp/alsa-mixer.c:2661 -#: spa/plugins/alsa/acp/alsa-mixer.c:2745 +#: spa/plugins/alsa/acp/alsa-mixer.c:2730 +#: spa/plugins/alsa/acp/alsa-mixer.c:2814 msgid "Internal Microphone" msgstr "Notranji mikrofon" -#: spa/plugins/alsa/acp/alsa-mixer.c:2662 -#: spa/plugins/alsa/acp/alsa-mixer.c:2748 +#: spa/plugins/alsa/acp/alsa-mixer.c:2731 +#: spa/plugins/alsa/acp/alsa-mixer.c:2817 msgid "Radio" msgstr "Radio" -#: spa/plugins/alsa/acp/alsa-mixer.c:2663 -#: spa/plugins/alsa/acp/alsa-mixer.c:2749 +#: spa/plugins/alsa/acp/alsa-mixer.c:2732 +#: spa/plugins/alsa/acp/alsa-mixer.c:2818 msgid "Video" msgstr "Video" -#: spa/plugins/alsa/acp/alsa-mixer.c:2664 +#: spa/plugins/alsa/acp/alsa-mixer.c:2733 msgid "Automatic Gain Control" msgstr "Samodejni nadzor ojačanja" -#: spa/plugins/alsa/acp/alsa-mixer.c:2665 +#: spa/plugins/alsa/acp/alsa-mixer.c:2734 msgid "No Automatic Gain Control" msgstr "Brez samodejnega nadzora ojačanja" -#: spa/plugins/alsa/acp/alsa-mixer.c:2666 +#: spa/plugins/alsa/acp/alsa-mixer.c:2735 msgid "Boost" msgstr "Ojačitev" -#: spa/plugins/alsa/acp/alsa-mixer.c:2667 +#: spa/plugins/alsa/acp/alsa-mixer.c:2736 msgid "No Boost" msgstr "Brez ojačitve" -#: spa/plugins/alsa/acp/alsa-mixer.c:2668 +#: spa/plugins/alsa/acp/alsa-mixer.c:2737 msgid "Amplifier" msgstr "Ojačevalnik" -#: spa/plugins/alsa/acp/alsa-mixer.c:2669 +#: spa/plugins/alsa/acp/alsa-mixer.c:2738 msgid "No Amplifier" msgstr "Brez ojačevalnika" -#: spa/plugins/alsa/acp/alsa-mixer.c:2670 +#: spa/plugins/alsa/acp/alsa-mixer.c:2739 msgid "Bass Boost" msgstr "Ojačitev nizkih tonov" -#: spa/plugins/alsa/acp/alsa-mixer.c:2671 +#: spa/plugins/alsa/acp/alsa-mixer.c:2740 msgid "No Bass Boost" msgstr "Brez ojačitve nizkih tonov" -#: spa/plugins/alsa/acp/alsa-mixer.c:2672 -#: spa/plugins/bluez5/bluez5-device.c:2378 +#: spa/plugins/alsa/acp/alsa-mixer.c:2741 +#: spa/plugins/bluez5/bluez5-device.c:2380 msgid "Speaker" msgstr "Zvočnik" #. Don't call it "headset", the HF one has the mic -#: spa/plugins/alsa/acp/alsa-mixer.c:2673 -#: spa/plugins/alsa/acp/alsa-mixer.c:2751 -#: spa/plugins/bluez5/bluez5-device.c:2384 -#: spa/plugins/bluez5/bluez5-device.c:2451 +#: spa/plugins/alsa/acp/alsa-mixer.c:2742 +#: spa/plugins/alsa/acp/alsa-mixer.c:2820 +#: spa/plugins/bluez5/bluez5-device.c:2386 +#: spa/plugins/bluez5/bluez5-device.c:2453 msgid "Headphones" msgstr "Slušalke" -#: spa/plugins/alsa/acp/alsa-mixer.c:2740 +#: spa/plugins/alsa/acp/alsa-mixer.c:2809 msgid "Analog Input" msgstr "Analogni vhod" -#: spa/plugins/alsa/acp/alsa-mixer.c:2744 +#: spa/plugins/alsa/acp/alsa-mixer.c:2813 msgid "Dock Microphone" msgstr "Priklopni mikrofon" -#: spa/plugins/alsa/acp/alsa-mixer.c:2746 +#: spa/plugins/alsa/acp/alsa-mixer.c:2815 msgid "Headset Microphone" msgstr "Mikrofon s slušalkami" -#: spa/plugins/alsa/acp/alsa-mixer.c:2750 +#: spa/plugins/alsa/acp/alsa-mixer.c:2819 msgid "Analog Output" msgstr "Analogni izhod" -#: spa/plugins/alsa/acp/alsa-mixer.c:2752 +#: spa/plugins/alsa/acp/alsa-mixer.c:2821 msgid "Headphones 2" msgstr "Slušalke 2" -#: spa/plugins/alsa/acp/alsa-mixer.c:2753 +#: spa/plugins/alsa/acp/alsa-mixer.c:2822 msgid "Headphones Mono Output" msgstr "Mono izhod slušalk" -#: spa/plugins/alsa/acp/alsa-mixer.c:2754 +#: spa/plugins/alsa/acp/alsa-mixer.c:2823 msgid "Line Out" msgstr "Linijsk izhod" -#: spa/plugins/alsa/acp/alsa-mixer.c:2755 +#: spa/plugins/alsa/acp/alsa-mixer.c:2824 msgid "Analog Mono Output" msgstr "Analogni mono izhod" -#: spa/plugins/alsa/acp/alsa-mixer.c:2756 +#: spa/plugins/alsa/acp/alsa-mixer.c:2825 msgid "Speakers" msgstr "Govorniki" -#: spa/plugins/alsa/acp/alsa-mixer.c:2757 +#: spa/plugins/alsa/acp/alsa-mixer.c:2826 msgid "HDMI / DisplayPort" msgstr "HDMI / DisplayPort" -#: spa/plugins/alsa/acp/alsa-mixer.c:2758 +#: spa/plugins/alsa/acp/alsa-mixer.c:2827 msgid "Digital Output (S/PDIF)" msgstr "Digitalni izhod (S/PDIF)" -#: spa/plugins/alsa/acp/alsa-mixer.c:2759 +#: spa/plugins/alsa/acp/alsa-mixer.c:2828 msgid "Digital Input (S/PDIF)" msgstr "Digitalni vhod (S/PDIF)" -#: spa/plugins/alsa/acp/alsa-mixer.c:2760 +#: spa/plugins/alsa/acp/alsa-mixer.c:2829 msgid "Multichannel Input" msgstr "Večkanalni vhod" -#: spa/plugins/alsa/acp/alsa-mixer.c:2761 +#: spa/plugins/alsa/acp/alsa-mixer.c:2830 msgid "Multichannel Output" msgstr "Večkanalni izhod" -#: spa/plugins/alsa/acp/alsa-mixer.c:2762 +#: spa/plugins/alsa/acp/alsa-mixer.c:2831 msgid "Game Output" msgstr "Vhod igre" -#: spa/plugins/alsa/acp/alsa-mixer.c:2763 -#: spa/plugins/alsa/acp/alsa-mixer.c:2764 +#: spa/plugins/alsa/acp/alsa-mixer.c:2832 +#: spa/plugins/alsa/acp/alsa-mixer.c:2833 msgid "Chat Output" msgstr "Izhod klepeta" -#: spa/plugins/alsa/acp/alsa-mixer.c:2765 +#: spa/plugins/alsa/acp/alsa-mixer.c:2834 msgid "Chat Input" msgstr "Vhod klepeta" -#: spa/plugins/alsa/acp/alsa-mixer.c:2766 +#: spa/plugins/alsa/acp/alsa-mixer.c:2835 msgid "Virtual Surround 7.1" msgstr "Navidezni prostorski zvok 7.1" -#: spa/plugins/alsa/acp/alsa-mixer.c:4458 +#: spa/plugins/alsa/acp/alsa-mixer.c:4522 msgid "Analog Mono" msgstr "Analogni mono" -#: spa/plugins/alsa/acp/alsa-mixer.c:4459 +#: spa/plugins/alsa/acp/alsa-mixer.c:4523 msgid "Analog Mono (Left)" msgstr "Analogni mono (levo)" -#: spa/plugins/alsa/acp/alsa-mixer.c:4460 +#: spa/plugins/alsa/acp/alsa-mixer.c:4524 msgid "Analog Mono (Right)" msgstr "Analogni mono (desno)" @@ -417,142 +417,142 @@ #. * here would lead to the source name to become "Analog Stereo Input #. * Input". The same logic applies to analog-stereo-output, #. * multichannel-input and multichannel-output. -#: spa/plugins/alsa/acp/alsa-mixer.c:4461 -#: spa/plugins/alsa/acp/alsa-mixer.c:4469 -#: spa/plugins/alsa/acp/alsa-mixer.c:4470 +#: spa/plugins/alsa/acp/alsa-mixer.c:4525 +#: spa/plugins/alsa/acp/alsa-mixer.c:4533 +#: spa/plugins/alsa/acp/alsa-mixer.c:4534 msgid "Analog Stereo" msgstr "Analogni stereo" -#: spa/plugins/alsa/acp/alsa-mixer.c:4462 +#: spa/plugins/alsa/acp/alsa-mixer.c:4526 msgid "Mono" msgstr "Mono" -#: spa/plugins/alsa/acp/alsa-mixer.c:4463 +#: spa/plugins/alsa/acp/alsa-mixer.c:4527 msgid "Stereo" msgstr "Stereo" -#: spa/plugins/alsa/acp/alsa-mixer.c:4471 -#: spa/plugins/alsa/acp/alsa-mixer.c:4629 -#: spa/plugins/bluez5/bluez5-device.c:2360 +#: spa/plugins/alsa/acp/alsa-mixer.c:4535 +#: spa/plugins/alsa/acp/alsa-mixer.c:4693 +#: spa/plugins/bluez5/bluez5-device.c:2362 msgid "Headset" msgstr "Slušalka" -#: spa/plugins/alsa/acp/alsa-mixer.c:4472 -#: spa/plugins/alsa/acp/alsa-mixer.c:4630 +#: spa/plugins/alsa/acp/alsa-mixer.c:4536 +#: spa/plugins/alsa/acp/alsa-mixer.c:4694 msgid "Speakerphone" msgstr "Zvočnik telefona" -#: spa/plugins/alsa/acp/alsa-mixer.c:4473 -#: spa/plugins/alsa/acp/alsa-mixer.c:4474 +#: spa/plugins/alsa/acp/alsa-mixer.c:4537 +#: spa/plugins/alsa/acp/alsa-mixer.c:4538 msgid "Multichannel" msgstr "Večkanalno" -#: spa/plugins/alsa/acp/alsa-mixer.c:4475 +#: spa/plugins/alsa/acp/alsa-mixer.c:4539 msgid "Analog Surround 2.1" msgstr "Analogni prostorski zvok 2.1" -#: spa/plugins/alsa/acp/alsa-mixer.c:4476 +#: spa/plugins/alsa/acp/alsa-mixer.c:4540 msgid "Analog Surround 3.0" msgstr "Analogni prostorski zvok 3.0" -#: spa/plugins/alsa/acp/alsa-mixer.c:4477 +#: spa/plugins/alsa/acp/alsa-mixer.c:4541 msgid "Analog Surround 3.1" msgstr "Analogni prostorski zvok 3.1" -#: spa/plugins/alsa/acp/alsa-mixer.c:4478 +#: spa/plugins/alsa/acp/alsa-mixer.c:4542 msgid "Analog Surround 4.0" msgstr "Analogni prostorski zvok 4.0" -#: spa/plugins/alsa/acp/alsa-mixer.c:4479 +#: spa/plugins/alsa/acp/alsa-mixer.c:4543 msgid "Analog Surround 4.1" msgstr "Analogni prostorski zvok 4.1" -#: spa/plugins/alsa/acp/alsa-mixer.c:4480 +#: spa/plugins/alsa/acp/alsa-mixer.c:4544 msgid "Analog Surround 5.0" msgstr "Analogni prostorski zvok 5.0" -#: spa/plugins/alsa/acp/alsa-mixer.c:4481 +#: spa/plugins/alsa/acp/alsa-mixer.c:4545 msgid "Analog Surround 5.1" msgstr "Analogni prostorski zvok 5.1" -#: spa/plugins/alsa/acp/alsa-mixer.c:4482 +#: spa/plugins/alsa/acp/alsa-mixer.c:4546 msgid "Analog Surround 6.0" msgstr "Analogni prostorski zvok 6.0" -#: spa/plugins/alsa/acp/alsa-mixer.c:4483 +#: spa/plugins/alsa/acp/alsa-mixer.c:4547 msgid "Analog Surround 6.1" msgstr "Analogni prostorski zvok 6.1" -#: spa/plugins/alsa/acp/alsa-mixer.c:4484 +#: spa/plugins/alsa/acp/alsa-mixer.c:4548 msgid "Analog Surround 7.0" msgstr "Analogni prostorski zvok 7.0" -#: spa/plugins/alsa/acp/alsa-mixer.c:4485 +#: spa/plugins/alsa/acp/alsa-mixer.c:4549 msgid "Analog Surround 7.1" msgstr "Analogni prostorski zvok 7.1" -#: spa/plugins/alsa/acp/alsa-mixer.c:4486 +#: spa/plugins/alsa/acp/alsa-mixer.c:4550 msgid "Digital Stereo (IEC958)" msgstr "Digitalni stereo (IEC958)" -#: spa/plugins/alsa/acp/alsa-mixer.c:4487 +#: spa/plugins/alsa/acp/alsa-mixer.c:4551 msgid "Digital Surround 4.0 (IEC958/AC3)" msgstr "Digitalni prostorski zvok 4.0 (IEC958/AC3)" -#: spa/plugins/alsa/acp/alsa-mixer.c:4488 +#: spa/plugins/alsa/acp/alsa-mixer.c:4552 msgid "Digital Surround 5.1 (IEC958/AC3)" msgstr "Digitalni prostorski zvok 5.1 (IEC958/AC3)" -#: spa/plugins/alsa/acp/alsa-mixer.c:4489 +#: spa/plugins/alsa/acp/alsa-mixer.c:4553 msgid "Digital Surround 5.1 (IEC958/DTS)" msgstr "Digitalni prostorski zvok 5.1 (IEC958/DTS)" -#: spa/plugins/alsa/acp/alsa-mixer.c:4490 +#: spa/plugins/alsa/acp/alsa-mixer.c:4554 msgid "Digital Stereo (HDMI)" msgstr "Digitalni stereo (HDMI)" -#: spa/plugins/alsa/acp/alsa-mixer.c:4491 +#: spa/plugins/alsa/acp/alsa-mixer.c:4555 msgid "Digital Surround 5.1 (HDMI)" msgstr "Digitalni prostorski zvok 5.1 (HDMI)" -#: spa/plugins/alsa/acp/alsa-mixer.c:4492 +#: spa/plugins/alsa/acp/alsa-mixer.c:4556 msgid "Chat" msgstr "Klepet" -#: spa/plugins/alsa/acp/alsa-mixer.c:4493 +#: spa/plugins/alsa/acp/alsa-mixer.c:4557 msgid "Game" msgstr "Igra" -#: spa/plugins/alsa/acp/alsa-mixer.c:4627 +#: spa/plugins/alsa/acp/alsa-mixer.c:4691 msgid "Analog Mono Duplex" msgstr "Analogni mono dupleks" -#: spa/plugins/alsa/acp/alsa-mixer.c:4628 +#: spa/plugins/alsa/acp/alsa-mixer.c:4692 msgid "Analog Stereo Duplex" msgstr "Analogni stereo dupleks" -#: spa/plugins/alsa/acp/alsa-mixer.c:4631 +#: spa/plugins/alsa/acp/alsa-mixer.c:4695 msgid "Digital Stereo Duplex (IEC958)" msgstr "Digitalni stereo dupleks (IEC958)" -#: spa/plugins/alsa/acp/alsa-mixer.c:4632 +#: spa/plugins/alsa/acp/alsa-mixer.c:4696 msgid "Multichannel Duplex" msgstr "Večkanalni dupleks" -#: spa/plugins/alsa/acp/alsa-mixer.c:4633 +#: spa/plugins/alsa/acp/alsa-mixer.c:4697 msgid "Stereo Duplex" msgstr "Stereo dupleks" -#: spa/plugins/alsa/acp/alsa-mixer.c:4634 +#: spa/plugins/alsa/acp/alsa-mixer.c:4698 msgid "Mono Chat + 7.1 Surround" msgstr "Mono klepet + prostorski zvok 7.1" -#: spa/plugins/alsa/acp/alsa-mixer.c:4735 +#: spa/plugins/alsa/acp/alsa-mixer.c:4799 #, c-format msgid "%s Output" msgstr "Izhod %s" -#: spa/plugins/alsa/acp/alsa-mixer.c:4743 +#: spa/plugins/alsa/acp/alsa-mixer.c:4807 #, c-format msgid "%s Input" msgstr "Vhod %s" @@ -592,13 +592,13 @@ #: spa/plugins/alsa/acp/alsa-util.c:1299 #, c-format msgid "" -"snd_pcm_delay() returned a value that is exceptionally large: %li byte " -"(%s%lu ms).\n" +"snd_pcm_delay() returned a value that is exceptionally large: %li byte (%s" +"%lu ms).\n" "Most likely this is a bug in the ALSA driver '%s'. Please report this issue " "to the ALSA developers." msgid_plural "" -"snd_pcm_delay() returned a value that is exceptionally large: %li bytes " -"(%s%lu ms).\n" +"snd_pcm_delay() returned a value that is exceptionally large: %li bytes (%s" +"%lu ms).\n" "Most likely this is a bug in the ALSA driver '%s'. Please report this issue " "to the ALSA developers." msgstr0 "" @@ -668,7 +668,7 @@ "Najverjetneje je to napaka v gonilniku ALSA »%s«. O tej težavi obvestite " "razvijalce ALSA." -#: spa/plugins/alsa/acp/channelmap.h:457 +#: spa/plugins/alsa/acp/channelmap.h:460 msgid "(invalid)" msgstr "(neveljavno)" @@ -680,100 +680,100 @@ msgid "Modem" msgstr "Modem" -#: spa/plugins/bluez5/bluez5-device.c:1985 +#: spa/plugins/bluez5/bluez5-device.c:1987 msgid "Audio Gateway (A2DP Source & HSP/HFP AG)" msgstr "Zvožni prehod (vir A2DP in HSP/HFP AG)" -#: spa/plugins/bluez5/bluez5-device.c:2014 +#: spa/plugins/bluez5/bluez5-device.c:2016 msgid "Audio Streaming for Hearing Aids (ASHA Sink)" msgstr "Pretakanje zvoka za slušne aparate (ponor ASHA)" -#: spa/plugins/bluez5/bluez5-device.c:2057 +#: spa/plugins/bluez5/bluez5-device.c:2059 #, c-format msgid "High Fidelity Playback (A2DP Sink, codec %s)" msgstr "Predvajanje visoke ločljivosti (ponor A2DP, kodek %s)" -#: spa/plugins/bluez5/bluez5-device.c:2060 +#: spa/plugins/bluez5/bluez5-device.c:2062 #, c-format msgid "High Fidelity Duplex (A2DP Source/Sink, codec %s)" msgstr "Dupleks visoke ločljivosti (vir/ponor A2DP, kodek %s)" -#: spa/plugins/bluez5/bluez5-device.c:2068 +#: spa/plugins/bluez5/bluez5-device.c:2070 msgid "High Fidelity Playback (A2DP Sink)" msgstr "Predvajanje visoke ločljivosti (ponor A2DP)" -#: spa/plugins/bluez5/bluez5-device.c:2070 +#: spa/plugins/bluez5/bluez5-device.c:2072 msgid "High Fidelity Duplex (A2DP Source/Sink)" msgstr "Dupleks visoke ločljivosti (vir/ponor A2DP)" -#: spa/plugins/bluez5/bluez5-device.c:2144 +#: spa/plugins/bluez5/bluez5-device.c:2146 #, c-format msgid "High Fidelity Playback (BAP Sink, codec %s)" msgstr "Predvajanje visoke ločljivosti (ponor BAP, kodek %s)" -#: spa/plugins/bluez5/bluez5-device.c:2149 +#: spa/plugins/bluez5/bluez5-device.c:2151 #, c-format msgid "High Fidelity Input (BAP Source, codec %s)" msgstr "Vhod visoke ločljivosti (vir BAP, kodek %s)" -#: spa/plugins/bluez5/bluez5-device.c:2153 +#: spa/plugins/bluez5/bluez5-device.c:2155 #, c-format msgid "High Fidelity Duplex (BAP Source/Sink, codec %s)" msgstr "Dupleks visoke ločljivosti (vir/ponor BAP, kodek %s)" -#: spa/plugins/bluez5/bluez5-device.c:2162 +#: spa/plugins/bluez5/bluez5-device.c:2164 msgid "High Fidelity Playback (BAP Sink)" msgstr "Predvajanje visoke ločljivosti (ponor BAP)" -#: spa/plugins/bluez5/bluez5-device.c:2166 +#: spa/plugins/bluez5/bluez5-device.c:2168 msgid "High Fidelity Input (BAP Source)" msgstr "Vhod visoke ločljivosti (vir BAP)" -#: spa/plugins/bluez5/bluez5-device.c:2169 +#: spa/plugins/bluez5/bluez5-device.c:2171 msgid "High Fidelity Duplex (BAP Source/Sink)" msgstr "Dupleks visoke ločljivosti (vir/ponor BAP)" -#: spa/plugins/bluez5/bluez5-device.c:2209 +#: spa/plugins/bluez5/bluez5-device.c:2211 #, c-format msgid "Headset Head Unit (HSP/HFP, codec %s)" msgstr "Naglavna enota slušalk (HSP/HFP, kodek %s)" -#: spa/plugins/bluez5/bluez5-device.c:2361 -#: spa/plugins/bluez5/bluez5-device.c:2366 -#: spa/plugins/bluez5/bluez5-device.c:2373 -#: spa/plugins/bluez5/bluez5-device.c:2379 -#: spa/plugins/bluez5/bluez5-device.c:2385 -#: spa/plugins/bluez5/bluez5-device.c:2391 -#: spa/plugins/bluez5/bluez5-device.c:2397 -#: spa/plugins/bluez5/bluez5-device.c:2403 -#: spa/plugins/bluez5/bluez5-device.c:2409 +#: spa/plugins/bluez5/bluez5-device.c:2363 +#: spa/plugins/bluez5/bluez5-device.c:2368 +#: spa/plugins/bluez5/bluez5-device.c:2375 +#: spa/plugins/bluez5/bluez5-device.c:2381 +#: spa/plugins/bluez5/bluez5-device.c:2387 +#: spa/plugins/bluez5/bluez5-device.c:2393 +#: spa/plugins/bluez5/bluez5-device.c:2399 +#: spa/plugins/bluez5/bluez5-device.c:2405 +#: spa/plugins/bluez5/bluez5-device.c:2411 msgid "Handsfree" msgstr "Prostoročno telefoniranje" -#: spa/plugins/bluez5/bluez5-device.c:2367 +#: spa/plugins/bluez5/bluez5-device.c:2369 msgid "Handsfree (HFP)" msgstr "Prostoročno telefoniranje (HFP)" -#: spa/plugins/bluez5/bluez5-device.c:2390 +#: spa/plugins/bluez5/bluez5-device.c:2392 msgid "Portable" msgstr "Prenosna naprava" -#: spa/plugins/bluez5/bluez5-device.c:2396 +#: spa/plugins/bluez5/bluez5-device.c:2398 msgid "Car" msgstr "Avtomobil" -#: spa/plugins/bluez5/bluez5-device.c:2402 +#: spa/plugins/bluez5/bluez5-device.c:2404 msgid "HiFi" msgstr "HiFi" -#: spa/plugins/bluez5/bluez5-device.c:2408 +#: spa/plugins/bluez5/bluez5-device.c:2410 msgid "Phone" msgstr "Telefon" -#: spa/plugins/bluez5/bluez5-device.c:2415 +#: spa/plugins/bluez5/bluez5-device.c:2417 msgid "Bluetooth" msgstr "Bluetooth" -#: spa/plugins/bluez5/bluez5-device.c:2416 -msgid "Bluetooth (HFP)" -msgstr "Bluetooth (HFP)" +#: spa/plugins/bluez5/bluez5-device.c:2418 +msgid "Bluetooth Handsfree" +msgstr "Bluetooth - prostoročno"
View file
_service:download_files:pipewire-1.5.83.tar.bz2/po/zh_CN.po -> _service:download_files:pipewire-1.5.84.tar.bz2/po/zh_CN.po
Changed
@@ -13,8 +13,8 @@ "Project-Id-Version: pipewire.master-tx\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/-/" "issues\n" -"POT-Creation-Date: 2025-11-04 15:35+0000\n" -"PO-Revision-Date: 2025-11-05 07:47+0800\n" +"POT-Creation-Date: 2025-11-25 15:35+0000\n" +"PO-Revision-Date: 2025-11-26 10:19+0800\n" "Last-Translator: lumingzh <lumingzh@qq.com>\n" "Language-Team: Chinese (China) <i18n-zh@googlegroups.com>\n" "Language: zh_CN\n" @@ -79,7 +79,7 @@ msgid "%s on %s" msgstr "%2$s 上的 %1$s" -#: src/tools/pw-cat.c:1096 +#: src/tools/pw-cat.c:1088 #, c-format msgid "" "%s options <file>|-\n" @@ -94,7 +94,7 @@ " -v, --verbose 输出详细操作\n" "\n" -#: src/tools/pw-cat.c:1103 +#: src/tools/pw-cat.c:1095 #, c-format msgid "" " -R, --remote Remote daemon name\n" @@ -126,7 +126,7 @@ " -P --properties 设置节点属性\n" "\n" -#: src/tools/pw-cat.c:1121 +#: src/tools/pw-cat.c:1113 #, c-format msgid "" " --rate Sample rate (req. for rec) (default " @@ -134,8 +134,8 @@ " --channels Number of channels (req. for rec) " "(default %u)\n" " --channel-map Channel map\n" -" one of: \"stereo\", " -"\"surround-51\",... or\n" +" one of: \"Stereo\", \"5.1\",... " +"or\n" " comma separated list of channel " "names: eg. \"FL,FR\"\n" " --format Sample format %s (req. for rec) " @@ -152,9 +152,9 @@ " --rate 采样率 (录制模式需要) (默认 %u)\n" " --channels 通道数 (录制模式需要) (默认 %u)\n" " --channel-map 通道映射\n" -" \"stereo\", \"surround-51\",... " -"中的其一或\n" -" 以\",\"分隔的通道名列表: 如 " +" \"stereo\", \"5.1\",... 中的其一" +"或\n" +" 以英文逗号分隔的通道名列表: 如 " "\"FL,FR\"\n" " --format 采样格式 %s (录制模式需要) (默认 " "%s)\n" @@ -166,7 +166,7 @@ " -n, --sample-count COUNT 计数采样后停止\n" "\n" -#: src/tools/pw-cat.c:1141 +#: src/tools/pw-cat.c:1133 msgid "" " -p, --playback Playback mode\n" " -r, --record Recording mode\n"
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/include/spa/param/audio/dsd-utils.h -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/include/spa/param/audio/dsd-utils.h
Changed
@@ -33,6 +33,8 @@ { struct spa_pod *position = NULL; int res; + uint32_t max_position = SPA_N_ELEMENTS(info->position); + info->flags = 0; res = spa_pod_parse_object(format, SPA_TYPE_OBJECT_Format, NULL, @@ -41,10 +43,13 @@ SPA_FORMAT_AUDIO_rate, SPA_POD_OPT_Int(&info->rate), SPA_FORMAT_AUDIO_channels, SPA_POD_OPT_Int(&info->channels), SPA_FORMAT_AUDIO_position, SPA_POD_OPT_Pod(&position)); + if (info->channels > max_position) + return -ECHRNG; if (position == NULL || - !spa_pod_copy_array(position, SPA_TYPE_Id, info->position, SPA_N_ELEMENTS(info->position))) + spa_pod_copy_array(position, SPA_TYPE_Id, info->position, max_position) != info->channels) { SPA_FLAG_SET(info->flags, SPA_AUDIO_FLAG_UNPOSITIONED); - + spa_memzero(info->position, max_position * sizeof(info->position0)); + } return res; }
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/include/spa/param/audio/raw-utils.h -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/include/spa/param/audio/raw-utils.h
Changed
@@ -48,8 +48,10 @@ if (info->channels > max_position) return -ECHRNG; if (position == NULL || - spa_pod_copy_array(position, SPA_TYPE_Id, info->position, max_position) != info->channels) + spa_pod_copy_array(position, SPA_TYPE_Id, info->position, max_position) != info->channels) { SPA_FLAG_SET(info->flags, SPA_AUDIO_FLAG_UNPOSITIONED); + spa_memzero(info->position, max_position * sizeof(info->position0)); + } return res; }
View file
_service:download_files:pipewire-1.5.84.tar.bz2/spa/include/spa/param/dict-types.h
Added
@@ -0,0 +1,38 @@ +/* Simple Plugin API */ +/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */ +/* SPDX-License-Identifier: MIT */ + +#ifndef SPA_PARAM_DICT_TYPES_H +#define SPA_PARAM_DICT_TYPES_H + +#include <spa/utils/enum-types.h> +#include <spa/param/param-types.h> +#include <spa/param/dict.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#define SPA_TYPE_INFO_PARAM_Dict SPA_TYPE_INFO_PARAM_BASE "Dict" +#define SPA_TYPE_INFO_PARAM_DICT_BASE SPA_TYPE_INFO_PARAM_Dict ":" + +static const struct spa_type_info spa_type_param_dict = { + { SPA_PARAM_DICT_START, SPA_TYPE_Id, SPA_TYPE_INFO_PARAM_DICT_BASE, spa_type_param, }, + { SPA_PARAM_DICT_info, SPA_TYPE_Struct, SPA_TYPE_INFO_PARAM_DICT_BASE "info", NULL, }, + { 0, 0, NULL, NULL }, +}; + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_PARAM_DICT_TYPES_H */
View file
_service:download_files:pipewire-1.5.84.tar.bz2/spa/include/spa/param/dict-utils.h
Added
@@ -0,0 +1,125 @@ +/* Simple Plugin API */ +/* SPDX-FileCopyrightText: Copyright © 2023 Wim Taymans */ +/* SPDX-License-Identifier: MIT */ + +#ifndef SPA_PARAM_DICT_UTILS_H +#define SPA_PARAM_DICT_UTILS_H + +#include <float.h> + +#include <spa/utils/dict.h> +#include <spa/pod/builder.h> +#include <spa/pod/iter.h> +#include <spa/pod/parser.h> +#include <spa/pod/compare.h> +#include <spa/param/dict.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#ifndef SPA_API_DICT_UTILS + #ifdef SPA_API_IMPL + #define SPA_API_DICT_UTILS SPA_API_IMPL + #else + #define SPA_API_DICT_UTILS static inline + #endif +#endif + +SPA_API_DICT_UTILS int +spa_param_dict_compare(const struct spa_pod *a, const struct spa_pod *b) +{ + return spa_pod_memcmp(a, b); +} + +SPA_API_DICT_UTILS struct spa_pod * +spa_param_dict_build_dict(struct spa_pod_builder *builder, uint32_t id, struct spa_dict *dict) +{ + struct spa_pod_frame f2; + uint32_t i, n_items; + + spa_pod_builder_push_object(builder, &f0, SPA_TYPE_OBJECT_ParamDict, id); + + n_items = dict ? dict->n_items : 0; + + spa_pod_builder_prop(builder, SPA_PARAM_DICT_info, SPA_POD_PROP_FLAG_HINT_DICT); + spa_pod_builder_push_struct(builder, &f1); + spa_pod_builder_int(builder, n_items); + for (i = 0; i < n_items; i++) { + spa_pod_builder_string(builder, dict->itemsi.key); + spa_pod_builder_string(builder, dict->itemsi.value); + } + spa_pod_builder_pop(builder, &f1); + + return (struct spa_pod*)spa_pod_builder_pop(builder, &f0); +} + +SPA_API_DICT_UTILS struct spa_pod * +spa_param_dict_build_info(struct spa_pod_builder *builder, uint32_t id, struct spa_param_dict_info *info) +{ + struct spa_pod_frame f; + spa_pod_builder_push_object(builder, &f, SPA_TYPE_OBJECT_ParamDict, id); + spa_pod_builder_add(builder, SPA_PARAM_DICT_info, SPA_POD_PROP_FLAG_HINT_DICT); + spa_pod_builder_primitive(builder, info->info); + return (struct spa_pod*)spa_pod_builder_pop(builder, &f); +} + +SPA_API_DICT_UTILS int +spa_param_dict_parse(const struct spa_pod *dict, struct spa_param_dict_info *info, size_t size) +{ + memset(info, 0, size); + return spa_pod_parse_object(dict, + SPA_TYPE_OBJECT_ParamDict, NULL, + SPA_PARAM_DICT_info, SPA_POD_PodStruct(&info->info)); +} + +SPA_API_DICT_UTILS int +spa_param_dict_info_parse(const struct spa_param_dict_info *info, size_t size, + struct spa_dict *dict, struct spa_dict_item *items) +{ + struct spa_pod_parser prs; + uint32_t n, n_items; + const char *key, *value; + struct spa_pod_frame f1; + + spa_pod_parser_pod(&prs, info->info); + if (spa_pod_parser_push_struct(&prs, &f0) < 0 || + spa_pod_parser_get_int(&prs, (int32_t*)&n_items) < 0) + return -EINVAL; + + if (items == NULL) { + dict->n_items = n_items; + return 0; + } + n_items = SPA_MIN(dict->n_items, n_items); + + for (n = 0; n < n_items; n++) { + if (spa_pod_parser_get(&prs, + SPA_POD_String(&key), + SPA_POD_String(&value), + NULL) < 0) + break; + if (key == NULL || value == NULL) + return -EINVAL; + itemsn.key = key; + itemsn.value = value; + } + dict->items = items; + spa_pod_parser_pop(&prs, &f0); + return 0; +} + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_PARAM_DICT_UTILS_H */
View file
_service:download_files:pipewire-1.5.84.tar.bz2/spa/include/spa/param/dict.h
Added
@@ -0,0 +1,42 @@ +/* Simple Plugin API */ +/* SPDX-FileCopyrightText: Copyright © 2025 Wim Taymans */ +/* SPDX-License-Identifier: MIT */ + +#ifndef SPA_PARAM_DICT_H +#define SPA_PARAM_DICT_H + +#include <spa/param/param.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +/** properties for SPA_TYPE_OBJECT_ParamDict */ +enum spa_param_dict { + SPA_PARAM_DICT_START, + SPA_PARAM_DICT_info, /**< Struct( + * Int: n_items + * (String: key + * String: value)* + * ) */ +}; + +/** helper structure for managing info objects */ +struct spa_param_dict_info { + const struct spa_pod *info; +}; + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_PARAM_DICT_H */
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/include/spa/param/param-types.h -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/include/spa/param/param-types.h
Changed
@@ -41,7 +41,9 @@ { SPA_PARAM_Latency, SPA_TYPE_OBJECT_ParamLatency, SPA_TYPE_INFO_PARAM_ID_BASE "Latency", NULL }, { SPA_PARAM_ProcessLatency, SPA_TYPE_OBJECT_ParamProcessLatency, SPA_TYPE_INFO_PARAM_ID_BASE "ProcessLatency", NULL }, { SPA_PARAM_Tag, SPA_TYPE_OBJECT_ParamTag, SPA_TYPE_INFO_PARAM_ID_BASE "Tag", NULL }, - { SPA_PARAM_PeerFormats, SPA_TYPE_Struct, SPA_TYPE_INFO_PARAM_ID_BASE "PeerFormats", NULL }, + { SPA_PARAM_PeerEnumFormat, SPA_TYPE_OBJECT_PeerParam, SPA_TYPE_INFO_PARAM_ID_BASE "PeerEnumFormat", NULL }, + { SPA_PARAM_Capability, SPA_TYPE_OBJECT_ParamDict, SPA_TYPE_INFO_PARAM_ID_BASE "Capability", NULL }, + { SPA_PARAM_PeerCapability, SPA_TYPE_OBJECT_PeerParam, SPA_TYPE_INFO_PARAM_ID_BASE "PeerCapability", NULL }, { 0, 0, NULL, NULL }, };
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/include/spa/param/param.h -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/include/spa/param/param.h
Changed
@@ -40,7 +40,11 @@ SPA_PARAM_Latency, /**< latency reporting, a SPA_TYPE_OBJECT_ParamLatency */ SPA_PARAM_ProcessLatency, /**< processing latency, a SPA_TYPE_OBJECT_ParamProcessLatency */ SPA_PARAM_Tag, /**< tag reporting, a SPA_TYPE_OBJECT_ParamTag. Since 0.3.79 */ - SPA_PARAM_PeerFormats, /**< peer formats, a SPA_TYPE_Struct of SPA_TYPE_OBJECT_Format. Since 1.5.0 */ + SPA_PARAM_PeerEnumFormat, /**< peer formats, a SPA_TYPE_OBJECT_PeerParam with + * SPA_TYPE_OBJECT_Format. Since 1.5.0 */ + SPA_PARAM_Capability, /**< capability info, a SPA_TYPE_OBJECT_ParamDict, Since 1.5.84 */ + SPA_PARAM_PeerCapability, /**< peer capabilities, a SPA_TYPE_OBJECT_PeerParam with + * SPA_TYPE_OBJECT_ParamDict, since 1.5.84 */ }; /** information about a parameter */
View file
_service:download_files:pipewire-1.5.84.tar.bz2/spa/include/spa/param/peer-types.h
Added
@@ -0,0 +1,38 @@ +/* Simple Plugin API */ +/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */ +/* SPDX-License-Identifier: MIT */ + +#ifndef SPA_PARAM_PEER_TYPES_H +#define SPA_PARAM_PEER_TYPES_H + +#include <spa/utils/enum-types.h> +#include <spa/param/param-types.h> +#include <spa/param/peer.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#define SPA_TYPE_INFO_PeerParam SPA_TYPE_INFO_OBJECT_BASE "PeerParam" +#define SPA_TYPE_INFO_PEER_PARAM_BASE SPA_TYPE_INFO_PeerParam ":" + +static const struct spa_type_info spa_type_peer_param = { + { SPA_PEER_PARAM_START, SPA_TYPE_Id, SPA_TYPE_INFO_PEER_PARAM_BASE, spa_type_param, }, + { SPA_ID_INVALID, SPA_TYPE_Id, SPA_TYPE_INFO_PEER_PARAM_BASE, NULL, }, + { 0, 0, NULL, NULL }, +}; + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_PARAM_PEER_TYPES_H */
View file
_service:download_files:pipewire-1.5.84.tar.bz2/spa/include/spa/param/peer-utils.h
Added
@@ -0,0 +1,92 @@ +/* Simple Plugin API */ +/* SPDX-FileCopyrightText: Copyright © 2023 Wim Taymans */ +/* SPDX-License-Identifier: MIT */ + +#ifndef SPA_PARAM_PEER_PARAM_UTILS_H +#define SPA_PARAM_PEER_PARAM_UTILS_H + +#include <float.h> + +#include <spa/utils/dict.h> +#include <spa/pod/builder.h> +#include <spa/pod/iter.h> +#include <spa/pod/parser.h> +#include <spa/pod/compare.h> +#include <spa/param/peer.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +#ifndef SPA_API_PEER_PARAM_UTILS + #ifdef SPA_API_IMPL + #define SPA_API_PEER_PARAM_UTILS SPA_API_IMPL + #else + #define SPA_API_PEER_PARAM_UTILS static inline + #endif +#endif + +SPA_API_PEER_PARAM_UTILS int +spa_peer_param_parse(const struct spa_pod *param, struct spa_peer_param_info *info, + size_t size, void **state) +{ + int res; + const struct spa_pod_object *obj = (const struct spa_pod_object*)param; + const struct spa_pod_prop *first, *start, *cur; + + if ((res = spa_pod_parse_object(param, + SPA_TYPE_OBJECT_PeerParam, NULL)) < 0) + return res; + + first = spa_pod_prop_first(&obj->body); + start = *state ? spa_pod_prop_next((struct spa_pod_prop*)*state) : first; + + res = 0; + for (cur = start; spa_pod_prop_is_inside(&obj->body, obj->pod.size, cur); + cur = spa_pod_prop_next(cur)) { + info->peer_id = cur->key; + info->param = &cur->value; + *state = (void*)cur; + return 1; + } + return 0; +} + + +SPA_API_PEER_PARAM_UTILS void +spa_peer_param_build_start(struct spa_pod_builder *builder, struct spa_pod_frame *f, uint32_t id) +{ + spa_pod_builder_push_object(builder, f, SPA_TYPE_OBJECT_PeerParam, id); +} + +SPA_API_PEER_PARAM_UTILS void +spa_peer_param_build_add_param(struct spa_pod_builder *builder, uint32_t peer_id, + const struct spa_pod *param) +{ + spa_pod_builder_prop(builder, peer_id, 0); + if (param) + spa_pod_builder_primitive(builder, param); + else + spa_pod_builder_none(builder); +} + +SPA_API_PEER_PARAM_UTILS struct spa_pod * +spa_peer_param_build_end(struct spa_pod_builder *builder, struct spa_pod_frame *f) +{ + return (struct spa_pod*)spa_pod_builder_pop(builder, f); +} + +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_PARAM_PEER_PARAM_UTILS_H */
View file
_service:download_files:pipewire-1.5.84.tar.bz2/spa/include/spa/param/peer.h
Added
@@ -0,0 +1,37 @@ +/* Simple Plugin API */ +/* SPDX-FileCopyrightText: Copyright © 2025 Wim Taymans */ +/* SPDX-License-Identifier: MIT */ + +#ifndef SPA_PARAM_PEER_PARAM_H +#define SPA_PARAM_PEER_PARAM_H + +#include <spa/param/param.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup spa_param + * \{ + */ + +/** properties for SPA_TYPE_OBJECT_PeerParam */ +enum spa_peer_param { + SPA_PEER_PARAM_START, /**< id of peer as key, SPA_TYPE_Pod as value */ + SPA_PEER_PARAM_END = 0xfffffffe, +}; + +struct spa_peer_param_info { + uint32_t peer_id; + const struct spa_pod *param; +}; +/** + * \} + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* SPA_PARAM_PEER_PARAM_H */
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/include/spa/param/tag-utils.h -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/include/spa/param/tag-utils.h
Changed
@@ -11,6 +11,7 @@ #include <spa/pod/builder.h> #include <spa/pod/iter.h> #include <spa/pod/parser.h> +#include <spa/pod/compare.h> #include <spa/param/tag.h> #ifdef __cplusplus @@ -33,8 +34,7 @@ SPA_API_TAG_UTILS int spa_tag_compare(const struct spa_pod *a, const struct spa_pod *b) { - return ((a == b) || (a && b && SPA_POD_SIZE(a) == SPA_POD_SIZE(b) && - memcmp(a, b, SPA_POD_SIZE(b)) == 0)) ? 0 : 1; + return spa_pod_memcmp(a, b); } SPA_API_TAG_UTILS int
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/include/spa/param/type-info.h -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/include/spa/param/type-info.h
Changed
@@ -15,5 +15,7 @@ #include <spa/param/profile-types.h> #include <spa/param/route-types.h> #include <spa/param/tag-types.h> +#include <spa/param/dict-types.h> +#include <spa/param/peer-types.h> #endif /* SPA_PARAM_TYPE_INFO_H */
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/include/spa/pod/compare.h -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/include/spa/pod/compare.h
Changed
@@ -80,6 +80,13 @@ return 0; } +SPA_API_POD_COMPARE int spa_pod_memcmp(const struct spa_pod *a, + const struct spa_pod *b) +{ + return ((a == b) || (a && b && SPA_POD_SIZE(a) == SPA_POD_SIZE(b) && + memcmp(a, b, SPA_POD_SIZE(b)) == 0)) ? 0 : 1; +} + SPA_API_POD_COMPARE int spa_pod_compare(const struct spa_pod *pod1, const struct spa_pod *pod2) { @@ -149,12 +156,8 @@ break; } case SPA_TYPE_Array: - { - if (pod1->size != pod2->size) - return -EINVAL; - res = memcmp(SPA_POD_BODY(pod1), SPA_POD_BODY(pod2), pod2->size); + res = spa_pod_memcmp(pod1, pod2); break; - } default: if (pod1->size != pod2->size) return -EINVAL;
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/include/spa/pod/dynamic.h -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/include/spa/pod/dynamic.h
Changed
@@ -70,8 +70,10 @@ SPA_API_POD_DYNAMIC void spa_pod_dynamic_builder_clean(struct spa_pod_dynamic_builder *builder) { - if (builder->data != builder->b.data) + if (builder->data != builder->b.data) { free(builder->b.data); + builder->b.data = NULL; + } } SPA_DEFINE_AUTO_CLEANUP(spa_pod_dynamic_builder, struct spa_pod_dynamic_builder, {
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/include/spa/pod/filter.h -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/include/spa/pod/filter.h
Changed
@@ -339,9 +339,7 @@ default: if (pf != NULL) { - if (pp->size != pf->size) - return -EINVAL; - if (memcmp(pp, pf, pp->size) != 0) + if (spa_pod_memcmp(pp, pf) != 0) return -EINVAL; do_advance = true; }
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/include/spa/utils/type-info.h -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/include/spa/utils/type-info.h
Changed
@@ -5,6 +5,7 @@ #ifndef SPA_TYPE_INFO_H #define SPA_TYPE_INFO_H + #include <spa/utils/defs.h> #include <spa/utils/type.h> #include <spa/utils/enum-types.h> @@ -78,6 +79,8 @@ { SPA_TYPE_OBJECT_ParamLatency, SPA_TYPE_Object, SPA_TYPE_INFO_PARAM_Latency, spa_type_param_latency }, { SPA_TYPE_OBJECT_ParamProcessLatency, SPA_TYPE_Object, SPA_TYPE_INFO_PARAM_ProcessLatency, spa_type_param_process_latency }, { SPA_TYPE_OBJECT_ParamTag, SPA_TYPE_Object, SPA_TYPE_INFO_PARAM_Tag, spa_type_param_tag }, + { SPA_TYPE_OBJECT_PeerParam, SPA_TYPE_Object, SPA_TYPE_INFO_PeerParam, spa_type_peer_param }, + { SPA_TYPE_OBJECT_ParamDict, SPA_TYPE_Object, SPA_TYPE_INFO_PARAM_Dict, spa_type_param_dict }, { 0, 0, NULL, NULL } };
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/include/spa/utils/type.h -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/include/spa/utils/type.h
Changed
@@ -88,6 +88,8 @@ SPA_TYPE_OBJECT_ParamLatency, SPA_TYPE_OBJECT_ParamProcessLatency, SPA_TYPE_OBJECT_ParamTag, + SPA_TYPE_OBJECT_PeerParam, + SPA_TYPE_OBJECT_ParamDict, _SPA_TYPE_OBJECT_LAST, /**< not part of ABI */ /* vendor extensions */
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/plugins/audioconvert/audioconvert.c -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/plugins/audioconvert/audioconvert.c
Changed
@@ -100,6 +100,7 @@ unsigned int mix_disabled:1; unsigned int resample_disabled:1; unsigned int resample_quality; + struct resample_config resample_config; double rate; char wav_path512; unsigned int lock_volumes:1; @@ -122,6 +123,7 @@ props->mix_disabled = false; props->resample_disabled = false; props->resample_quality = RESAMPLE_DEFAULT_QUALITY; + spa_zero(props->resample_config); props->rate = 1.0; spa_zero(props->wav_path); props->lock_volumes = false; @@ -1019,7 +1021,7 @@ if (this->io_position && this->io_clock && this->io_position->clock.target_rate.denom != this->io_clock->target_rate.denom && !this->props.resample_disabled) { - spa_log_warn(this->log, "driver %d changed rate:%u -> %u", this->io_position->clock.id, + spa_log_debug(this->log, "driver %d changed rate:%u -> %u", this->io_position->clock.id, this->io_clock->target_rate.denom, this->io_position->clock.target_rate.denom); @@ -1478,6 +1480,16 @@ this->props.resample_quality = atoi(s); else if (spa_streq(k, "resample.disable")) this->props.resample_disabled = spa_atob(s); + else if (spa_streq(k, "resample.window")) + this->props.resample_config.window = resample_window_from_label(s); + else if (spa_streq(k, "resample.cutoff")) + spa_atod(s, &this->props.resample_config.cutoff); + else if (spa_streq(k, "resample.n-taps")) + spa_atou32(s, &this->props.resample_config.n_taps, 0); + else if (spa_strstartswith(k, "resample.param.")) { + uint32_t idx = resample_param_from_label(k+strlen("resample.param.")); + spa_atod(s, &this->props.resample_config.paramsidx); + } else if (spa_streq(k, "dither.noise")) spa_atou32(s, &this->dir1.conv.noise_bits, 0); else if (spa_streq(k, "dither.method")) @@ -2289,6 +2301,7 @@ this->resample.o_rate = out->format.info.raw.rate; this->resample.log = this->log; this->resample.quality = this->props.resample_quality; + this->resample.config = this->props.resample_config; this->resample.cpu_flags = this->cpu_flags; this->rate_adjust = this->props.rate != 1.0;
View file
_service:download_files:pipewire-1.5.84.tar.bz2/spa/plugins/audioconvert/dbesi0.c
Added
@@ -0,0 +1,147 @@ +/* Copyright(C) 1996 Takuya OOURA + +You may use, copy, modify this code for any purpose and +without fee. + +Package home: http://www.kurims.kyoto-u.ac.jp/~ooura/bessel.html +*/ + +/* Bessel I_0(x) function in double precision */ + +#include <math.h> + +static double +dbesi0 (double x) +{ + int k; + double w, t, y; + static double a65 = { + 8.5246820682016865877e-11, 2.5966600546497407288e-9, + 7.9689994568640180274e-8, 1.9906710409667748239e-6, + 4.0312469446528002532e-5, 6.4499871606224265421e-4, + 0.0079012345761930579108, 0.071111111109207045212, + 0.444444444444724909, 1.7777777777777532045, + 4.0000000000000011182, 3.99999999999999998, + 1.0000000000000000001, + 1.1520919130377195927e-10, 2.2287613013610985225e-9, + 8.1903951930694585113e-8, 1.9821560631611544984e-6, + 4.0335461940910133184e-5, 6.4495330974432203401e-4, + 0.0079013012611467520626, 0.071111038160875566622, + 0.44444450319062699316, 1.7777777439146450067, + 4.0000000132337935071, 3.9999999968569015366, + 1.0000000003426703174, + 1.5476870780515238488e-10, 1.2685004214732975355e-9, + 9.2776861851114223267e-8, 1.9063070109379044378e-6, + 4.0698004389917945832e-5, 6.4370447244298070713e-4, + 0.0079044749458444976958, 0.071105052411749363882, + 0.44445280640924755082, 1.7777694934432109713, + 4.0000055808824003386, 3.9999977081165740932, + 1.0000004333949319118, + 2.0675200625006793075e-10, -6.1689554705125681442e-10, + 1.2436765915401571654e-7, 1.5830429403520613423e-6, + 4.2947227560776583326e-5, 6.3249861665073441312e-4, + 0.0079454472840953930811, 0.070994327785661860575, + 0.44467219586283000332, 1.7774588182255374745, + 4.0003038986252717972, 3.9998233869142057195, + 1.0000472932961288324, + 2.7475684794982708655e-10, -3.8991472076521332023e-9, + 1.9730170483976049388e-7, 5.9651531561967674521e-7, + 5.1992971474748995357e-5, 5.7327338675433770752e-4, + 0.0082293143836530412024, 0.069990934858728039037, + 0.44726764292723985087, 1.7726685170014087784, + 4.0062907863712704432, 3.9952750700487845355, + 1.0016354346654179322 + }; + static double b70 = { + 6.7852367144945531383e-8, 4.6266061382821826854e-7, + 6.9703135812354071774e-6, 7.6637663462953234134e-5, + 7.9113515222612691636e-4, 0.0073401204731103808981, + 0.060677114958668837046, 0.43994941411651569622, + 2.7420017097661750609, 14.289661921740860534, + 59.820609640320710779, 188.78998681199150629, + 399.8731367825601118, 427.56411572180478514, + 1.8042097874891098754e-7, 1.2277164312044637357e-6, + 1.8484393221474274861e-5, 2.0293995900091309208e-4, + 0.0020918539850246207459, 0.019375315654033949297, + 0.15985869016767185908, 1.1565260527420641724, + 7.1896341224206072113, 37.354773811947484532, + 155.80993164266268457, 489.5211371158540918, + 1030.9147225169564806, 1093.5883545113746958, + 4.8017305613187493564e-7, 3.261317843912380074e-6, + 4.9073137508166159639e-5, 5.3806506676487583755e-4, + 0.0055387918291051866561, 0.051223717488786549025, + 0.42190298621367914765, 3.0463625987357355872, + 18.895299447327733204, 97.915189029455461554, + 407.13940115493494659, 1274.3088990480582632, + 2670.9883037012547506, 2815.7166284662544712, + 1.2789926338424623394e-6, 8.6718263067604918916e-6, + 1.3041508821299929489e-4, 0.001428224737372747892, + 0.014684070635768789378, 0.13561403190404185755, + 1.1152592585977393953, 8.0387088559465389038, + 49.761318895895479206, 257.2684232313529138, + 1066.8543146269566231, 3328.3874581009636362, + 6948.8586598121634874, 7288.4893398212481055, + 3.409350368197032893e-6, 2.3079025203103376076e-5, + 3.4691373283901830239e-4, 0.003794994977222908545, + 0.038974209677945602145, 0.3594948380414878371, + 2.9522878893539528226, 21.246564609514287056, + 131.28727387146173141, 677.38107093296675421, + 2802.3724744545046518, 8718.5731420798254081, + 18141.348781638832286, 18948.925349296308859 + }; + static double c45 = { + 2.5568678676452702768e-15, 3.0393953792305924324e-14, + 6.3343751991094840009e-13, 1.5041298011833009649e-11, + 4.4569436918556541414e-10, 1.746393051427167951e-8, + 1.0059224011079852317e-6, 1.0729838945088577089e-4, + 0.05150322693642527738, + 5.2527963991711562216e-15, 7.202118481421005641e-15, + 7.2561421229904797156e-13, 1.482312146673104251e-11, + 4.4602670450376245434e-10, 1.7463600061788679671e-8, + 1.005922609132234756e-6, 1.0729838937545111487e-4, + 0.051503226936437300716, + 1.3365917359358069908e-14, -1.2932643065888544835e-13, + 1.7450199447905602915e-12, 1.0419051209056979788e-11, + 4.58047881980598326e-10, 1.7442405450073548966e-8, + 1.0059461453281292278e-6, 1.0729837434500161228e-4, + 0.051503226940658446941, + 5.3771611477352308649e-14, -1.1396193006413731702e-12, + 1.2858641335221653409e-11, -5.9802086004570057703e-11, + 7.3666894305929510222e-10, 1.6731837150730356448e-8, + 1.0070831435812128922e-6, 1.0729733111203704813e-4, + 0.051503227360726294675, + 3.7819492084858931093e-14, -4.8600496888588034879e-13, + 1.6898350504817224909e-12, 4.5884624327524255865e-11, + 1.2521615963377513729e-10, 1.8959658437754727957e-8, + 1.0020716710561353622e-6, 1.073037119856927559e-4, + 0.05150322383300230775 + }; + + w = fabs (x); + if (w < 8.5) { + t = w * w * 0.0625; + k = 13 * ((int) t); + y = (((((((((((ak * t + ak + 1) * t + + ak + 2) * t + ak + 3) * t + + ak + 4) * t + ak + 5) * t + ak + + 6) * t + ak + 7) * t + ak + 8) * t + ak + + 9) * t + ak + 10) * t + ak + 11) * t + ak + 12; + } else if (w < 12.5) { + k = (int) w; + t = w - k; + k = 14 * (k - 8); + y = ((((((((((((bk * t + bk + 1) * t + bk + 2) * t + bk + 3) * t + + bk + 4) * t + bk + 5) * t + bk + + 6) * t + bk + 7) * t + bk + 8) * t + + bk + 9) * t + bk + 10) * t + bk + 11) * t + bk + + 12) * t + bk + 13; + } else { + t = 60 / w; + k = 9 * ((int) t); + y = ((((((((ck * t + ck + 1) * t + + ck + 2) * t + ck + 3) * t + ck + 4) * t + + ck + 5) * t + ck + 6) * t + ck + 7) * t + + ck + 8) * sqrt (t) * exp (w); + } + return y; +}
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/plugins/audioconvert/resample-native.c -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/plugins/audioconvert/resample-native.c
Changed
@@ -13,72 +13,186 @@ SPA_LOG_TOPIC_DEFINE(resample_log_topic, "spa.resample"); +#define INHERIT_PARAM(c,q,p) if ((c)->paramsp == 0.0) (c)->paramsp = (q)->paramsp; + struct quality { uint32_t n_taps; - double cutoff; + double cutoff_up; /* when upsampling */ + double cutoff_down; /* for downsampling */ + double paramsRESAMPLE_MAX_PARAMS; }; -static const struct quality window_qualities = { - { 8, 0.53, }, - { 16, 0.67, }, - { 24, 0.75, }, - { 32, 0.80, }, - { 48, 0.85, }, /* default */ - { 64, 0.88, }, - { 80, 0.895, }, - { 96, 0.910, }, - { 128, 0.936, }, - { 144, 0.945, }, - { 160, 0.950, }, - { 192, 0.960, }, - { 256, 0.970, }, - { 896, 0.990, }, - { 1024, 0.995, }, + +struct window_info { + uint32_t window; + void (*func) (struct resample *r, double *w, double t, uint32_t n_taps); + uint32_t n_qualities; + const struct quality *qualities; + void (*config) (struct resample *r); +}; +struct window_info window_info; + +static const struct quality blackman_qualities = { + { 8, 0.58, 0.58, { 0.16, }}, + { 16, 0.70, 0.70, { 0.20, }}, + { 24, 0.77, 0.77, { 0.16, }}, + { 32, 0.82, 0.82, { 0.16, }}, + { 48, 0.87, 0.87, { 0.16, }}, /* default */ + { 64, 0.895, 0.895, { 0.16, }}, + { 80, 0.910, 0.910, { 0.16, }}, + { 96, 0.925, 0.925, { 0.16, }}, + { 128, 0.942, 0.942, { 0.16, }}, + { 144, 0.950, 0.950, { 0.16, }}, + { 160, 0.958, 0.958, { 0.16, }}, + { 192, 0.966, 0.966, { 0.16, }}, + { 256, 0.975, 0.975, { 0.16, }}, + { 896, 0.988, 0.988, { 0.16, }}, + { 1024, 0.990, 0.990, { 0.16, }}, }; -static inline double sinc(double x) +static inline void blackman_window(struct resample *r, double *w, double t, uint32_t n_taps) { - if (x < 1e-6) return 1.0; - x *= M_PI; - return sin(x) / x; + double x, alpha = r->config.paramsRESAMPLE_PARAM_BLACKMAN_ALPHA; + uint32_t i, n_taps12 = n_taps/2; + for (i = 0; i < n_taps12; i++, t += 1.0) { + x = 2.0 * M_PI * t / n_taps; + wi = (1.0 - alpha) / 2.0 + (1.0 / 2.0) * cos(x) + + (alpha / 2.0) * cos(2.0 * x); + } +} +static inline void blackman_config(struct resample *r) +{ + const struct quality *q = &window_infor->config.window.qualitiesr->quality; + INHERIT_PARAM(&r->config, q, RESAMPLE_PARAM_BLACKMAN_ALPHA); } -static inline double window_blackman(double x, double n_taps) +static const struct quality exp_qualities = { + { 8, 0.58, 0.58, { 16.97789, }}, + { 16, 0.70, 0.70, { 16.97789, }}, + { 24, 0.77, 0.77, { 16.97789, }}, + { 32, 0.82, 0.82, { 16.97789, }}, + { 48, 0.87, 0.87, { 16.97789, }}, /* default */ + { 64, 0.895, 0.895, { 16.97789, }}, + { 80, 0.910, 0.910, { 16.97789, }}, + { 96, 0.925, 0.925, { 16.97789, }}, + { 128, 0.942, 0.942, { 16.97789, }}, + { 144, 0.950, 0.950, { 16.97789, }}, + { 160, 0.958, 0.958, { 16.97789, }}, + { 192, 0.966, 0.966, { 16.97789, }}, + { 256, 0.975, 0.975, { 16.97789, }}, + { 896, 0.988, 0.988, { 16.97789, }}, + { 1024, 0.990, 0.990, { 16.97789, }}, +}; + +static inline void exp_window(struct resample *r, double *w, double t, uint32_t n_taps) { - double alpha = 0.232, r; - x = 2.0 * M_PI * x / n_taps; - r = (1.0 - alpha) / 2.0 + (1.0 / 2.0) * cos(x) + - (alpha / 2.0) * cos(2.0 * x); - return r; + double x, A = r->config.paramsRESAMPLE_PARAM_EXP_A; + uint32_t i, n_taps12 = n_taps/2; + + for (i = 0; i < n_taps12; i++, t += 1.0) { + x = 2.0 * t / n_taps; + /* doi:10.1109/RME.2008.4595727 with tweak */ + wi = (exp(A * sqrt(fmax(0.0, 1.0 - x*x))) - 1) / (exp(A) - 1); + } } +static inline void exp_config(struct resample *r) +{ + const struct quality *q = &window_infor->config.window.qualitiesr->quality; + INHERIT_PARAM(&r->config, q, RESAMPLE_PARAM_EXP_A); +} + +#include "dbesi0.c" + +static const struct quality kaiser_qualities = { + { 8, 0.620000, 0.620000, { 3.553376, 110.000000, 0.888064 }}, + { 16, 0.780000, 0.780000, { 3.553376, 110.000000, 0.444032 }}, + { 24, 0.820000, 0.820000, { 3.904154, 120.000000, 0.325043 }}, + { 32, 0.865000, 0.865000, { 4.254931, 130.000000, 0.265548 }}, + { 48, 0.895000, 0.895000, { 4.254931, 130.000000, 0.177032 }}, + { 64, 0.915000, 0.915000, { 4.254931, 130.000000, 0.132774 }}, + { 80, 0.928000, 0.928000, { 4.254931, 130.000000, 0.106219 }}, + { 96, 0.942000, 0.942000, { 4.254931, 130.000000, 0.088516 }}, + { 128, 0.952000, 0.952000, { 4.254931, 130.000000, 0.066387 }}, + { 160, 0.960000, 0.960000, { 4.254931, 130.000000, 0.053110 }}, + { 192, 0.968000, 0.968000, { 4.254931, 130.000000, 0.044258 }}, + { 256, 0.976000, 0.976000, { 4.605709, 140.000000, 0.035914 }}, + { 512, 0.985000, 0.985000, { 4.781097, 145.000000, 0.018637 }}, + { 768, 0.990000, 0.990000, { 4.956486, 150.000000, 0.012878 }}, + { 1024, 0.993000, 0.993000, { 5.131875, 155.000000, 0.009999 }}, +}; -static inline double window_cosh(double x, double n_taps) +static inline void kaiser_window(struct resample *r, double *w, double t, uint32_t n_taps) { - double r; - double A = 16.97789; - double x2; - x = 2.0 * x / n_taps; - x2 = x * x; - if (x2 >= 1.0) - return 0.0; - /* doi:10.1109/RME.2008.4595727 with tweak */ - r = (exp(A * sqrt(1 - x2)) - 1) / (exp(A) - 1); - return r; + double x, beta = r->config.paramsRESAMPLE_PARAM_KAISER_ALPHA * M_PI; + double den = dbesi0(beta); + uint32_t i, n_taps12 = n_taps/2; + for (i = 0; i < n_taps12; i++, t += 1.0) { + x = 2.0 * t / n_taps; + wi = dbesi0(beta * sqrt(fmax(0.0, 1.0 - x*x))) / den; + } } -#define window (1 ? window_cosh : window_blackman) +static inline void kaiser_config(struct resample *r) +{ + double A, B, dw, tr_bw, alpha; + uint32_t n; + const struct quality *q = &window_infor->config.window.qualitiesr->quality; + + if ((A = r->config.paramsRESAMPLE_PARAM_KAISER_SB_ATT) == 0.0) + A = q->paramsRESAMPLE_PARAM_KAISER_SB_ATT; + if ((tr_bw = r->config.paramsRESAMPLE_PARAM_KAISER_TR_BW) == 0.0) + tr_bw = q->paramsRESAMPLE_PARAM_KAISER_TR_BW; + + if ((alpha = r->config.paramsRESAMPLE_PARAM_KAISER_ALPHA) == 0.0) { + /* calculate Beta and alpha */ + if (A > 50) + B = 0.1102 * (A - 8.7); + else if (A >= 21) + B = 0.5842 * pow (A - 21, 0.4) + 0.07886 * (A - 21); + else + B = 0.0; + + r->config.paramsRESAMPLE_PARAM_KAISER_ALPHA = B / M_PI; + } + if (r->config.n_taps == 0) { + /* calculate transition width in radians */ + dw = 2 * M_PI * (tr_bw); + /* order of the filter */ + n = (uint32_t)((A - 8.0) / (2.285 * dw)); + r->config.n_taps = n + 1; + } +} + +struct window_info window_info = { + RESAMPLE_WINDOW_EXP = { RESAMPLE_WINDOW_EXP, exp_window, + SPA_N_ELEMENTS(exp_qualities), exp_qualities, exp_config }, + RESAMPLE_WINDOW_BLACKMAN = { RESAMPLE_WINDOW_BLACKMAN, blackman_window, + SPA_N_ELEMENTS(blackman_qualities), blackman_qualities, blackman_config }, + RESAMPLE_WINDOW_KAISER = { RESAMPLE_WINDOW_KAISER, kaiser_window, + SPA_N_ELEMENTS(kaiser_qualities), kaiser_qualities, kaiser_config }, +}; + +static inline double sinc(double x, double cutoff) +{ + if (x < 1e-6) return cutoff; + x *= M_PI; + return sin(x * cutoff) / x; +} -static int build_filter(float *taps, uint32_t stride, uint32_t n_taps, uint32_t n_phases, double cutoff) +static int build_filter(struct resample *r, float *taps, uint32_t stride, uint32_t n_taps, + uint32_t n_phases, double cutoff) { uint32_t i, j, n_taps12 = n_taps/2; + double windown_taps12+1; for (i = 0; i <= n_phases; i++) { double t = (double) i / (double) n_phases; + window_infor->config.window.func(r, window, t, n_taps); for (j = 0; j < n_taps12; j++, t += 1.0) { /* exploit symmetry in filter taps */ taps(n_phases - i) * stride + n_taps12 + j = tapsi * stride + (n_taps12 - j - 1) = (float) - (cutoff * sinc(t * cutoff) * window(t, n_taps)); + (sinc(t, cutoff) * windowj); } } return 0; @@ -352,11 +466,18 @@ { struct native_data *d; const struct quality *q; - double scale; - uint32_t c, n_taps, n_phases, filter_size, in_rate, out_rate, gcd, filter_stride; + double scale, cutoff; + uint32_t i, n_taps, n_phases, filter_size, in_rate, out_rate, gcd, filter_stride; uint32_t history_stride, history_size, oversample; + struct resample_config *c = &r->config; +#ifndef RESAMPLE_DISABLE_PRECOMP + struct resample_config def = { 0 }; + bool default_config; - r->quality = SPA_CLAMP(r->quality, 0, (int) SPA_N_ELEMENTS(window_qualities) - 1); + default_config = memcmp(c, &def, sizeof(def)) == 0; +#endif + c->window = SPA_CLAMP(c->window, 0u, SPA_N_ELEMENTS(window_info)-1); + r->quality = SPA_CLAMP(r->quality, 0, (int)(window_infoc->window.n_qualities - 1)); r->free = impl_native_free; r->update_rate = impl_native_update_rate; r->in_len = impl_native_in_len; @@ -366,17 +487,22 @@ r->delay = impl_native_delay; r->phase = impl_native_phase; - q = &window_qualitiesr->quality; + window_infoc->window.config(r); + + q = &window_infoc->window.qualitiesr->quality; + cutoff = r->o_rate < r->i_rate ? q->cutoff_down : q->cutoff_up; + c->cutoff = c->cutoff <= 0.0 ? cutoff: c->cutoff; + n_taps = c->n_taps == 0 ? q->n_taps : c->n_taps; gcd = calc_gcd(r->i_rate, r->o_rate); in_rate = r->i_rate / gcd; out_rate = r->o_rate / gcd; - scale = SPA_MIN(q->cutoff * out_rate / in_rate, q->cutoff); + scale = SPA_MIN(c->cutoff * out_rate / in_rate, c->cutoff); /* multiple of 8 taps to ease simd optimizations */ - n_taps = SPA_ROUND_UP_N((uint32_t)ceil(q->n_taps / scale), 8); + n_taps = SPA_ROUND_UP_N((uint32_t)ceil(n_taps / scale), 8); n_taps = SPA_MIN(n_taps, 1u << 18); /* try to get at least 256 phases so that interpolation is @@ -400,7 +526,7 @@ return -errno; r->data = d; - d->n_taps = n_taps; + c->n_taps = d->n_taps = n_taps; d->n_phases = n_phases; d->in_rate = UINT32_TO_FIXP(in_rate); d->out_rate = out_rate; @@ -411,25 +537,26 @@ d->history = SPA_PTROFF(d->hist_mem, history_size, float*); d->filter_stride = filter_stride / sizeof(float); d->filter_stride_os = d->filter_stride * oversample; - for (c = 0; c < r->channels; c++) - d->historyc = SPA_PTROFF(d->hist_mem, c * history_stride, float); + for (i = 0; i < r->channels; i++) + d->historyi = SPA_PTROFF(d->hist_mem, i * history_stride, float); #ifndef RESAMPLE_DISABLE_PRECOMP /* See if we have precomputed coefficients */ - for (c = 0; precomp_coeffsc.filter; c++) { - if (precomp_coeffsc.in_rate == r->i_rate && - precomp_coeffsc.out_rate == r->o_rate && - precomp_coeffsc.quality == r->quality) + for (i = 0; precomp_coeffsi.filter; i++) { + if (default_config && + precomp_coeffsi.in_rate == r->i_rate && + precomp_coeffsi.out_rate == r->o_rate && + precomp_coeffsi.quality == r->quality) break; } - if (precomp_coeffsc.filter) { - spa_log_debug(r->log, "using precomputed filter for %u->%u(%u)", + if (precomp_coeffsi.filter) { + spa_log_info(r->log, "using precomputed filter for %u->%u(%u)", r->i_rate, r->o_rate, r->quality); - spa_memcpy(d->filter, precomp_coeffsc.filter, filter_size); + spa_memcpy(d->filter, precomp_coeffsi.filter, filter_size); } else { #endif - build_filter(d->filter, d->filter_stride, n_taps, n_phases, scale); + build_filter(r, d->filter, d->filter_stride, n_taps, n_phases, scale); #ifndef RESAMPLE_DISABLE_PRECOMP } #endif @@ -440,8 +567,8 @@ return -ENOTSUP; } - spa_log_debug(r->log, "native %p: q:%d in:%d out:%d gcd:%d n_taps:%d n_phases:%d features:%08x:%08x", - r, r->quality, r->i_rate, r->o_rate, gcd, n_taps, n_phases, + spa_log_info(r->log, "native %p: c:%f q:%d w:%d in:%d out:%d gcd:%d n_taps:%d n_phases:%d features:%08x:%08x", + r, c->cutoff, r->quality, c->window, r->i_rate, r->o_rate, gcd, n_taps, n_phases, r->cpu_flags, d->info->cpu_flags); r->cpu_flags = d->info->cpu_flags;
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/plugins/audioconvert/resample.h -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/plugins/audioconvert/resample.h
Changed
@@ -9,6 +9,26 @@ #include <spa/support/log.h> #define RESAMPLE_DEFAULT_QUALITY 4 +#define RESAMPLE_WINDOW_DEFAULT RESAMPLE_WINDOW_EXP +#define RESAMPLE_MAX_PARAMS 16 + +struct resample_config { +#define RESAMPLE_WINDOW_EXP 0 +#define RESAMPLE_WINDOW_BLACKMAN 1 +#define RESAMPLE_WINDOW_KAISER 2 + uint32_t window; + + double cutoff; + uint32_t n_taps; + +#define RESAMPLE_PARAM_EXP_A 0 +#define RESAMPLE_PARAM_BLACKMAN_ALPHA 0 +#define RESAMPLE_PARAM_KAISER_ALPHA 0 +#define RESAMPLE_PARAM_KAISER_SB_ATT 1 /* stopband attenuation */ +#define RESAMPLE_PARAM_KAISER_TR_BW 2 /* transition bandwidth */ +#define RESAMPLE_PARAM_INVALID (RESAMPLE_MAX_PARAMS-1) + double paramsRESAMPLE_MAX_PARAMS; +}; struct resample { struct spa_log *log; @@ -23,6 +43,8 @@ double rate; int quality; + struct resample_config config; /* set to all 0 for defaults */ + void (*free) (struct resample *r); void (*update_rate) (struct resample *r, double rate); uint32_t (*in_len) (struct resample *r, uint32_t out_len); @@ -49,6 +71,56 @@ #define resample_phase(r) (r)->phase(r) int resample_native_init(struct resample *r); +int resample_native_init_config(struct resample *r, struct resample_config *conf); int resample_peaks_init(struct resample *r); +static const struct resample_window_info { + uint32_t window; + const char *label; + const char *description; + uint32_t n_params; +} resample_window_info = { + RESAMPLE_WINDOW_EXP = { RESAMPLE_WINDOW_EXP, + "exp", "Exponential window", 1 }, + RESAMPLE_WINDOW_BLACKMAN = { RESAMPLE_WINDOW_BLACKMAN, + "blackman", "Blackman window", 1 }, + RESAMPLE_WINDOW_KAISER = { RESAMPLE_WINDOW_KAISER, + "kaiser", "Kaiser window", 3 }, +}; + +static inline uint32_t resample_window_from_label(const char *label) +{ + SPA_FOR_EACH_ELEMENT_VAR(resample_window_info, i) { + if (spa_streq(i->label, label)) + return i->window; + } + return RESAMPLE_WINDOW_EXP; +} + +static inline const char *resample_window_name(uint32_t idx) +{ + return resample_window_infoSPA_CLAMP(idx, 0u, SPA_N_ELEMENTS(resample_window_info)-1).label; +} + +static const struct resample_param_info { + uint32_t window; + uint32_t idx; + const char *label; +} resample_param_info = { + { RESAMPLE_WINDOW_EXP, RESAMPLE_PARAM_EXP_A, "exp.A" }, + { RESAMPLE_WINDOW_BLACKMAN, RESAMPLE_PARAM_BLACKMAN_ALPHA, "blackman.alpha" }, + { RESAMPLE_WINDOW_KAISER, RESAMPLE_PARAM_KAISER_ALPHA, "kaiser.alpha" }, + { RESAMPLE_WINDOW_KAISER, RESAMPLE_PARAM_KAISER_SB_ATT, "kaiser.stopband-attenuation" }, + { RESAMPLE_WINDOW_KAISER, RESAMPLE_PARAM_KAISER_TR_BW, "kaiser.transition-bandwidth" }, +}; + +static inline uint32_t resample_param_from_label(const char *label) +{ + SPA_FOR_EACH_ELEMENT_VAR(resample_param_info, i) { + if (spa_streq(i->label, label)) + return i->idx; + } + return RESAMPLE_PARAM_INVALID; +} + #endif /* RESAMPLE_H */
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/plugins/audioconvert/spa-resample.c -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/plugins/audioconvert/spa-resample.c
Changed
@@ -29,7 +29,9 @@ bool verbose; int rate; int format; + uint32_t window; int quality; + struct resample_config config; int cpu_flags; const char *iname; @@ -43,15 +45,19 @@ #define STR_FMTS "(s8|s16|s32|f32|f64)" -#define OPTIONS "hvr:f:q:c:" +#define OPTIONS "hvc:r:f:w:q:u:t:p:" static const struct option long_options = { { "help", no_argument, NULL, 'h'}, { "verbose", no_argument, NULL, 'v'}, + { "cpuflags", required_argument, NULL, 'c' }, { "rate", required_argument, NULL, 'r' }, { "format", required_argument, NULL, 'f' }, + { "window", required_argument, NULL, 'w' }, { "quality", required_argument, NULL, 'q' }, - { "cpuflags", required_argument, NULL, 'c' }, + { "cutoff", required_argument, NULL, 'u' }, + { "taps", required_argument, NULL, 't' }, + { "param", required_argument, NULL, 'p' }, { NULL, 0, NULL, 0 } }; @@ -59,6 +65,7 @@ static void show_usage(const char *name, bool is_error) { FILE *fp; + uint32_t i; fp = is_error ? stderr : stdout; @@ -66,14 +73,31 @@ fprintf(fp, " -h, --help Show this help\n" " -v --verbose Be verbose\n" + " -c --cpuflags CPU flags (default 0)\n" "\n"); fprintf(fp, " -r --rate Output sample rate (default as input)\n" - " -f --format Output sample format %s (default as input)\n" + " -f --format Output sample format %s (default as input)\n\n" + " -w --window Window function (default %s)\n", + STR_FMTS, resample_window_name(RESAMPLE_WINDOW_DEFAULT)); + for (i = 0; i < SPA_N_ELEMENTS(resample_window_info); i++) { + fprintf(fp, + " %s: %s\n", + resample_window_infoi.label, + resample_window_infoi.description); + } + fprintf(fp, " -q --quality Resampler quality (default %u)\n" - " -c --cpuflags CPU flags (default 0)\n" - "\n", - STR_FMTS, DEFAULT_QUALITY); + " -u --cutoff Cutoff frequency 0.0..1.0 (default from quality)\n" + " -t --taps Resampler taps (default from quality)\n" + " -p --param Resampler param <name>=<value> (default from quality)\n", + DEFAULT_QUALITY); + for (i = 0; i < SPA_N_ELEMENTS(resample_param_info); i++) { + fprintf(fp, + " %s\n", + resample_param_infoi.label); + } + fprintf(fp, "\n"); } static inline const char * @@ -207,10 +231,23 @@ r.i_rate = d->iinfo.samplerate; r.o_rate = d->oinfo.samplerate; r.quality = d->quality < 0 ? DEFAULT_QUALITY : d->quality; + r.config = d->config; if ((res = resample_native_init(&r)) < 0) { fprintf(stderr, "can't init converter: %s\n", spa_strerror(res)); return res; } + if (d->verbose) { + fprintf(stdout, "window:%s cutoff:%f n_taps:%u\n", + resample_window_name(r.config.window), + r.config.cutoff, r.config.n_taps); + for (i = 0; i < SPA_N_ELEMENTS(resample_param_info); i++) { + if (resample_param_infoi.window != r.config.window) + continue; + fprintf(stdout, " param:%s %f\n", + resample_param_infoi.label, + r.config.paramsresample_param_infoi.idx); + } + } for (j = 0; j < channels; j++) srcj = &inMAX_SAMPLES * j; @@ -320,6 +357,27 @@ case 'c': data.cpu_flags = strtol(optarg, NULL, 0); break; + case 'u': + data.config.cutoff = strtod(optarg, NULL); + fprintf(stderr, "%f\n", data.config.cutoff); + break; + case 'w': + data.config.window = resample_window_from_label(optarg); + break; + case 'p': + { + char *eq; + if ((eq = strchr(optarg, '=')) != NULL) { + uint32_t idx; + *eq = 0; + idx = resample_param_from_label(optarg); + data.config.paramsidx = atof(eq+1); + } + break; + } + case 't': + data.config.n_taps = atoi(optarg); + break; default: fprintf(stderr, "error: unknown option '%c'\n", c); goto error_usage;
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/plugins/bluez5/a2dp-codec-aac.c -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/plugins/bluez5/a2dp-codec-aac.c
Changed
@@ -139,7 +139,8 @@ static int codec_select_config(const struct media_codec *codec, uint32_t flags, const void *caps, size_t caps_size, const struct media_codec_audio_info *info, - const struct spa_dict *settings, uint8_t configA2DP_MAX_CAPS_SIZE) + const struct spa_dict *settings, uint8_t configA2DP_MAX_CAPS_SIZE, + void **config_data) { a2dp_aac_t conf; int i;
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/plugins/bluez5/a2dp-codec-aptx.c -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/plugins/bluez5/a2dp-codec-aptx.c
Changed
@@ -110,7 +110,8 @@ static int codec_select_config(const struct media_codec *codec, uint32_t flags, const void *caps, size_t caps_size, const struct media_codec_audio_info *info, - const struct spa_dict *settings, uint8_t configA2DP_MAX_CAPS_SIZE) + const struct spa_dict *settings, uint8_t configA2DP_MAX_CAPS_SIZE, + void **config_data) { a2dp_aptx_t conf; int i; @@ -146,7 +147,8 @@ static int codec_select_config_ll(const struct media_codec *codec, uint32_t flags, const void *caps, size_t caps_size, const struct media_codec_audio_info *info, - const struct spa_dict *settings, uint8_t configA2DP_MAX_CAPS_SIZE) + const struct spa_dict *settings, uint8_t configA2DP_MAX_CAPS_SIZE, + void **config_data) { a2dp_aptx_ll_ext_t conf = { 0 }; size_t actual_conf_size; @@ -166,7 +168,7 @@ if (codec->duplex_codec && !conf.base.bidirect_link) return -ENOTSUP; - if ((res = codec_select_config(codec, flags, caps, caps_size, info, settings, config)) < 0) + if ((res = codec_select_config(codec, flags, caps, caps_size, info, settings, config, NULL)) < 0) return res; memcpy(&conf.base.aptx, config, sizeof(conf.base.aptx));
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/plugins/bluez5/a2dp-codec-faststream.c -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/plugins/bluez5/a2dp-codec-faststream.c
Changed
@@ -61,7 +61,8 @@ static int codec_select_config(const struct media_codec *codec, uint32_t flags, const void *caps, size_t caps_size, const struct media_codec_audio_info *info, - const struct spa_dict *settings, uint8_t configA2DP_MAX_CAPS_SIZE) + const struct spa_dict *settings, uint8_t configA2DP_MAX_CAPS_SIZE, + void **config_data) { a2dp_faststream_t conf; int i;
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/plugins/bluez5/a2dp-codec-lc3plus.c -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/plugins/bluez5/a2dp-codec-lc3plus.c
Changed
@@ -83,7 +83,8 @@ static int codec_select_config(const struct media_codec *codec, uint32_t flags, const void *caps, size_t caps_size, const struct media_codec_audio_info *info, - const struct spa_dict *settings, uint8_t configA2DP_MAX_CAPS_SIZE) + const struct spa_dict *settings, uint8_t configA2DP_MAX_CAPS_SIZE, + void **config_data) { a2dp_lc3plus_hr_t conf; @@ -137,8 +138,8 @@ int a, b; /* Order selected configurations by preference */ - res1 = codec->select_config(codec, 0, caps1, caps1_size, info, NULL, (uint8_t *)&conf1); - res2 = codec->select_config(codec, 0, caps2, caps2_size, info , NULL, (uint8_t *)&conf2); + res1 = codec->select_config(codec, 0, caps1, caps1_size, info, NULL, (uint8_t *)&conf1, NULL); + res2 = codec->select_config(codec, 0, caps2, caps2_size, info , NULL, (uint8_t *)&conf2, NULL); #define PREFER_EXPR(expr) \ do { \
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/plugins/bluez5/a2dp-codec-ldac.c -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/plugins/bluez5/a2dp-codec-ldac.c
Changed
@@ -115,7 +115,8 @@ static int codec_select_config(const struct media_codec *codec, uint32_t flags, const void *caps, size_t caps_size, const struct media_codec_audio_info *info, - const struct spa_dict *settings, uint8_t configA2DP_MAX_CAPS_SIZE) + const struct spa_dict *settings, uint8_t configA2DP_MAX_CAPS_SIZE, + void **config_data) { a2dp_ldac_t conf; int i;
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/plugins/bluez5/a2dp-codec-opus-g.c -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/plugins/bluez5/a2dp-codec-opus-g.c
Changed
@@ -74,7 +74,8 @@ static int codec_select_config(const struct media_codec *codec, uint32_t flags, const void *caps, size_t caps_size, const struct media_codec_audio_info *info, - const struct spa_dict *global_settings, uint8_t configA2DP_MAX_CAPS_SIZE) + const struct spa_dict *global_settings, uint8_t configA2DP_MAX_CAPS_SIZE, + void **config_data) { a2dp_opus_g_t conf; int frequency, duration, channels; @@ -126,8 +127,8 @@ int a, b; /* Order selected configurations by preference */ - res1 = codec->select_config(codec, flags, caps1, caps1_size, info, global_settings, (uint8_t *)&conf1); - res2 = codec->select_config(codec, flags, caps2, caps2_size, info, global_settings, (uint8_t *)&conf2); + res1 = codec->select_config(codec, flags, caps1, caps1_size, info, global_settings, (uint8_t *)&conf1, NULL); + res2 = codec->select_config(codec, flags, caps2, caps2_size, info, global_settings, (uint8_t *)&conf2, NULL); #define PREFER_EXPR(expr) \ do { \
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/plugins/bluez5/a2dp-codec-opus.c -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/plugins/bluez5/a2dp-codec-opus.c
Changed
@@ -590,7 +590,8 @@ static int codec_select_config(const struct media_codec *codec, uint32_t flags, const void *caps, size_t caps_size, const struct media_codec_audio_info *info, - const struct spa_dict *global_settings, uint8_t configA2DP_MAX_CAPS_SIZE) + const struct spa_dict *global_settings, uint8_t configA2DP_MAX_CAPS_SIZE, + void **config_data) { struct props props; a2dp_opus_05_t conf; @@ -699,8 +700,8 @@ int a, b; /* Order selected configurations by preference */ - res1 = codec->select_config(codec, flags, caps1, caps1_size, info, global_settings, (uint8_t *)&conf1); - res2 = codec->select_config(codec, flags, caps2, caps2_size, info, global_settings, (uint8_t *)&conf2); + res1 = codec->select_config(codec, flags, caps1, caps1_size, info, global_settings, (uint8_t *)&conf1, NULL); + res2 = codec->select_config(codec, flags, caps2, caps2_size, info, global_settings, (uint8_t *)&conf2, NULL); #define PREFER_EXPR(expr) \ do { \
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/plugins/bluez5/a2dp-codec-sbc.c -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/plugins/bluez5/a2dp-codec-sbc.c
Changed
@@ -135,7 +135,8 @@ static int codec_select_config(const struct media_codec *codec, uint32_t flags, const void *caps, size_t caps_size, const struct media_codec_audio_info *info, - const struct spa_dict *settings, uint8_t configA2DP_MAX_CAPS_SIZE) + const struct spa_dict *settings, uint8_t configA2DP_MAX_CAPS_SIZE, + void **config_data) { a2dp_sbc_t conf; int bitpool, i; @@ -221,8 +222,8 @@ bool xq = (spa_streq(codec->name, "sbc_xq")); /* Order selected configurations by preference */ - res1 = codec->select_config(codec, 0, caps1, caps1_size, info, NULL, (uint8_t *)&conf1); - res2 = codec->select_config(codec, 0, caps2, caps2_size, info , NULL, (uint8_t *)&conf2); + res1 = codec->select_config(codec, 0, caps1, caps1_size, info, NULL, (uint8_t *)&conf1, NULL); + res2 = codec->select_config(codec, 0, caps2, caps2_size, info , NULL, (uint8_t *)&conf2, NULL); #define PREFER_EXPR(expr) \ do { \
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/plugins/bluez5/backend-native.c -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/plugins/bluez5/backend-native.c
Changed
@@ -852,7 +852,7 @@ if (cfg) libusb_free_config_descriptor(cfg); if (devices) - libusb_free_device_list(devices, 0); + libusb_free_device_list(devices, true); if (ctx) libusb_exit(ctx); return ok; @@ -1010,6 +1010,7 @@ switch (indicator) { case SPA_BT_HFP_HF_INDICATOR_ENHANCED_SAFETY: + rfcomm_send_error(rfcomm, CMEE_AG_FAILURE); break; case SPA_BT_HFP_HF_INDICATOR_BATTERY_LEVEL: // Battery level is reported in range 0-100 @@ -1018,12 +1019,15 @@ if (value <= 100) { // TODO: report without Battery Provider (using props) spa_bt_device_report_battery_level(rfcomm->device, value); + rfcomm_send_reply(rfcomm, "OK"); } else { spa_log_warn(backend->log, "battery HF indicator %u outside of range 0, 100: %u", indicator, value); + rfcomm_send_error(rfcomm, CMEE_AG_FAILURE); } break; default: spa_log_warn(backend->log, "unknown HF indicator:%u value:%u", indicator, value); + rfcomm_send_error(rfcomm, CMEE_AG_FAILURE); break; } } @@ -1307,7 +1311,7 @@ type = INTERNATIONAL_NUMBER; else type = NATIONAL_NUMBER; - rfcomm_send_reply(rfcomm, "+CNUM: ,\"%s\",%u", backend->modem.own_number, type); + rfcomm_send_reply(rfcomm, "+CNUM: ,\"%s\",%u,,4", backend->modem.own_number, type); } rfcomm_send_reply(rfcomm, "OK"); } else if (spa_strstartswith(buf, "AT+COPS=")) { @@ -1350,6 +1354,7 @@ rfcomm_send_reply(rfcomm, "+BIND: (2)"); rfcomm_send_reply(rfcomm, "OK"); } else if (spa_strstartswith(buf, "AT+BIND?")) { + rfcomm_send_reply(rfcomm, "+BIND: 1,0"); rfcomm_send_reply(rfcomm, "+BIND: 2,1"); rfcomm_send_reply(rfcomm, "OK"); } else if (spa_strstartswith(buf, "AT+BIND=")) { @@ -1359,7 +1364,6 @@ rfcomm_send_reply(rfcomm, "OK"); } else if (sscanf(buf, "AT+BIEV=%u,%u", &indicator, &indicator_value) == 2) { process_hfp_hf_indicator(rfcomm, indicator, indicator_value); - rfcomm_send_reply(rfcomm, "OK"); } else if (sscanf(buf, "AT+XAPL=%04x-%04x-%*^,,%u", &xapl_vendor, &xapl_product, &xapl_features) == 3) { if (xapl_features & SPA_BT_HFP_HF_XAPL_FEATURE_BATTERY_REPORTING) { /* claim, that we support battery status reports */ @@ -2759,7 +2763,8 @@ goto fail; #ifdef HAVE_BLUEZ_5_BACKEND_HFP_NATIVE - rfcomm_hfp_ag_set_cind(td->rfcomm, true); + if (!mm_is_available(backend->modemmanager)) + rfcomm_hfp_ag_set_cind(td->rfcomm, true); #endif t->fd = sock; @@ -2813,7 +2818,8 @@ spa_bt_transport_set_state(t, SPA_BT_TRANSPORT_STATE_IDLE); #ifdef HAVE_BLUEZ_5_BACKEND_HFP_NATIVE - rfcomm_hfp_ag_set_cind(td->rfcomm, false); + if (!mm_is_available(backend->modemmanager)) + rfcomm_hfp_ag_set_cind(td->rfcomm, false); #endif sco_destroy_cb(t);
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/plugins/bluez5/bap-codec-caps.h -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/plugins/bluez5/bap-codec-caps.h
Changed
@@ -82,6 +82,22 @@ #define LC3_MAX_CHANNELS 28 +/* Metadata types */ +#define BAP_META_TYPE_PREFERRED_CONTEXT 0x01 +#define BAP_META_TYPE_STREAMING_CONTEXT 0x02 +#define BAP_META_TYPE_PROGRAM_INFO 0x03 +#define BAP_META_TYPE_LANGUAGE 0x04 +#define BAP_META_TYPE_CCID_LIST 0x05 +#define BAP_META_TYPE_PARENTAL_RATING 0x06 +#define BAP_META_TYPE_PROGRAM_INFO_URI 0x07 +#define BAP_META_TYPE_AUDIO_ACTIVE_STATE 0x08 +#define BAP_META_TYPE_BCAST_IMMEDIATE 0x09 +#define BAP_META_TYPE_ASSISTED_LISTENING 0x0a +#define BAP_META_TYPE_BCAST_NAME 0x0b +#define BAP_META_TYPE_EXTENDED 0xfe +#define BAP_META_TYPE_VENDOR 0xff + + #define BAP_CHANNEL_MONO 0x00000000 /* mono */ #define BAP_CHANNEL_FL 0x00000001 /* front left */ #define BAP_CHANNEL_FR 0x00000002 /* front right */ @@ -137,12 +153,6 @@ #define BT_ISO_QOS_TARGET_LATENCY_BALANCED 0x02 #define BT_ISO_QOS_TARGET_LATENCY_RELIABILITY 0x03 -struct __attribute__((packed)) ltv { - uint8_t len; - uint8_t type; - uint8_t value; -}; - struct bap_endpoint_qos { uint8_t framing; uint8_t phy;
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/plugins/bluez5/bap-codec-lc3.c -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/plugins/bluez5/bap-codec-lc3.c
Changed
@@ -16,6 +16,7 @@ #include <spa/param/audio/format-utils.h> #include <spa/utils/string.h> #include <spa/utils/json.h> +#include <spa/utils/cleanup.h> #include <spa/debug/log.h> #include <lc3.h> @@ -45,9 +46,11 @@ struct settings { uint32_t locations; uint32_t channel_allocation; + uint16_t supported_context; + uint16_t available_context; bool sink; bool duplex; - const char *qos_name; + char *qos_name; int retransmission; int latency; int64_t delay; @@ -55,8 +58,10 @@ }; struct pac_data { - const uint8_t *data; + const void *data; size_t size; + const void *metadata; + size_t metadata_size; int index; const struct settings *settings; }; @@ -81,9 +86,16 @@ uint8_t n_blks; bool sink; bool duplex; + uint16_t preferred_context; unsigned int priority; } bap_lc3_t; +struct config_data { + bap_lc3_t conf; + int pac_index; + struct settings settings; +}; + #define BAP_QOS(name_, rate_, duration_, framing_, framelen_, rtn_, latency_, delay_, priority_) \ ((struct bap_qos){ .name = (name_), .rate = (rate_), .frame_duration = (duration_), .framing = (framing_), \ .framelen = (framelen_), .retransmission = (rtn_), .latency = (latency_), \ @@ -191,32 +203,6 @@ return 0; } -static int write_ltv(uint8_t *dest, uint8_t type, void* value, size_t len) -{ - struct ltv *ltv = (struct ltv *)dest; - - ltv->len = len + 1; - ltv->type = type; - memcpy(ltv->value, value, len); - - return len + 2; -} - -static int write_ltv_uint8(uint8_t *dest, uint8_t type, uint8_t value) -{ - return write_ltv(dest, type, &value, sizeof(value)); -} - -static int write_ltv_uint16(uint8_t *dest, uint8_t type, uint16_t value) -{ - return write_ltv(dest, type, &value, sizeof(value)); -} - -static int write_ltv_uint32(uint8_t *dest, uint8_t type, uint32_t value) -{ - return write_ltv(dest, type, &value, sizeof(value)); -} - static uint16_t parse_rates(const char *str) { struct spa_json it; @@ -319,7 +305,6 @@ static int codec_fill_caps(const struct media_codec *codec, uint32_t flags, const struct spa_dict *settings, uint8_t capsA2DP_MAX_CAPS_SIZE) { - uint8_t *data = caps; const char *str; uint16_t framelen2; uint16_t rate_mask = LC3_FREQ_48KHZ | LC3_FREQ_44KHZ | LC3_FREQ_32KHZ | \ @@ -330,6 +315,7 @@ uint16_t framelen_max = LC3_MAX_FRAME_BYTES; uint8_t max_frames = 2; uint32_t value; + struct ltv_writer writer = LTV_WRITER(caps, A2DP_MAX_CAPS_SIZE); if (settings && (str = spa_dict_lookup(settings, "bluez5.bap-server-capabilities.rates"))) rate_mask = parse_rates(str); @@ -355,17 +341,17 @@ framelen0 = htobs(framelen_min); framelen1 = htobs(framelen_max); - data += write_ltv_uint16(data, LC3_TYPE_FREQ, htobs(rate_mask)); - data += write_ltv_uint8(data, LC3_TYPE_DUR, duration_mask); - data += write_ltv_uint8(data, LC3_TYPE_CHAN, channel_counts); - data += write_ltv(data, LC3_TYPE_FRAMELEN, framelen, sizeof(framelen)); + ltv_writer_uint16(&writer, LC3_TYPE_FREQ, rate_mask); + ltv_writer_uint8(&writer, LC3_TYPE_DUR, duration_mask); + ltv_writer_uint8(&writer, LC3_TYPE_CHAN, channel_counts); + ltv_writer_data(&writer, LC3_TYPE_FRAMELEN, framelen, sizeof(framelen)); /* XXX: we support only one frame block -> max 2 frames per SDU */ if (max_frames > 2) max_frames = 2; - data += write_ltv_uint8(data, LC3_TYPE_BLKS, max_frames); + ltv_writer_uint8(&writer, LC3_TYPE_BLKS, max_frames); - return data - caps; + return ltv_writer_end(&writer); } static void debugc_ltv(struct spa_debug_context *debug_ctx, int pac, struct ltv *ltv) @@ -391,7 +377,7 @@ } } -static int parse_bluez_pacs(const uint8_t *data, size_t data_size, struct pac_data pacsMAX_PACS, +static int parse_bluez_pacs_data(const uint8_t *data, size_t data_size, struct pac_data pacsMAX_PACS, struct spa_debug_context *debug_ctx) { /* @@ -400,7 +386,7 @@ */ int pac = 0; - pacspac = (struct pac_data){ data, 0 }; + pacspac = (struct pac_data){ .data = data }; while (data_size > 0) { struct ltv *ltv = (struct ltv *)data; @@ -411,7 +397,7 @@ break; ++pac; - pacspac = (struct pac_data){ data + 1, 0, pac }; + pacspac = (struct pac_data){ .data = data + 1, .index = pac }; } else if (ltv->len >= data_size) { return -EINVAL; } else { @@ -425,6 +411,28 @@ return pac + 1; } +static int parse_bluez_pacs(const uint8_t *data, size_t data_size, + const uint8_t *metadata, size_t metadata_size, struct pac_data pacsMAX_PACS, + struct spa_debug_context *debug_ctx) +{ + struct pac_data metaMAX_PACS; + int pac_count, meta_count; + + pac_count = parse_bluez_pacs_data(data, data_size, pacs, debug_ctx); + if (pac_count < 0) + return pac_count; + + meta_count = parse_bluez_pacs_data(metadata, metadata_size, meta, debug_ctx); + if (meta_count == pac_count) { + for (int i = 0; i < pac_count; ++i) { + pacsi.metadata = metai.data; + pacsi.metadata_size = metai.size; + } + } + + return pac_count; +} + static uint8_t get_channel_count(uint32_t channels) { uint8_t num; @@ -549,7 +557,7 @@ static bool select_config(bap_lc3_t *conf, const struct pac_data *pac, struct spa_debug_context *debug_ctx) { - const uint8_t *data = pac->data; + const void *data = pac->data; size_t data_size = pac->size; uint16_t framelen_min = 0, framelen_max = 0; int max_frames = -1; @@ -557,9 +565,11 @@ uint8_t max_channels = 0; uint8_t duration_mask = 0; uint16_t rate_mask = 0; + uint16_t preferred_context = 0; struct bap_qos bap_qos; unsigned int i; bool found = false; + const struct ltv *ltv; if (!data_size) return false; @@ -571,14 +581,7 @@ /* XXX: we always use one frame block */ conf->n_blks = 1; - while (data_size > 0) { - struct ltv *ltv = (struct ltv *)data; - - if (ltv->len < sizeof(struct ltv) || ltv->len >= data_size) { - spa_debugc(debug_ctx, "invalid LTV data"); - return false; - } - + while ((ltv = ltv_next(&data, &data_size))) { switch (ltv->type) { case LC3_TYPE_FREQ: spa_return_val_if_fail(ltv->len == 3, false); @@ -605,9 +608,25 @@ spa_debugc(debug_ctx, "unknown LTV type: 0x%02x", ltv->type); break; } - data_size -= ltv->len + 1; - data += ltv->len + 1; } + if (data) { + spa_debugc(debug_ctx, "invalid LTV data"); + return false; + } + + data = pac->metadata; + data_size = pac->metadata_size; + while ((ltv = ltv_next(&data, &data_size))) { + switch (ltv->type) { + case BAP_META_TYPE_PREFERRED_CONTEXT: + if (ltv->len != 3) + break; + preferred_context = ltv->value0 + (ltv->value1 << 8); + break; + } + } + if (data) + spa_debugc(debug_ctx, "malformed metadata"); for (i = 0; i < 8; ++i) if (channel_counts & (1u << i)) @@ -646,8 +665,8 @@ * and reassemble SDUs as needed. */ if (pac->settings->duplex) { - /* 16KHz input is mandatory in BAP v1.0.1 Table 3.5, so prefer - * it or 32kHz for now for input rate in duplex configuration. + /* 16KHz input is mandatory in BAP v1.0.1 Table 3.5, and 32KHz in TMAP, + * so prefer those for now for input rate in duplex configuration. * * It appears few devices support 48kHz out + input, so in duplex mode * try 32 kHz or 16 kHz also for output direction. @@ -670,12 +689,15 @@ conf->frame_duration = bap_qos.frame_duration; conf->framelen = bap_qos.framelen; conf->priority = bap_qos.priority; + conf->preferred_context = preferred_context; return true; } -static bool parse_conf(bap_lc3_t *conf, const uint8_t *data, size_t data_size) +static bool parse_conf(bap_lc3_t *conf, const void *data, size_t data_size) { + const struct ltv *ltv; + if (!data_size) return false; memset(conf, 0, sizeof(*conf)); @@ -685,12 +707,7 @@ /* Absent Codec_Frame_Blocks_Per_SDU means 0x1 (BAP v1.0.1 Sec 4.3.2) */ conf->n_blks = 1; - while (data_size > 0) { - struct ltv *ltv = (struct ltv *)data; - - if (ltv->len < sizeof(struct ltv) || ltv->len >= data_size) - return false; - + while ((ltv = ltv_next(&data, &data_size))) { switch (ltv->type) { case LC3_TYPE_FREQ: spa_return_val_if_fail(ltv->len == 2, false); @@ -718,9 +735,9 @@ default: return false; } - data_size -= ltv->len + 1; - data += ltv->len + 1; } + if (data) + return false; if (conf->frame_duration == 0xFF || !conf->rate) return false; @@ -728,7 +745,32 @@ return true; } -static int conf_cmp(const bap_lc3_t *conf1, int res1, const bap_lc3_t *conf2, int res2) +static uint16_t get_wanted_context(const struct settings *settings) +{ + uint16_t context; + + /* Stick with contexts specified in TMAP. Anything else is probably crapshoot due + * to interesting device firmware behavior. + * + * Eg. some Earfun firmwares fail if we set MEDIA | CONVERSATIONAL, other versions + * disconnect if LIVE is set, Samsung Galaxy Buds fail on microphone Enable if + * CONVERSATIONAL is not set. + */ + if (settings->sink || settings->duplex) + context = BAP_CONTEXT_CONVERSATIONAL; + else + context = BAP_CONTEXT_MEDIA; + + /* CAP v1.0.1 Sec 7.3.1.2.1: drop contexts if not available, otherwise unspecified */ + context &= settings->available_context; + if (!context) + context = BAP_CONTEXT_UNSPECIFIED & settings->available_context; + + return context; +} + +static int conf_cmp(const bap_lc3_t *conf1, int res1, const bap_lc3_t *conf2, int res2, + const struct settings *settings) { const bap_lc3_t *conf; int a, b; @@ -753,6 +795,9 @@ PREFER_EXPR(conf->priority == UINT_MAX); + /* CAP v1.0.1 Sec 7.3.1.2.4: should use PAC preferred context if possible */ + PREFER_BOOL(conf->preferred_context & get_wanted_context(settings)); + PREFER_BOOL(conf->channels & LC3_CHAN_2); PREFER_BOOL(conf->channels & LC3_CHAN_1); @@ -778,7 +823,7 @@ res1 = select_config(&conf1, pac1, &debug_ctx.ctx) ? (int)sizeof(bap_lc3_t) : -EINVAL; res2 = select_config(&conf2, pac2, &debug_ctx.ctx) ? (int)sizeof(bap_lc3_t) : -EINVAL; - return conf_cmp(&conf1, res1, &conf2, res2); + return conf_cmp(&conf1, res1, &conf2, res2, pac1->settings); } static void parse_settings(struct settings *s, const struct spa_dict *settings, @@ -797,7 +842,7 @@ return; if ((str = spa_dict_lookup(settings, "bluez5.bap.preset"))) - s->qos_name = str; + s->qos_name = strdup(str); if (spa_atou32(spa_dict_lookup(settings, "bluez5.bap.rtn"), &value, 0)) s->retransmission = value; @@ -817,12 +862,18 @@ if (spa_atou32(spa_dict_lookup(settings, "bluez5.bap.channel-allocation"), &value, 0)) s->channel_allocation = value; + if (spa_atou32(spa_dict_lookup(settings, "bluez5.bap.supported-context"), &value, 0)) + s->supported_context = value; + + if (spa_atou32(spa_dict_lookup(settings, "bluez5.bap.available-context"), &value, 0)) + s->available_context = value; + if (spa_atob(spa_dict_lookup(settings, "bluez5.bap.debug"))) *debug_ctx = SPA_LOG_DEBUG_INIT(log_, SPA_LOG_LEVEL_DEBUG); else *debug_ctx = SPA_LOG_DEBUG_INIT(NULL, SPA_LOG_LEVEL_TRACE); - /* Is remote endpoint sink or source */ + /* Is local endpoint sink or source */ s->sink = spa_atob(spa_dict_lookup(settings, "bluez5.bap.sink")); /* Is remote endpoint duplex */ @@ -837,26 +888,48 @@ (int)s->sink, (int)s->duplex); } +static void free_config_data(struct config_data *d) +{ + if (!d) + return; + free(d->settings.qos_name); + free(d); +} + +SPA_DEFINE_AUTOPTR_CLEANUP(config_data, struct config_data, { spa_clear_ptr(*thing, free_config_data); }); + static int codec_select_config(const struct media_codec *codec, uint32_t flags, const void *caps, size_t caps_size, const struct media_codec_audio_info *info, - const struct spa_dict *settings, uint8_t configA2DP_MAX_CAPS_SIZE) + const struct spa_dict *settings, uint8_t configA2DP_MAX_CAPS_SIZE, + void **config_data) { struct pac_data pacsMAX_PACS; int npacs; bap_lc3_t conf; - uint8_t *data = config; struct spa_debug_log_ctx debug_ctx; - struct settings s; - int i; + spa_autoptr(config_data) d = NULL; + int i, ret; + struct ltv_writer writer = LTV_WRITER(config, A2DP_MAX_CAPS_SIZE); + const void *metadata = NULL; + uint32_t metadata_len = 0; if (caps == NULL) return -EINVAL; - parse_settings(&s, settings, &debug_ctx); + d = calloc(1, sizeof(*d)); + if (!d) + return -ENOMEM; + + parse_settings(&d->settings, settings, &debug_ctx); + + if (spa_atou32(spa_dict_lookup(settings, "bluez5.bap.metadata"), &metadata_len, 0)) + metadata = spa_dict_lookup(settings, "bluez5.bap.metadata"); + if (!metadata) + metadata_len = 0; /* Select best conf from those possible */ - npacs = parse_bluez_pacs(caps, caps_size, pacs, &debug_ctx.ctx); + npacs = parse_bluez_pacs(caps, caps_size, metadata, metadata_len, pacs, &debug_ctx.ctx); if (npacs < 0) { spa_debugc(&debug_ctx.ctx, "malformed PACS"); return npacs; @@ -866,7 +939,7 @@ } for (i = 0; i < npacs; ++i) - pacsi.settings = &s; + pacsi.settings = &d->settings; qsort(pacs, npacs, sizeof(struct pac_data), pac_cmp); @@ -875,30 +948,47 @@ if (!select_config(&conf, &pacs0, &debug_ctx.ctx)) return -ENOTSUP; - data += write_ltv_uint8(data, LC3_TYPE_FREQ, conf.rate); - data += write_ltv_uint8(data, LC3_TYPE_DUR, conf.frame_duration); + d->conf = conf; + d->pac_index = pacs0.index; + + ltv_writer_uint8(&writer, LC3_TYPE_FREQ, conf.rate); + ltv_writer_uint8(&writer, LC3_TYPE_DUR, conf.frame_duration); /* Indicate MONO with absent Audio_Channel_Allocation (BAP v1.0.1 Sec. 4.3.2) */ if (conf.channels != 0) - data += write_ltv_uint32(data, LC3_TYPE_CHAN, htobl(conf.channels)); + ltv_writer_uint32(&writer, LC3_TYPE_CHAN, conf.channels); - data += write_ltv_uint16(data, LC3_TYPE_FRAMELEN, htobs(conf.framelen)); - data += write_ltv_uint8(data, LC3_TYPE_BLKS, conf.n_blks); + ltv_writer_uint16(&writer, LC3_TYPE_FRAMELEN, conf.framelen); + ltv_writer_uint8(&writer, LC3_TYPE_BLKS, conf.n_blks); - return data - config; + ret = ltv_writer_end(&writer); + + if (ret >= 0 && config_data) + *config_data = spa_steal_ptr(d); + + return ret; } static int codec_caps_preference_cmp(const struct media_codec *codec, uint32_t flags, const void *caps1, size_t caps1_size, const void *caps2, size_t caps2_size, const struct media_codec_audio_info *info, const struct spa_dict *global_settings) { bap_lc3_t conf1, conf2; - int res1, res2; + int res1, res2, res; + void *data1 = NULL; + void *data2 = NULL; + const struct config_data *d; /* Order selected configurations by preference */ - res1 = codec->select_config(codec, 0, caps1, caps1_size, info, global_settings, (uint8_t *)&conf1); - res2 = codec->select_config(codec, 0, caps2, caps2_size, info, global_settings, (uint8_t *)&conf2); + res1 = codec->select_config(codec, 0, caps1, caps1_size, info, global_settings, (uint8_t *)&conf1, &data1); + res2 = codec->select_config(codec, 0, caps2, caps2_size, info, global_settings, (uint8_t *)&conf2, &data2); - return conf_cmp(&conf1, res1, &conf2, res2); + d = data1 ? data1 : data2; + res = conf_cmp(&conf1, res1, &conf2, res2, d ? &d->settings : NULL); + + codec->free_config_data(codec, data1); + codec->free_config_data(codec, data2); + + return res; } static uint8_t channels_to_positions(uint32_t channels, uint32_t *position, uint32_t max_position) @@ -1062,24 +1152,23 @@ } static int codec_get_qos(const struct media_codec *codec, - const void *config, size_t config_size, const struct bap_endpoint_qos *endpoint_qos, - struct bap_codec_qos *qos, const struct spa_dict *settings) + const void *config_data, + struct bap_codec_qos *qos) { struct bap_qos bap_qos; bap_lc3_t conf; bool found = false; - struct settings s; - struct spa_debug_log_ctx debug_ctx; + const struct config_data *d = config_data; spa_zero(*qos); - if (!parse_conf(&conf, config, config_size)) + if (!d) return -EINVAL; - parse_settings(&s, settings, &debug_ctx); + conf = d->conf; - found = select_bap_qos(&bap_qos, &s, get_rate_mask(conf.rate), get_duration_mask(conf.frame_duration), + found = select_bap_qos(&bap_qos, &d->settings, get_rate_mask(conf.rate), get_duration_mask(conf.frame_duration), conf.framelen, conf.framelen); if (!found) { /* shouldn't happen: select_config should pick existing one */ @@ -1122,6 +1211,27 @@ return 0; } +static int codec_get_metadata(const struct media_codec *codec, const void *config_data, + uint8_t *meta, size_t meta_max_size) +{ + const struct config_data *d = config_data; + struct ltv_writer writer = LTV_WRITER(meta, meta_max_size); + uint16_t ctx; + + ctx = get_wanted_context(&d->settings); + if (!ctx) + ctx = BAP_CONTEXT_UNSPECIFIED; + + ltv_writer_uint16(&writer, BAP_META_TYPE_STREAMING_CONTEXT, ctx); + + return ltv_writer_end(&writer); +} + +static void codec_free_config_data(const struct media_codec *codec, void *config_data) +{ + free_config_data(config_data); +} + static void *codec_init(const struct media_codec *codec, uint32_t flags, void *config, size_t config_len, const struct spa_audio_info *info, void *props, size_t mtu) @@ -1378,80 +1488,60 @@ uint8_t *caps_size, struct spa_dict *settings, struct bap_codec_qos *qos) { - int index = 0x0; - bool preset_found = false; - const char *preset = NULL; + const char *preset_name = NULL; int channel_allocation = 0; - uint8_t *data = caps; + int i, ret; + struct ltv_writer writer = LTV_WRITER(caps, *caps_size); + const struct bap_qos *preset = NULL; + *caps_size = 0; - int i; if (settings) { for (i = 0; i < (int)settings->n_items; ++i) { if (spa_streq(settings->itemsi.key, "channel_allocation")) sscanf(settings->itemsi.value, "%"PRIu32, &channel_allocation); if (spa_streq(settings->itemsi.key, "preset")) - preset = spa_dict_lookup(settings, "preset"); + preset_name = settings->itemsi.value; } } - if (preset == NULL) + if (preset_name == NULL) return -EINVAL; SPA_FOR_EACH_ELEMENT_VAR(bap_bcast_qos_configs, c) { - if (spa_streq(c->name, preset)) { - preset_found = true; + if (spa_streq(c->name, preset_name)) { + preset = c; break; } - index++; } - if (!preset_found) - return -EINVAL; - - switch (bap_bcast_qos_configsindex.rate) { - case LC3_CONFIG_FREQ_48KHZ: - data += write_ltv_uint8(data, LC3_TYPE_FREQ, LC3_CONFIG_FREQ_48KHZ); - break; - case LC3_CONFIG_FREQ_44KHZ: - data += write_ltv_uint8(data, LC3_TYPE_FREQ, LC3_CONFIG_FREQ_44KHZ); - break; - case LC3_CONFIG_FREQ_32KHZ: - data += write_ltv_uint8(data, LC3_TYPE_FREQ, LC3_CONFIG_FREQ_32KHZ); - break; - case LC3_CONFIG_FREQ_24KHZ: - data += write_ltv_uint8(data, LC3_TYPE_FREQ, LC3_CONFIG_FREQ_24KHZ); - break; - case LC3_CONFIG_FREQ_16KHZ: - data += write_ltv_uint8(data, LC3_TYPE_FREQ, LC3_CONFIG_FREQ_16KHZ); - break; - case LC3_CONFIG_FREQ_8KHZ: - data += write_ltv_uint8(data, LC3_TYPE_FREQ, LC3_CONFIG_FREQ_8KHZ); - break; - default: + if (!preset) return -EINVAL; - } - *caps_size += 3; - data += write_ltv_uint16(data, LC3_TYPE_FRAMELEN, htobs(bap_bcast_qos_configsindex.framelen)); - *caps_size += 4; - data += write_ltv_uint8(data, LC3_TYPE_DUR, bap_bcast_qos_configsindex.frame_duration); - *caps_size += 3; - data += write_ltv_uint32(data, LC3_TYPE_CHAN, htobl(channel_allocation)); - *caps_size += 6; + ltv_writer_uint8(&writer, LC3_TYPE_FREQ, preset->rate); + ltv_writer_uint16(&writer, LC3_TYPE_FRAMELEN, preset->framelen); + ltv_writer_uint8(&writer, LC3_TYPE_DUR, preset->frame_duration); + ltv_writer_uint32(&writer, LC3_TYPE_CHAN, channel_allocation); - if(bap_bcast_qos_configsindex.framing) + if (preset->framing) qos->framing = 1; else qos->framing = 0; - qos->sdu = bap_bcast_qos_configsindex.framelen * get_channel_count(channel_allocation); - qos->retransmission = bap_bcast_qos_configsindex.retransmission; - qos->latency = bap_bcast_qos_configsindex.latency; - qos->delay = bap_bcast_qos_configsindex.delay; + qos->sdu = preset->framelen * get_channel_count(channel_allocation); + qos->retransmission = preset->retransmission; + qos->latency = preset->latency; + qos->delay = preset->delay; qos->phy = 2; - qos->interval = (bap_bcast_qos_configsindex.frame_duration == LC3_CONFIG_DURATION_7_5 ? 7500 : 10000); + qos->interval = (preset->frame_duration == LC3_CONFIG_DURATION_7_5 ? 7500 : 10000); - return true; + ret = ltv_writer_end(&writer); + if (ret < 0) + return ret; + if (ret > UINT8_MAX) + return -ENOSPC; + + *caps_size = ret; + return 0; } const struct media_codec bap_codec_lc3 = { @@ -1465,6 +1555,8 @@ .enum_config = codec_enum_config, .validate_config = codec_validate_config, .get_qos = codec_get_qos, + .get_metadata = codec_get_metadata, + .free_config_data = codec_free_config_data, .caps_preference_cmp = codec_caps_preference_cmp, .init = codec_init, .deinit = codec_deinit,
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/plugins/bluez5/bluez5-dbus.c -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/plugins/bluez5/bluez5-dbus.c
Changed
@@ -152,8 +152,10 @@ char *uuid; unsigned int codec; struct spa_bt_device *device; - uint8_t capabilitiesA2DP_MAX_CAPS_SIZE; - int capabilities_len; + uint8_t *capabilities; + size_t capabilities_len; + uint8_t *metadata; + size_t metadata_len; bool delay_reporting; bool acceptor; @@ -693,7 +695,7 @@ * by codec switching. */ res = codec->select_config(codec, sink ? MEDIA_CODEC_FLAG_SINK : 0, cap, size, &monitor->default_audio_info, - &monitor->global_settings, config); + &monitor->global_settings, config, NULL); else res = -ENOTSUP; @@ -878,8 +880,9 @@ } static int parse_endpoint_props(struct spa_bt_monitor *monitor, DBusMessageIter *iter, - uint8_t capsA2DP_MAX_CAPS_SIZE, int *caps_size, const char **endpoint_path, - struct bap_endpoint_qos *qos) + uint8_t **caps, size_t *caps_size, + uint8_t **meta, size_t *meta_size, + const char **endpoint_path, struct bap_endpoint_qos *qos) { DBusMessageIter dict_iter = *iter; const char *key = NULL; @@ -900,12 +903,25 @@ type = dbus_message_iter_get_arg_type(&it1); - if (spa_streq(key, "Capabilities")) { - uint8_t *buf; + if (spa_streq(key, "Capabilities") || spa_streq(key, "Metadata")) { + uint8_t **dest; + size_t *size; + uint8_t *data, *buf; + int n; + + if (spa_streq(key, "Capabilities")) { + dest = caps; + size = caps_size; + } else { + dest = meta; + size = meta_size; + } - if (!caps) + if (!dest) goto next; + spa_assert(dest && size); + if (type != DBUS_TYPE_ARRAY) goto bad_property; @@ -914,15 +930,19 @@ if (type != DBUS_TYPE_BYTE) goto bad_property; - dbus_message_iter_get_fixed_array(&it2, &buf, caps_size); - if (*caps_size > A2DP_MAX_CAPS_SIZE) { - spa_log_error(monitor->log, "%s size:%d too large", key, (int)*caps_size); - return -EINVAL; - } - memcpy(caps, buf, *caps_size); + dbus_message_iter_get_fixed_array(&it2, &data, &n); - spa_log_info(monitor->log, "%p: %s size:%d", monitor, key, *caps_size); - spa_debug_log_mem(monitor->log, SPA_LOG_LEVEL_DEBUG, ' ', caps, (size_t)*caps_size); + buf = malloc(n); + if (!buf) + return -ENOMEM; + + free(*dest); + *dest = buf; + *size = n; + memcpy(buf, data, n); + + spa_log_info(monitor->log, "%p: %s size:%zu", monitor, key, *size); + spa_debug_log_mem(monitor->log, SPA_LOG_LEVEL_DEBUG, ' ', *dest, *size); } else if (spa_streq(key, "Endpoint")) { if (!endpoint_path) goto next; @@ -1012,8 +1032,12 @@ const char *endpoint_path = NULL; uint8_t configA2DP_MAX_CAPS_SIZE; + void *config_data = NULL; char locations64 = {0}; char channel_allocation64 = {0}; + char supported_context64 = {0}; + char available_context64 = {0}; + char metadata_len64 = {0}; int conf_size; DBusMessageIter dict; @@ -1028,6 +1052,9 @@ path = dbus_message_get_path(m); + if ((r = dbus_message_new_method_return(m)) == NULL) + return DBUS_HANDLER_RESULT_NEED_MEMORY; + /* TODO: for codecs with shared endpoint, this currently always picks the default * one. However, currently we don't have BAP codecs with shared endpoint, so * this does not matter, but in case they are needed later we should pick the @@ -1043,7 +1070,7 @@ /* Find endpoint */ iter = props; - if (parse_endpoint_props(monitor, &iter, NULL, NULL, &endpoint_path, NULL) < 0) + if (parse_endpoint_props(monitor, &iter, NULL, NULL, NULL, NULL, &endpoint_path, NULL) < 0) goto error_invalid; ep = remote_endpoint_find(monitor, endpoint_path); @@ -1059,7 +1086,8 @@ /* Parse endpoint properties */ iter = props; - if (parse_endpoint_props(monitor, &iter, ep->capabilities, &ep->capabilities_len, NULL, &ep->qos) < 0) + if (parse_endpoint_props(monitor, &iter, &ep->capabilities, &ep->capabilities_len, + &ep->metadata, &ep->metadata_len, NULL, &ep->qos) < 0) goto error_invalid; if (ep->qos.locations) @@ -1067,6 +1095,10 @@ if (ep->qos.channel_allocation) spa_scnprintf(channel_allocation, sizeof(channel_allocation), "%"PRIu32, ep->qos.channel_allocation); + spa_scnprintf(supported_context, sizeof(supported_context), "%"PRIu16, ep->qos.supported_context); + spa_scnprintf(available_context, sizeof(available_context), "%"PRIu16, ep->qos.context); + spa_scnprintf(metadata_len, sizeof(metadata_len), "%zu", ep->metadata_len); + if (!ep->device->preferred_profiles) ep->device->preferred_profiles = ep->device->profiles; @@ -1075,16 +1107,20 @@ i = 0; setting_itemsi++ = SPA_DICT_ITEM_INIT("bluez5.bap.locations", locations); setting_itemsi++ = SPA_DICT_ITEM_INIT("bluez5.bap.channel-allocation", channel_allocation); + setting_itemsi++ = SPA_DICT_ITEM_INIT("bluez5.bap.supported-context", supported_context); + setting_itemsi++ = SPA_DICT_ITEM_INIT("bluez5.bap.available-context", available_context); setting_itemsi++ = SPA_DICT_ITEM_INIT("bluez5.bap.sink", sink ? "true" : "false"); setting_itemsi++ = SPA_DICT_ITEM_INIT("bluez5.bap.duplex", duplex ? "true" : "false"); setting_itemsi++ = SPA_DICT_ITEM_INIT("bluez5.bap.debug", "true"); + setting_itemsi++ = SPA_DICT_ITEM_INIT("bluez5.bap.metadata", (void *)ep->metadata); + setting_itemsi++ = SPA_DICT_ITEM_INIT("bluez5.bap.metadata-len", metadata_len); if (ep->device->settings) for (j = 0; j < ep->device->settings->n_items && i < SPA_N_ELEMENTS(setting_items); ++i, ++j) setting_itemsi = ep->device->settings->itemsj; settings = SPA_DICT_INIT(setting_items, i); conf_size = codec->select_config(codec, 0, ep->capabilities, ep->capabilities_len, - &monitor->default_audio_info, &settings, config); + &monitor->default_audio_info, &settings, config, &config_data); if (conf_size < 0) { spa_log_error(monitor->log, "can't select config: %d (%s)", conf_size, spa_strerror(conf_size)); @@ -1093,8 +1129,6 @@ spa_log_info(monitor->log, "%p: selected conf %d", monitor, conf_size); spa_debug_log_mem(monitor->log, SPA_LOG_LEVEL_DEBUG, ' ', (uint8_t *)config, (size_t)conf_size); - if ((r = dbus_message_new_method_return(m)) == NULL) - return DBUS_HANDLER_RESULT_NEED_MEMORY; dbus_message_iter_init_append(r, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, @@ -1113,7 +1147,7 @@ spa_zero(qos); - res = codec->get_qos(codec, config, conf_size, &ep->qos, &qos, &settings); + res = codec->get_qos(codec, &ep->qos, config_data, &qos); if (res < 0) { spa_log_error(monitor->log, "can't select QOS config: %d (%s)", res, spa_strerror(res)); @@ -1161,8 +1195,30 @@ dbus_message_iter_close_container(&dict, &entry); } + if (codec->get_metadata) { + uint8_t meta4096 = {}; + size_t meta_size; + + meta_size = res = codec->get_metadata(codec, config_data, meta, sizeof(meta)); + if (res < 0) { + spa_log_error(monitor->log, "can't select metadata config: %d (%s)", + res, spa_strerror(res)); + goto error_invalid; + } + + if (meta_size) { + spa_log_info(monitor->log, "%p: selected metadata %d", monitor, (int)meta_size); + spa_debug_log_mem(monitor->log, SPA_LOG_LEVEL_DEBUG, ' ', meta, meta_size); + + append_basic_array_variant_dict_entry(&dict, "Metadata", "ay", "y", DBUS_TYPE_BYTE, &meta, meta_size); + } + } + dbus_message_iter_close_container(&iter, &dict); + if (config_data && codec->free_config_data) + codec->free_config_data(codec, config_data); + if (!dbus_connection_send(conn, r, NULL)) return DBUS_HANDLER_RESULT_NEED_MEMORY; @@ -1173,6 +1229,9 @@ goto error; error: + if (config_data && codec->free_config_data) + codec->free_config_data(codec, config_data); + if (!reply_with_error(conn, m, "org.bluez.Error.InvalidArguments", err_msg)) return DBUS_HANDLER_RESULT_NEED_MEMORY; return DBUS_HANDLER_RESULT_HANDLED; @@ -2805,8 +2864,9 @@ DBusMessageIter copy_iter = *props_iter; parse_endpoint_props(monitor, ©_iter, - remote_endpoint->capabilities, &remote_endpoint->capabilities_len, NULL, - &remote_endpoint->qos); + &remote_endpoint->capabilities, &remote_endpoint->capabilities_len, + &remote_endpoint->metadata, &remote_endpoint->metadata_len, + NULL, &remote_endpoint->qos); while (dbus_message_iter_get_arg_type(props_iter) != DBUS_TYPE_INVALID) { DBusMessageIter it2; @@ -2820,7 +2880,8 @@ type = dbus_message_iter_get_arg_type(&it1); - if (spa_streq(key, "Capabilities") || spa_streq(key, "Locations") || + if (spa_streq(key, "Capabilities") || spa_streq(key, "Metadata") || + spa_streq(key, "Locations") || spa_streq(key, "QoS") || spa_streq(key, "Context") || spa_streq(key, "SupportedContext")) { /* parsed by parse_endpoint_props */ @@ -2990,6 +3051,8 @@ free(remote_endpoint->path); free(remote_endpoint->transport_path); free(remote_endpoint->uuid); + free(remote_endpoint->capabilities); + free(remote_endpoint->metadata); free(remote_endpoint); } @@ -4087,13 +4150,22 @@ return do_transport_acquire(data); } -static int do_transport_release(struct spa_bt_transport *transport) +struct pending_release { + struct spa_list link; + DBusPendingCall *pending; + struct spa_bt_transport *transport; + bool is_idle; +}; + +static struct pending_release *do_transport_release(struct spa_bt_transport *transport) { struct spa_bt_monitor *monitor = transport->monitor; - spa_autoptr(DBusMessage) m = NULL, r = NULL; + spa_autoptr(DBusMessage) m = NULL; struct spa_bt_transport *t_linked; bool is_idle = (transport->state == SPA_BT_TRANSPORT_STATE_IDLE); bool linked = false; + struct pending_release *pending; + DBusPendingCall *p; spa_log_debug(monitor->log, "transport %p: Release %s", transport, transport->path); @@ -4130,7 +4202,7 @@ if (linked) { spa_log_info(monitor->log, "Linked transport %s released", transport->path); transport->fd = -1; - return 0; + return NULL; } release: @@ -4146,46 +4218,39 @@ BLUEZ_MEDIA_TRANSPORT_INTERFACE, "Release"); if (m == NULL) - return -ENOMEM; + return NULL; - spa_auto(DBusError) err = DBUS_ERROR_INIT; - r = dbus_connection_send_with_reply_and_block(monitor->conn, m, -1, &err); - if (r == NULL) { - if (is_idle) { - /* XXX: The fd always needs to be closed. However, Release() - * XXX: apparently doesn't need to be called on idle transports - * XXX: and fails. We call it just to be sure (e.g. in case - * XXX: there's a race with updating the property), but tone down the error. - */ - spa_log_debug(monitor->log, "Failed to release idle transport %s: %s", - transport->path, err.message); - } else if (spa_streq(err.name, DBUS_ERROR_UNKNOWN_METHOD) || - spa_streq(err.name, DBUS_ERROR_UNKNOWN_OBJECT)) { - /* Transport disappeared */ - spa_log_debug(monitor->log, "Failed to release (gone) transport %s: %s", - transport->path, err.message); - } else { - spa_log_error(monitor->log, "Failed to release transport %s: %s", - transport->path, err.message); - } - } else { - spa_log_info(monitor->log, "Transport %s released", transport->path); + p = send_with_reply(monitor->conn, m, NULL, NULL); + if (!p) + return NULL; + + pending = calloc(1, sizeof(*pending)); + if (!pending) { + dbus_pending_call_block(p); + dbus_pending_call_unref(p); + return NULL; } - return 0; + pending->pending = p; + pending->transport = transport; + pending->is_idle = is_idle; + return pending; } static int transport_release(void *data) { struct spa_bt_transport *transport = data; struct spa_bt_monitor *monitor = transport->monitor; - struct spa_bt_transport *t; + struct spa_list pending = SPA_LIST_INIT(&pending); + struct pending_release *item; /* * XXX: When as BAP Central, release CIS in a CIG when the last transport * XXX: goes away. */ if (transport->bap_initiator) { + struct spa_bt_transport *t; + /* Check if another transport is alive */ if (another_cig_transport_active(transport)) { spa_log_debug(monitor->log, "Releasing %s: wait for CIG %d", @@ -4201,15 +4266,61 @@ spa_log_debug(monitor->log, "Release CIG %d: transport %s", transport->bap_cig, t->path); - if (t->fd >= 0) - do_transport_release(t); + if (t->fd >= 0) { + item = do_transport_release(t); + if (item) + spa_list_append(&pending, &item->link); + } } spa_log_debug(monitor->log, "Release CIG %d: transport %s", transport->bap_cig, transport->path); } - return do_transport_release(data); + item = do_transport_release(transport); + if (item) + spa_list_append(&pending, &item->link); + + spa_list_consume(item, &pending, link) { + struct spa_bt_transport *t = item->transport; + bool is_idle = item->is_idle; + DBusPendingCall *p = item->pending; + spa_autoptr(DBusMessage) r = NULL; + spa_auto(DBusError) err = DBUS_ERROR_INIT; + + spa_list_remove(&item->link); + free(item); + if (!p) + continue; + + dbus_pending_call_block(p); + r = steal_reply_and_unref(&p); + + if (r == NULL) { + if (is_idle) { + /* XXX: The fd always needs to be closed. However, Release() + * XXX: apparently doesn't need to be called on idle transports + * XXX: and fails. We call it just to be sure (e.g. in case + * XXX: there's a race with updating the property), but tone down the error. + */ + spa_log_debug(monitor->log, "Failed to release idle transport %s: %s", + t->path, err.message); + } else if (spa_streq(err.name, DBUS_ERROR_UNKNOWN_METHOD) || + spa_streq(err.name, DBUS_ERROR_UNKNOWN_OBJECT)) { + /* Transport disappeared */ + spa_log_debug(monitor->log, "Failed to release (gone) transport %s: %s", + t->path, err.message); + } else { + spa_log_error(monitor->log, "Failed to release transport %s: %s", + t->path, err.message); + } + } else { + spa_log_info(monitor->log, "Transport %s released", t->path); + } + } + + return 0; + } static int transport_set_delay(void *data, int64_t delay_nsec) @@ -4481,7 +4592,7 @@ } res = codec->select_config(codec, sink ? MEDIA_CODEC_FLAG_SINK : 0, ep->capabilities, ep->capabilities_len, - &monitor->default_audio_info, &monitor->global_settings, config); + &monitor->default_audio_info, &monitor->global_settings, config, NULL); if (res < 0) { spa_log_error(monitor->log, "media codec switch %p: incompatible capabilities (%d)", sw, res); @@ -5582,10 +5693,10 @@ static int register_media_application(struct spa_bt_monitor * monitor) { const struct media_codec * const * const media_codecs = monitor->media_codecs; - const DBusObjectPathVTable vtable_object_manager_a2dp = { + static const DBusObjectPathVTable vtable_object_manager_a2dp = { .message_function = object_manager_handler_a2dp, }; - const DBusObjectPathVTable vtable_object_manager_bap = { + static const DBusObjectPathVTable vtable_object_manager_bap = { .message_function = object_manager_handler_bap, }; @@ -5816,6 +5927,7 @@ int sync_cte_type = 0; int sync_timeout = 2000; int timeout = 2000; + int ret; /* Configure each BIS from a BIG */ spa_list_for_each(metadata_entry, &bis->metadata_list, link) { @@ -5839,7 +5951,12 @@ setting_items1 = SPA_DICT_ITEM_INIT("preset", bis->qos_preset); settings = SPA_DICT_INIT(setting_items, 2); - codec->get_bis_config(codec, caps, &caps_size, &settings, &qos); + caps_size = sizeof(caps); + ret = codec->get_bis_config(codec, caps, &caps_size, &settings, &qos); + if (ret < 0) { + spa_log_warn(monitor->log, "Getting BIS config failed"); + return; + } msg = dbus_message_new_method_call(BLUEZ_SERVICE, object_path, @@ -6883,8 +7000,8 @@ static void parse_bap_server(struct spa_bt_monitor *this, const struct spa_dict *info) { - this->bap_sink_locations = BAP_CHANNEL_ALL; - this->bap_source_locations = BAP_CHANNEL_ALL; + this->bap_sink_locations = BAP_CHANNEL_FL | BAP_CHANNEL_FR; + this->bap_source_locations = BAP_CHANNEL_FL | BAP_CHANNEL_FR; this->bap_sink_contexts = this->bap_sink_supported_contexts = BAP_CONTEXT_ALL; this->bap_source_contexts = this->bap_source_supported_contexts = (BAP_CONTEXT_UNSPECIFIED | BAP_CONTEXT_CONVERSATIONAL | BAP_CONTEXT_MEDIA | BAP_CONTEXT_GAME);
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/plugins/bluez5/iso-io.c -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/plugins/bluez5/iso-io.c
Changed
@@ -309,6 +309,7 @@ if (stream->this.size == 0) { spa_log_debug(group->log, "%p: ISO group:%u miss fd:%d", group, group->id, stream->fd); + stream->this.resync = true; if (stream_silence(stream) < 0) { fail = true; continue; @@ -625,6 +626,17 @@ struct stream *stream = SPA_CONTAINER_OF(this, struct stream, this); struct group *group = stream->group; + if (!stream->sink) { + struct stream *s; + + spa_list_for_each(s, &group->streams, link) { + if (s->sink && s->fd == stream->fd) { + stream = s; + break; + } + } + } + return spa_bt_latency_recv_errqueue(&stream->tx_latency, stream->fd, group->log); }
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/plugins/bluez5/media-codecs.c -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/plugins/bluez5/media-codecs.c
Changed
@@ -8,6 +8,8 @@ * */ +#include <bluetooth/bluetooth.h> + #include <spa/utils/string.h> #include <spa/utils/cleanup.h> @@ -90,7 +92,7 @@ if (caps == NULL) return false; - res = codec->select_config(codec, 0, caps, caps_size, info, global_settings, config); + res = codec->select_config(codec, 0, caps, caps_size, info, global_settings, config, NULL); if (res < 0) return false; @@ -100,6 +102,52 @@ return ((size_t)res == caps_size); } +void ltv_writer_data(struct ltv_writer *w, uint8_t type, void* value, size_t len) +{ + struct ltv *ltv; + size_t sz = (size_t)w->size + sizeof(struct ltv) + len; + + if (!w->buf || sz > w->max_size || (uint16_t)sz != sz) { + w->buf = NULL; + return; + } + + ltv = SPA_PTROFF(w->buf, w->size, struct ltv); + ltv->len = len + 1; + ltv->type = type; + memcpy(ltv->value, value, len); + + w->size = sz; +} + +void ltv_writer_uint8(struct ltv_writer *w, uint8_t type, uint8_t v) +{ + ltv_writer_data(w, type, &v, sizeof(v)); +} + +void ltv_writer_uint16(struct ltv_writer *w, uint8_t type, uint16_t value) +{ + uint16_t v = htobs(value); + + ltv_writer_data(w, type, &v, sizeof(v)); +} + +void ltv_writer_uint32(struct ltv_writer *w, uint8_t type, uint32_t value) +{ + uint32_t v = htobl(value); + + ltv_writer_data(w, type, &v, sizeof(v)); +} + +int ltv_writer_end(struct ltv_writer *w) +{ + if (!w->buf) + return -ENOSPC; + + w->buf = NULL; + return w->size; +} + #ifdef CODEC_PLUGIN struct impl {
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/plugins/bluez5/media-codecs.h -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/plugins/bluez5/media-codecs.h
Changed
@@ -15,6 +15,7 @@ #include <spa/pod/pod.h> #include <spa/pod/builder.h> #include <spa/support/log.h> +#include <spa/debug/log.h> #include "a2dp-codec-caps.h" #include "bap-codec-caps.h" @@ -26,7 +27,7 @@ #define SPA_TYPE_INTERFACE_Bluez5CodecMedia SPA_TYPE_INFO_INTERFACE_BASE "Bluez5:Codec:Media:Private" -#define SPA_VERSION_BLUEZ5_CODEC_MEDIA 15 +#define SPA_VERSION_BLUEZ5_CODEC_MEDIA 16 struct spa_bluez5_codec_a2dp { struct spa_interface iface; @@ -93,7 +94,7 @@ * called again to parse the remaining data. */ int (*get_bis_config)(const struct media_codec *codec, uint8_t *caps, - uint8_t *caps_size, struct spa_dict *settings, + uint8_t *caps_size, struct spa_dict *settings, struct bap_codec_qos *qos); /** If fill_caps is NULL, no endpoint is registered (for sharing with another codec). */ @@ -103,7 +104,8 @@ int (*select_config) (const struct media_codec *codec, uint32_t flags, const void *caps, size_t caps_size, const struct media_codec_audio_info *info, - const struct spa_dict *global_settings, uint8_t configA2DP_MAX_CAPS_SIZE); + const struct spa_dict *global_settings, uint8_t configA2DP_MAX_CAPS_SIZE, + void **config_data); int (*enum_config) (const struct media_codec *codec, uint32_t flags, const void *caps, size_t caps_size, uint32_t id, uint32_t idx, struct spa_pod_builder *builder, struct spa_pod **param); @@ -111,9 +113,12 @@ const void *caps, size_t caps_size, struct spa_audio_info *info); int (*get_qos)(const struct media_codec *codec, - const void *config, size_t config_size, const struct bap_endpoint_qos *endpoint_qos, - struct bap_codec_qos *qos, const struct spa_dict *settings); + const void *config_data, + struct bap_codec_qos *qos); + int (*get_metadata)(const struct media_codec *codec, const void *config_data, + uint8_t *meta, size_t meta_max_size); + void (*free_config_data)(const struct media_codec *codec, void *config_data); /** qsort comparison sorting caps in order of preference for the codec. * Used in codec switching to select best remote endpoints. @@ -264,4 +269,44 @@ const void *caps, size_t caps_size, const struct media_codec_audio_info *info, const struct spa_dict *global_settings); +struct __attribute__((packed)) ltv { + uint8_t len; + uint8_t type; + uint8_t value; +}; + +struct ltv_writer { + void *buf; + uint16_t size; + size_t max_size; +}; + +#define LTV_WRITER(ptr, max) ((struct ltv_writer) { .buf = (ptr), .max_size = (max) }) + +void ltv_writer_data(struct ltv_writer *w, uint8_t type, void* value, size_t len); +void ltv_writer_uint8(struct ltv_writer *w, uint8_t type, uint8_t v); +void ltv_writer_uint16(struct ltv_writer *w, uint8_t type, uint16_t value); +void ltv_writer_uint32(struct ltv_writer *w, uint8_t type, uint32_t value); +int ltv_writer_end(struct ltv_writer *w); + +static inline const struct ltv *ltv_next(const void **data, size_t *size) +{ + const struct ltv *ltv; + + if (*size == 0) { + *data = NULL; + return NULL; + } + if (*size < sizeof(struct ltv)) + return NULL; + + ltv = *data; + if (ltv->len >= *size) + return NULL; + + *data = SPA_PTROFF(*data, ltv->len + 1, void); + *size -= ltv->len + 1; + return ltv; +} + #endif
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/plugins/bluez5/media-source.c -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/plugins/bluez5/media-source.c
Changed
@@ -613,6 +613,10 @@ { int res; + if (this->transport && this->transport->iso_io) + if (spa_bt_iso_io_recv_errqueue(this->transport->iso_io) == 0) + return; + /* iso-io/media-sink use these for TX latency. * Someone else should be reading them, so drop * only after yielding.
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/plugins/bluez5/modemmanager.c -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/plugins/bluez5/modemmanager.c
Changed
@@ -10,6 +10,10 @@ #include "modemmanager.h" +SPA_LOG_TOPIC_DEFINE_STATIC(log_topic, "spa.bluez5.modemmanager"); +#undef SPA_LOG_TOPIC_DEFAULT +#define SPA_LOG_TOPIC_DEFAULT &log_topic + #define DBUS_INTERFACE_OBJECTMANAGER "org.freedesktop.DBus.ObjectManager" struct modem { @@ -412,6 +416,26 @@ } } +static bool mm_get_managed_objects(struct impl *this) +{ + spa_autoptr(DBusMessage) m = dbus_message_new_method_call(MM_DBUS_SERVICE, + "/org/freedesktop/ModemManager1", + DBUS_INTERFACE_OBJECTMANAGER, + "GetManagedObjects"); + if (m == NULL) + return false; + + dbus_message_set_auto_start(m, false); + + this->pending = send_with_reply(this->conn, m, mm_get_managed_objects_reply, this); + if (!this->pending) { + spa_log_error(this->log, "dbus call failure"); + return false; + } + + return true; +} + static void call_free(struct call *call) { spa_list_remove(&call->link); @@ -488,8 +512,12 @@ mm_clean_modem(this); } - if (new_owner && *new_owner) + if (new_owner && *new_owner) { spa_log_debug(this->log, "ModemManager daemon appeared (%s)", new_owner); + + if (!mm_get_managed_objects(this)) + goto finish; + } } } else if (dbus_message_is_signal(m, DBUS_INTERFACE_OBJECTMANAGER, DBUS_SIGNAL_INTERFACES_ADDED)) { DBusMessageIter arg_i; @@ -1080,20 +1108,8 @@ if (add_filters(this) < 0) return NULL; - spa_autoptr(DBusMessage) m = dbus_message_new_method_call(MM_DBUS_SERVICE, - "/org/freedesktop/ModemManager1", - DBUS_INTERFACE_OBJECTMANAGER, - "GetManagedObjects"); - if (m == NULL) - return NULL; - - dbus_message_set_auto_start(m, false); - - this->pending = send_with_reply(this->conn, m, mm_get_managed_objects_reply, this); - if (!this->pending) { - spa_log_error(this->log, "dbus call failure"); + if (!mm_get_managed_objects(this)) return NULL; - } return spa_steal_ptr(this); }
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/plugins/bluez5/player.c -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/plugins/bluez5/player.c
Changed
@@ -247,11 +247,12 @@ struct spa_bt_player *spa_bt_player_new(void *dbus_connection, struct spa_log *log) { - struct impl *impl; - const DBusObjectPathVTable vtable = { + static const DBusObjectPathVTable vtable = { .message_function = player_handler, }; + struct impl *impl; + spa_log_topic_init(log, &log_topic); impl = calloc(1, sizeof(struct impl));
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/plugins/bluez5/telephony.c -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/plugins/bluez5/telephony.c
Changed
@@ -1148,20 +1148,23 @@ { struct agimpl *agimpl = SPA_CONTAINER_OF(ag, struct agimpl, this); struct impl *impl = SPA_CONTAINER_OF(agimpl->this.telephony, struct impl, this); - char *path; - const DBusObjectPathVTable vtable = { + static const DBusObjectPathVTable vtable = { .message_function = ag_handler, }; - path = spa_aprintf (PW_TELEPHONY_OBJECT_PATH "/ag%d", agimpl->this.id); + if (agimpl->path) + return -EBUSY; + + spa_autofree char *path = spa_aprintf(PW_TELEPHONY_OBJECT_PATH "/ag%d", agimpl->this.id); /* register object */ if (!dbus_connection_register_object_path(impl->conn, path, &vtable, agimpl)) { spa_log_error(impl->log, "failed to register %s", path); return -EIO; } - agimpl->path = strdup(path); + + agimpl->path = spa_steal_ptr(path); /* notify on ObjectManager of the Manager object */ { @@ -1174,7 +1177,7 @@ dbus_iter_append_ag_interfaces(&iter, ag); if (!dbus_connection_send(impl->conn, msg, NULL)) { - spa_log_error(impl->log, "failed to send InterfacesAdded for %s", path); + spa_log_error(impl->log, "failed to send InterfacesAdded for %s", agimpl->path); telephony_ag_unregister(ag); return -EIO; } @@ -1188,18 +1191,18 @@ msg = dbus_message_new_signal(impl->path, OFONO_MANAGER_IFACE, "ModemAdded"); dbus_message_iter_init_append(msg, &iter); - dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &agimpl->path); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &props_dict); dbus_message_iter_close_container(&iter, &props_dict); if (!dbus_connection_send(impl->conn, msg, NULL)) { - spa_log_error(impl->log, "failed to send ModemAdded for %s", path); + spa_log_error(impl->log, "failed to send ModemAdded for %s", agimpl->path); telephony_ag_unregister(ag); return -EIO; } } - spa_log_debug(impl->log, "registered AudioGateway: %s", path); + spa_log_debug(impl->log, "registered AudioGateway: %s", agimpl->path); return 0; } @@ -1646,20 +1649,23 @@ struct callimpl *callimpl = SPA_CONTAINER_OF(call, struct callimpl, this); struct agimpl *agimpl = SPA_CONTAINER_OF(callimpl->this.ag, struct agimpl, this); struct impl *impl = SPA_CONTAINER_OF(agimpl->this.telephony, struct impl, this); - char *path; - const DBusObjectPathVTable vtable = { + static const DBusObjectPathVTable vtable = { .message_function = call_handler, }; - path = spa_aprintf ("%s/call%d", agimpl->path, callimpl->this.id); + if (callimpl->path) + return -EBUSY; + + spa_autofree char *path = spa_aprintf("%s/call%d", agimpl->path, callimpl->this.id); /* register object */ if (!dbus_connection_register_object_path(impl->conn, path, &vtable, callimpl)) { spa_log_error(impl->log, "failed to register %s", path); return -EIO; } - callimpl->path = strdup(path); + + callimpl->path = spa_steal_ptr(path); /* notify on ObjectManager of the AudioGateway object */ { @@ -1671,7 +1677,7 @@ DBUS_INTERFACE_OBJECT_MANAGER, "InterfacesAdded"); dbus_message_iter_init_append(msg, &iter); - dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &callimpl->path); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sa{sv}}", &dict); dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry); dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &interface); @@ -1680,7 +1686,7 @@ dbus_message_iter_close_container(&iter, &dict); if (!dbus_connection_send(impl->conn, msg, NULL)) { - spa_log_error(impl->log, "failed to send InterfacesAdded for %s", path); + spa_log_error(impl->log, "failed to send InterfacesAdded for %s", callimpl->path); telephony_call_unregister(call); return -EIO; } @@ -1695,11 +1701,11 @@ OFONO_VOICE_CALL_MANAGER_IFACE, "CallAdded"); dbus_message_iter_init_append(msg, &iter); - dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &callimpl->path); dbus_iter_append_call_properties(&iter, call, true); if (!dbus_connection_send(impl->conn, msg, NULL)) { - spa_log_error(impl->log, "failed to send CallAdded for %s", path); + spa_log_error(impl->log, "failed to send CallAdded for %s", callimpl->path); telephony_call_unregister(call); return -EIO; } @@ -1707,7 +1713,7 @@ telephony_call_commit_properties(call); - spa_log_debug(impl->log, "registered Call: %s", path); + spa_log_debug(impl->log, "registered Call: %s", callimpl->path); return 0; }
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/plugins/filter-graph/plugin_builtin.c -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/plugins/filter-graph/plugin_builtin.c
Changed
@@ -704,16 +704,93 @@ struct convolver *conv; }; +struct finfo { +#define TYPE_INVALID 0 +#define TYPE_SNDFILE 1 +#define TYPE_HILBERT 2 +#define TYPE_DIRAC 3 +#define TYPE_IR 4 + uint32_t type; + + const char *filename; #ifdef HAVE_SNDFILE -static float *read_samples_from_sf(SNDFILE *f, const SF_INFO *info, float gain, int delay, - int offset, int length, int channel, long unsigned *rate, int *n_samples) { - float *samples; - int i, n; + SF_INFO info; + SNDFILE *fs; +#endif + int channels; + int def_frames; + int max_frames; + float latency; /* latency relative to number of samples */ + uint32_t rate; + const char *error; +}; + +static int finfo_open(const char *filename, struct finfo *info, int rate) +{ + info->filename = filename; + if (spa_strstartswith(filename, "/hilbert")) { + info->channels = 1; + info->rate = rate; + info->def_frames = 64; + info->max_frames = INT_MAX; + info->type = TYPE_HILBERT; + info->latency = 0.5f; + } + else if (spa_strstartswith(filename, "/dirac")) { + info->channels = 1; + info->def_frames = 1; + info->max_frames = 1; + info->rate = rate; + info->type = TYPE_DIRAC; + info->latency = 0.0f; + } + else if (spa_strstartswith(filename, "/ir:")) { + struct spa_json it1; + float v; + int rate; + info->channels = 1; + info->type = TYPE_IR; + info->def_frames = 0; + if (spa_json_begin_array_relax(&it0, filename+4, strlen(filename+4)) <= 0) + return -EINVAL; + if (spa_json_get_int(&it0, &rate) <= 0) + return -EINVAL; + info->rate = rate; + while (spa_json_get_float(&it0, &v) > 0) + info->def_frames++; + info->max_frames = info->def_frames; + info->latency = 0.0f; + } else { +#ifdef HAVE_SNDFILE + info->fs = sf_open(filename, SFM_READ, &info->info); + if (info->fs == NULL) { + info->error = sf_strerror(NULL); + return -ENOENT; + } + info->channels = info->info.channels; + info->def_frames = info->info.frames; + info->max_frames = info->def_frames; + info->rate = info->info.samplerate; + info->type = TYPE_SNDFILE; + info->latency = 0.0f; +#else + info->error = "compiled without sndfile support, can't load samples"; + return -ENOTSUP; +#endif + } + return 0; +} + +static float *finfo_read_samples(struct plugin *pl, struct finfo *info, float gain, int delay, + int offset, int length, int channel, long unsigned *rate, int *n_samples, int *latency) +{ + float *samples, v; + int i, n, h; if (length <= 0) - length = info->frames; + length = info->def_frames; else - length = SPA_MIN(length, info->frames); + length = SPA_MIN(length, info->max_frames); length -= SPA_MIN(offset, length); @@ -725,127 +802,106 @@ if (samples == NULL) return NULL; - if (offset > 0) - sf_seek(f, offset, SEEK_SET); - sf_readf_float(f, samples + (delay * info->channels), length); - channel = channel % info->channels; - for (i = 0; i < n; i++) - samplesi = samplesinfo->channels * i + channel * gain; - + switch (info->type) { + case TYPE_SNDFILE: +#ifdef HAVE_SNDFILE + if (offset > 0) + sf_seek(info->fs, offset, SEEK_SET); + sf_readf_float(info->fs, samples + (delay * info->channels), length); + for (i = 0; i < n; i++) + samplesi = samplesinfo->channels * i + channel * gain; +#endif + break; + case TYPE_HILBERT: + gain *= 2 / (float)M_PI; + h = length / 2; + for (i = 1; i < h; i += 2) { + v = (gain / i) * (0.43f + 0.57f * cosf(i * (float)M_PI / h)); + samplesdelay + h + i = -v; + samplesdelay + h - i = v; + } + spa_log_info(pl->log, "created hilbert function length %d", length); + break; + case TYPE_DIRAC: + samplesdelay = gain; + spa_log_info(pl->log, "created dirac function"); + break; + case TYPE_IR: + { + struct spa_json it1; + float v; + if (spa_json_begin_array_relax(&it0, info->filename+4, strlen(info->filename+4)) <= 0) + return NULL; + if (spa_json_get_int(&it0, &h) <= 0) + return NULL; + info->rate = h; + i = 0; + while (spa_json_get_float(&it0, &v) > 0) { + samplesdelay + i = v * gain; + i++; + } + break; + } + } *n_samples = n; - *rate = info->samplerate; + *rate = info->rate; + *latency = (int) (n * info->latency); return samples; } -#endif -static float *read_closest(struct plugin *pl, char **filenames, float gain, float delay_sec, int offset, - int length, int channel, long unsigned *rate, int *n_samples) + +static void finfo_close(struct finfo *info) { #ifdef HAVE_SNDFILE - SF_INFO infosMAX_RATES; - SNDFILE *fsMAX_RATES; - - spa_zero(infos); - spa_zero(fs); + if (info->type == TYPE_SNDFILE && info->fs != NULL) + sf_close(info->fs); +#endif +} - int diff = INT_MAX; - uint32_t best = 0, i; +static float *read_closest(struct plugin *pl, char **filenames, float gain, float delay_sec, int offset, + int length, int channel, long unsigned *rate, int *n_samples, int *latency) +{ + struct finfo finfoMAX_RATES; + int res, diff = INT_MAX; + uint32_t best = SPA_ID_INVALID, i; float *samples = NULL; + spa_zero(finfo); + for (i = 0; i < MAX_RATES && filenamesi && filenamesi0; i++) { - fsi = sf_open(filenamesi, SFM_READ, &infosi); - if (fsi == NULL) + res = finfo_open(filenamesi, &finfoi, *rate); + if (res < 0) continue; - if (labs((long)infosi.samplerate - (long)*rate) < diff) { + if (labs((long)finfoi.rate - (long)*rate) < diff) { best = i; - diff = labs((long)infosi.samplerate - (long)*rate); - spa_log_debug(pl->log, "new closest match: %d", infosi.samplerate); + diff = labs((long)finfoi.rate - (long)*rate); + spa_log_debug(pl->log, "new closest match: %d", finfoi.rate); } } - if (fsbest != NULL) { - spa_log_info(pl->log, "loading best rate:%u %s", infosbest.samplerate, filenamesbest); - samples = read_samples_from_sf(fsbest, &infosbest, gain, - (int) (delay_sec * infosbest.samplerate), offset, length, - channel, rate, n_samples); + if (best != SPA_ID_INVALID) { + spa_log_info(pl->log, "loading best rate:%u %s", finfobest.rate, filenamesbest); + samples = finfo_read_samples(pl, &finfobest, gain, + (int) (delay_sec * finfobest.rate), offset, length, + channel, rate, n_samples, latency); } else { char bufPATH_MAX; spa_log_error(pl->log, "Can't open any sample file (CWD %s):", getcwd(buf, sizeof(buf))); + for (i = 0; i < MAX_RATES && filenamesi && filenamesi0; i++) { - fsi = sf_open(filenamesi, SFM_READ, &infosi); - if (fsi == NULL) - spa_log_error(pl->log, " failed file %s: %s", filenamesi, sf_strerror(fsi)); + res = finfo_open(filenamesi, &finfoi, *rate); + if (res < 0) + spa_log_error(pl->log, " failed file %s: %s", filenamesi, finfoi.error); else spa_log_warn(pl->log, " unexpectedly opened file %s", filenamesi); } } for (i = 0; i < MAX_RATES; i++) - if (fsi != NULL) - sf_close(fsi); - - return samples; -#else - spa_log_error(pl->log, "compiled without sndfile support, can't load samples: " - "using dirac impulse"); - float *samples = calloc(1, sizeof(float)); - samples0 = gain; - *n_samples = 1; - return samples; -#endif -} - -static float *create_hilbert(struct plugin *pl, const char *filename, float gain, int rate, float delay_sec, int offset, - int length, int *n_samples) -{ - float *samples, v; - int i, n, h; - int delay = (int) (delay_sec * rate); - - if (length <= 0) - length = 64; - - length -= SPA_MIN(offset, length); - - n = delay + length; - if (n == 0) - return NULL; + finfo_close(&finfoi); - samples = calloc(n, sizeof(float)); - if (samples == NULL) - return NULL; - - gain *= 2 / (float)M_PI; - h = length / 2; - for (i = 1; i < h; i += 2) { - v = (gain / i) * (0.43f + 0.57f * cosf(i * (float)M_PI / h)); - samplesdelay + h + i = -v; - samplesdelay + h - i = v; - } - *n_samples = n; - spa_log_info(pl->log, "created hilbert function"); - return samples; -} - -static float *create_dirac(struct plugin *pl, const char *filename, float gain, int rate, float delay_sec, int offset, - int length, int *n_samples) -{ - float *samples; - int delay = (int) (delay_sec * rate); - int n; - - n = delay + 1; - - samples = calloc(n, sizeof(float)); - if (samples == NULL) - return NULL; - - samplesdelay = gain; - - spa_log_info(pl->log, "created dirac function"); - *n_samples = n; return samples; } @@ -936,10 +992,10 @@ uint32_t i = 0; struct spa_json it2; const char *val; - char key256, v256; + char key256; char *filenamesMAX_RATES = { 0 }; int blocksize = 0, tailsize = 0; - int resample_quality = RESAMPLE_DEFAULT_QUALITY; + int resample_quality = RESAMPLE_DEFAULT_QUALITY, def_latency; float gain = 1.0f, delay = 0.0f, latency = -1.0f; unsigned long rate; @@ -985,17 +1041,20 @@ else if (spa_streq(key, "filename")) { if (spa_json_is_array(val, len)) { spa_json_enter(&it0, &it1); - while (spa_json_get_string(&it1, v, sizeof(v)) > 0 && + while ((len = spa_json_next(&it1, &val)) > 0 && i < SPA_N_ELEMENTS(filenames)) { - filenamesi = strdup(v); + filenamesi = malloc(len+1); + if (filenamesi == NULL) + return NULL; + spa_json_parse_stringn(val, len, filenamesi, len+1); i++; } } - else if (spa_json_parse_stringn(val, len, v, sizeof(v)) <= 0) { - spa_log_error(pl->log, "convolver:filename requires a string or an array"); - return NULL; - } else { - filenames0 = strdup(v); + else { + filenames0 = malloc(len+1); + if (filenames0 == NULL) + return NULL; + spa_json_parse_stringn(val, len, filenames0, len+1); } } else if (spa_streq(key, "offset")) { @@ -1042,21 +1101,12 @@ if (offset < 0) offset = 0; - if (spa_streq(filenames0, "/hilbert")) { - samples = create_hilbert(pl, filenames0, gain, SampleRate, delay, offset, - length, &n_samples); - } else if (spa_streq(filenames0, "/dirac")) { - samples = create_dirac(pl, filenames0, gain, SampleRate, delay, offset, - length, &n_samples); - } else { - rate = SampleRate; - samples = read_closest(pl, filenames, gain, delay, offset, - length, channel, &rate, &n_samples); - if (samples != NULL && rate != SampleRate) { - samples = resample_buffer(pl, samples, &n_samples, - rate, SampleRate, resample_quality); - } - } + rate = SampleRate; + samples = read_closest(pl, filenames, gain, delay, offset, + length, channel, &rate, &n_samples, &def_latency); + if (samples != NULL && rate != SampleRate) + samples = resample_buffer(pl, samples, &n_samples, + rate, SampleRate, resample_quality); for (i = 0; i < MAX_RATES; i++) if (filenamesi) @@ -1072,8 +1122,8 @@ if (tailsize <= 0) tailsize = SPA_CLAMP(4096, blocksize, 32768); - spa_log_info(pl->log, "using n_samples:%u %d:%d blocksize delay:%f", n_samples, - blocksize, tailsize, delay); + spa_log_info(pl->log, "using n_samples:%u %d:%d blocksize delay:%f def-latency:%d", n_samples, + blocksize, tailsize, delay, def_latency); impl = calloc(1, sizeof(*impl)); if (impl == NULL) @@ -1089,7 +1139,7 @@ goto error; if (latency < 0.0f) - impl->latency = n_samples; + impl->latency = def_latency; else impl->latency = latency * impl->rate;
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/plugins/libcamera/libcamera-source.cpp -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/plugins/libcamera/libcamera-source.cpp
Changed
@@ -71,7 +71,6 @@ struct spa_fraction rate = {}; StreamConfiguration streamConfig; - spa_data_type memtype = SPA_DATA_Invalid; uint32_t buffers_blocks = 1; struct buffer buffersMAX_BUFFERS; @@ -449,8 +448,7 @@ uint32_t type, uint32_t subtype, uint32_t format) { for (const auto& f : format_info) { - if (f.media_type == type && f.media_subtype == subtype - && (f.format == SPA_VIDEO_FORMAT_UNKNOWN || f.format == format)) + if (f.media_type == type && f.media_subtype == subtype && f.format == format) return &f; } @@ -667,7 +665,6 @@ const struct format_info *info = nullptr; uint32_t video_format; struct spa_rectangle *size = nullptr; - struct spa_fraction *framerate = nullptr; CameraConfiguration::Status validation; int res; @@ -675,18 +672,15 @@ case SPA_MEDIA_SUBTYPE_raw: video_format = format->info.raw.format; size = &format->info.raw.size; - framerate = &format->info.raw.framerate; break; case SPA_MEDIA_SUBTYPE_mjpg: case SPA_MEDIA_SUBTYPE_jpeg: video_format = SPA_VIDEO_FORMAT_ENCODED; size = &format->info.mjpg.size; - framerate = &format->info.mjpg.framerate; break; case SPA_MEDIA_SUBTYPE_h264: video_format = SPA_VIDEO_FORMAT_ENCODED; size = &format->info.h264.size; - framerate = &format->info.h264.framerate; break; default: video_format = SPA_VIDEO_FORMAT_ENCODED; @@ -695,7 +689,7 @@ info = find_format_info_by_media_type(format->media_type, format->media_subtype, video_format); - if (info == nullptr || size == nullptr || framerate == nullptr) { + if (info == nullptr || size == nullptr) { spa_log_error(impl->log, "unknown media type %d %d %d", format->media_type, format->media_subtype, video_format); return -EINVAL; @@ -1210,21 +1204,17 @@ const std::vector<std::unique_ptr<FrameBuffer>> &bufs = impl->allocator.buffers(stream); - if (n_buffers > 0) { - if (bufs.size() != n_buffers) - return -EINVAL; + if (n_buffers > 0 && bufs.size() != n_buffers) + return -EINVAL; - spa_data *d = buffers0->datas; + const auto choose_memtype = (uint32_t t) { + if (t != SPA_ID_INVALID && t & (1u << SPA_DATA_DmaBuf)) + return SPA_DATA_DmaBuf; + if (t & (1u << SPA_DATA_MemFd)) + return SPA_DATA_MemFd; - if (d0.type != SPA_ID_INVALID && d0.type & (1u << SPA_DATA_DmaBuf)) { - port->memtype = SPA_DATA_DmaBuf; - } else if (d0.type & (1u << SPA_DATA_MemFd)) { - port->memtype = SPA_DATA_MemFd; - } else { - spa_log_error(impl->log, "can't use buffers of type %d", d0.type); - return -EINVAL; - } - } + return SPA_DATA_Invalid; + }; for (uint32_t i = 0; i < n_buffers; i++) { struct buffer *b; @@ -1254,9 +1244,17 @@ spa_data *d = buffersi->datas; for(uint32_t j = 0; j < buffersi->n_datas; ++j) { - dj.type = port->memtype; + const auto memtype = choose_memtype(dj.type); + if (memtype == SPA_DATA_Invalid) { + spa_log_error(impl->log, "can't use buffers of type %" PRIu32, dj.type); + return -EINVAL; + } + + dj.type = memtype; dj.flags = SPA_DATA_FLAG_READABLE; + dj.fd = -1; dj.mapoffset = 0; + dj.data = nullptr; dj.chunk->stride = port->streamConfig.stride; dj.chunk->flags = 0; /* Update parameters according to the plane information */ @@ -1286,15 +1284,16 @@ dj.chunk->size = port->streamConfig.frameSize; } - if (port->memtype == SPA_DATA_DmaBuf || - port->memtype == SPA_DATA_MemFd) { + switch (memtype) { + case SPA_DATA_DmaBuf: + case SPA_DATA_MemFd: dj.flags |= SPA_DATA_FLAG_MAPPABLE; dj.fd = planesj.fd.get(); spa_log_debug(impl->log, "Got fd = %" PRId64 " for buffer: #%d", dj.fd, i); - dj.data = nullptr; - } else { - spa_log_error(impl->log, "invalid buffer type"); - return -EIO; + break; + default: + spa_assert_not_reached(); + break; } } } @@ -1420,20 +1419,17 @@ spa_pod_builder_add(builder, SPA_FORMAT_VIDEO_format, SPA_POD_Id(port->current_format->info.raw.format), SPA_FORMAT_VIDEO_size, SPA_POD_Rectangle(&port->current_format->info.raw.size), - SPA_FORMAT_VIDEO_framerate, SPA_POD_Fraction(&port->current_format->info.raw.framerate), 0); break; case SPA_MEDIA_SUBTYPE_mjpg: case SPA_MEDIA_SUBTYPE_jpeg: spa_pod_builder_add(builder, SPA_FORMAT_VIDEO_size, SPA_POD_Rectangle(&port->current_format->info.mjpg.size), - SPA_FORMAT_VIDEO_framerate, SPA_POD_Fraction(&port->current_format->info.mjpg.framerate), 0); break; case SPA_MEDIA_SUBTYPE_h264: spa_pod_builder_add(builder, SPA_FORMAT_VIDEO_size, SPA_POD_Rectangle(&port->current_format->info.h264.size), - SPA_FORMAT_VIDEO_framerate, SPA_POD_Fraction(&port->current_format->info.h264.framerate), 0); break; default:
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/plugins/support/loop.c -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/plugins/support/loop.c
Changed
@@ -9,7 +9,6 @@ #include <stdlib.h> #include <stdio.h> #include <pthread.h> -#include <threads.h> #include <stdatomic.h> #include <spa/support/loop.h>
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/plugins/videoconvert/videoadapter.c -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/plugins/videoconvert/videoadapter.c
Changed
@@ -25,6 +25,7 @@ #include <spa/param/video/format-utils.h> #include <spa/param/latency-utils.h> #include <spa/param/tag-utils.h> +#include <spa/param/peer-utils.h> #include <spa/debug/format.h> #include <spa/debug/pod.h> #include <spa/debug/log.h> @@ -900,7 +901,6 @@ switch (id) { case SPA_IO_Position: this->io_position = data; - this->recheck_format = true; break; default: break; @@ -920,7 +920,7 @@ uint8_t buffer4096; spa_auto(spa_pod_dynamic_builder) b = { 0 }; uint32_t state = 0; - struct spa_pod *param; + struct spa_pod *param, *p, *str; struct spa_pod_frame f; int res; @@ -934,7 +934,6 @@ spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096); spa_pod_builder_push_struct(&b.b, &f); - while (true) { res = node_port_enum_params_sync(impl, impl->follower, impl->direction, 0, @@ -951,10 +950,24 @@ spa_pod_simplify(&b.b, ¶m, param); spa_debug_log_pod(impl->log, SPA_LOG_LEVEL_DEBUG, 0, NULL, param); + str = spa_pod_copy(param); + spa_pod_dynamic_builder_clean(&b); + + spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096); + spa_peer_param_build_start(&b.b, &f, SPA_PARAM_PeerEnumFormat); + SPA_POD_STRUCT_FOREACH(str, p) { + spa_debug_log_pod(impl->log, SPA_LOG_LEVEL_DEBUG, 0, NULL, p); + spa_peer_param_build_add_param(&b.b, 1, p); + } + param = spa_peer_param_build_end(&b.b, &f); + + spa_debug_log_pod(impl->log, SPA_LOG_LEVEL_DEBUG, 0, NULL, param); + res = spa_node_port_set_param(impl->target, SPA_DIRECTION_REVERSE(impl->direction), 0, - SPA_PARAM_PeerFormats, 0, param); + SPA_PARAM_PeerEnumFormat, 0, param); + free(str); impl->recheck_format = false; spa_log_debug(impl->log, "done updating peer formats: %d", res);
View file
_service:download_files:pipewire-1.5.83.tar.bz2/spa/plugins/videoconvert/videoconvert-ffmpeg.c -> _service:download_files:pipewire-1.5.84.tar.bz2/spa/plugins/videoconvert/videoconvert-ffmpeg.c
Changed
@@ -31,6 +31,7 @@ #include <spa/param/param.h> #include <spa/param/latency-utils.h> #include <spa/param/tag-utils.h> +#include <spa/param/peer-utils.h> #include <spa/pod/filter.h> #include <spa/pod/dynamic.h> #include <spa/debug/types.h> @@ -77,15 +78,16 @@ uint64_t info_all; struct spa_port_info info; -#define IDX_EnumFormat 0 -#define IDX_Meta 1 -#define IDX_IO 2 -#define IDX_Format 3 -#define IDX_Buffers 4 -#define IDX_Latency 5 -#define IDX_Tag 6 -#define IDX_PeerFormats 7 -#define N_PORT_PARAMS 8 +#define IDX_EnumFormat 0 +#define IDX_Meta 1 +#define IDX_IO 2 +#define IDX_Format 3 +#define IDX_Buffers 4 +#define IDX_Latency 5 +#define IDX_Tag 6 +#define IDX_PeerEnumFormat 7 +#define IDX_PeerCapability 8 +#define N_PORT_PARAMS 9 struct spa_param_info paramsN_PORT_PARAMS; struct spa_pod *peer_format_pod; @@ -485,7 +487,8 @@ port->paramsIDX_Buffers = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0); port->paramsIDX_Latency = SPA_PARAM_INFO(SPA_PARAM_Latency, SPA_PARAM_INFO_READWRITE); port->paramsIDX_Tag = SPA_PARAM_INFO(SPA_PARAM_Tag, SPA_PARAM_INFO_READWRITE); - port->paramsIDX_PeerFormats = SPA_PARAM_INFO(SPA_PARAM_PeerFormats, SPA_PARAM_INFO_WRITE); + port->paramsIDX_PeerEnumFormat = SPA_PARAM_INFO(SPA_PARAM_PeerEnumFormat, SPA_PARAM_INFO_WRITE); + port->paramsIDX_PeerCapability = SPA_PARAM_INFO(SPA_PARAM_PeerCapability, SPA_PARAM_INFO_WRITE); port->info.params = port->params; port->info.n_params = N_PORT_PARAMS; @@ -1599,7 +1602,7 @@ return 0; } -static int port_param_peer_formats(struct impl *this, struct port *port, uint32_t index, +static int port_param_peer_enum_format(struct impl *this, struct port *port, uint32_t index, const struct spa_pod **param, struct spa_pod_builder *b) { if (index >= port->n_peer_formats) @@ -1664,8 +1667,8 @@ case SPA_PARAM_Tag: res = port_param_tag(this, port, id, result.index, ¶m, &b); break; - case SPA_PARAM_PeerFormats: - res = port_param_peer_formats(this, port, result.index, ¶m, &b); + case SPA_PARAM_PeerEnumFormat: + res = port_param_peer_enum_format(this, port, result.index, ¶m, &b); break; default: return -ENOENT; @@ -1980,7 +1983,7 @@ } -static int port_set_peer_formats(void *object, +static int port_set_peer_enum_format(void *object, enum spa_direction direction, uint32_t port_id, uint32_t flags, @@ -1990,14 +1993,15 @@ struct port *port, *oport; int res = 0; uint32_t i; - const struct spa_pod *format; enum spa_direction other = SPA_DIRECTION_REVERSE(direction); static uint32_t subtypes = { SPA_MEDIA_SUBTYPE_raw, SPA_MEDIA_SUBTYPE_mjpg, SPA_MEDIA_SUBTYPE_h264 }; + struct spa_peer_param_info info; + void *state = NULL; - spa_return_val_if_fail(spa_pod_is_struct(formats), -EINVAL); + spa_return_val_if_fail(spa_pod_is_object(formats), -EINVAL); port = GET_PORT(this, direction, port_id); oport = GET_PORT(this, other, port_id); @@ -2013,9 +2017,10 @@ port->peer_format_pod = spa_pod_copy(formats); for (i = 0; i < SPA_N_ELEMENTS(subtypes); i++) { - SPA_POD_STRUCT_FOREACH(port->peer_format_pod, format) { + state = NULL; + while (spa_peer_param_parse(formats, &info, sizeof(info), &state) > 0) { uint32_t media_type, media_subtype; - if (!spa_format_parse(format, &media_type, &media_subtype) || + if (!spa_format_parse(info.param, &media_type, &media_subtype) || media_type != SPA_MEDIA_TYPE_video || media_subtype != subtypesi) continue; @@ -2024,13 +2029,14 @@ } port->peer_formats = calloc(count, sizeof(struct spa_pod *)); for (i = 0; i < SPA_N_ELEMENTS(subtypes); i++) { - SPA_POD_STRUCT_FOREACH(port->peer_format_pod, format) { + state = NULL; + while (spa_peer_param_parse(port->peer_format_pod, &info, sizeof(info), &state) > 0) { uint32_t media_type, media_subtype; - if (!spa_format_parse(format, &media_type, &media_subtype) || + if (!spa_format_parse(info.param, &media_type, &media_subtype) || media_type != SPA_MEDIA_TYPE_video || media_subtype != subtypesi) continue; - port->peer_formatsport->n_peer_formats++ = format; + port->peer_formatsport->n_peer_formats++ = info.param; } } } @@ -2038,7 +2044,7 @@ oport->paramsIDX_EnumFormat.user++; port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS; port->paramsIDX_EnumFormat.user++; - port->paramsIDX_PeerFormats.user++; + port->paramsIDX_PeerEnumFormat.user++; return res; } @@ -2068,8 +2074,9 @@ case SPA_PARAM_Format: res = port_set_format(this, direction, port_id, flags, param); break; - case SPA_PARAM_PeerFormats: - res = port_set_peer_formats(this, direction, port_id, flags, param); + case SPA_PARAM_PeerEnumFormat: + res = port_set_peer_enum_format(this, direction, port_id, flags, param); + break; break; default: return -ENOENT;
View file
_service:download_files:pipewire-1.5.83.tar.bz2/src/daemon/systemd/user/pipewire-pulse.service.in -> _service:download_files:pipewire-1.5.84.tar.bz2/src/daemon/systemd/user/pipewire-pulse.service.in
Changed
@@ -17,6 +17,7 @@ ConditionUser=!root Wants=pipewire.service pipewire-session-manager.service After=pipewire.service pipewire-session-manager.service +BindsTo=pipewire.service Conflicts=pulseaudio.service Service
View file
_service:download_files:pipewire-1.5.83.tar.bz2/src/examples/video-play.c -> _service:download_files:pipewire-1.5.84.tar.bz2/src/examples/video-play.c
Changed
@@ -15,6 +15,8 @@ #include <spa/utils/result.h> #include <spa/param/video/format-utils.h> #include <spa/param/tag-utils.h> +#include <spa/param/dict-utils.h> +#include <spa/param/peer-utils.h> #include <spa/param/props.h> #include <spa/param/latency-utils.h> #include <spa/debug/format.h> @@ -270,6 +272,34 @@ } } +static void parse_peer_capability(struct data *data, const struct spa_pod *param) +{ + struct spa_peer_param_info info; + void *state = NULL; + + fprintf(stderr, "peer capability\n"); + while (spa_peer_param_parse(param, &info, sizeof(info), &state) == 1) { + struct spa_param_dict_info di; + + if (spa_param_dict_parse(info.param, &di, sizeof(di)) > 0) { + struct spa_dict dict; + struct spa_dict_item *items; + const struct spa_dict_item *it; + + if (spa_param_dict_info_parse(&di, sizeof(di), &dict, NULL) < 0) + return; + + items = alloca(sizeof(struct spa_dict_item) * dict.n_items); + if (spa_param_dict_info_parse(&di, sizeof(di), &dict, items) < 0) + return; + + spa_dict_for_each(it, &dict) + fprintf(stderr, "peer:%u %s: %s\n", info.peer_id, it->key, it->value); + + } + } +} + /* Be notified when the stream param changes. We're only looking at the * format changes. * @@ -294,8 +324,11 @@ void *d; int32_t mult, size, blocks; - if (param != NULL && id == SPA_PARAM_Tag) { - spa_debug_pod(0, NULL, param); + if (param != NULL && (id == SPA_PARAM_Tag || id == SPA_PARAM_PeerCapability)) { + if (id == SPA_PARAM_PeerCapability) + parse_peer_capability(data, param); + else + spa_debug_pod(0, NULL, param); return; } if (param != NULL && id == SPA_PARAM_Latency) {
View file
_service:download_files:pipewire-1.5.83.tar.bz2/src/examples/video-src.c -> _service:download_files:pipewire-1.5.84.tar.bz2/src/examples/video-src.c
Changed
@@ -15,6 +15,7 @@ #include <spa/param/video/format-utils.h> #include <spa/param/tag-utils.h> +#include <spa/param/dict-utils.h> #include <spa/debug/pod.h> #include <spa/debug/format.h> @@ -219,7 +220,7 @@ const struct spa_pod *params5; uint32_t n_params = 0; - if (param != NULL && id == SPA_PARAM_Tag) { + if (param != NULL && (id == SPA_PARAM_Tag || id == SPA_PARAM_PeerCapability)) { spa_debug_pod(0, NULL, param); return; } @@ -290,7 +291,8 @@ int main(int argc, char *argv) { struct data data = { 0, }; - const struct spa_pod *params2; + const struct spa_pod *params3; + uint32_t n_params = 0; uint8_t buffer1024; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); @@ -318,7 +320,7 @@ PW_KEY_NODE_SUPPORTS_REQUEST, "1", NULL)); - params0 = spa_pod_builder_add_object(&b, + paramsn_params++ = spa_pod_builder_add_object(&b, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video), SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw), @@ -336,7 +338,13 @@ spa_tag_build_add_dict(&b, &SPA_DICT_ITEMS( SPA_DICT_ITEM("my-tag-key", "my-special-tag-value"))); - params1 = spa_tag_build_end(&b, &f); + paramsn_params++ = spa_tag_build_end(&b, &f); + } + { + paramsn_params++ = spa_param_dict_build_dict(&b, SPA_PARAM_Capability, + &SPA_DICT_ITEMS( + SPA_DICT_ITEM("my-capability-key", "my-capability-value"))); + } pw_stream_add_listener(data.stream, @@ -349,7 +357,7 @@ PW_ID_ANY, PW_STREAM_FLAG_DRIVER | PW_STREAM_FLAG_MAP_BUFFERS, - params, 2); + params, n_params); pw_main_loop_run(data.loop);
View file
_service:download_files:pipewire-1.5.83.tar.bz2/src/modules/meson.build -> _service:download_files:pipewire-1.5.84.tar.bz2/src/modules/meson.build
Changed
@@ -736,6 +736,7 @@ 'module-avb/acmp.c', 'module-avb/aecp.c', 'module-avb/aecp-aem.c', + 'module-avb/es-builder.c', 'module-avb/avdecc.c', 'module-avb/maap.c', 'module-avb/mmrp.c',
View file
_service:download_files:pipewire-1.5.83.tar.bz2/src/modules/module-avb/aecp-aem-descriptors.h -> _service:download_files:pipewire-1.5.84.tar.bz2/src/modules/module-avb/aecp-aem-descriptors.h
Changed
@@ -1,5 +1,6 @@ /* AVB support */ /* SPDX-FileCopyrightText: Copyright © 2022 Wim Taymans */ +/* SPDX-FileCopyrightText: Copyright © 2025 Alexandre Malki (alexandre.malki@kebag-logic.com) */ /* SPDX-License-Identifier: MIT */ #ifndef AVB_AECP_AEM_DESCRIPTORS_H @@ -45,6 +46,8 @@ #define AVB_AEM_DESC_SIGNAL_TRANSCODER 0x0023 #define AVB_AEM_DESC_CLOCK_DOMAIN 0x0024 #define AVB_AEM_DESC_CONTROL_BLOCK 0x0025 +/** IEEE 1722.1-2021 Table-7 has up to descriptor 0x0029, reserved for future */ +#define AVB_AEM_DESC_LAST_RESERVED_17221 0x0029 #define AVB_AEM_DESC_INVALID 0xffff struct avb_aem_desc_entity {
View file
_service:download_files:pipewire-1.5.83.tar.bz2/src/modules/module-avb/descriptors.h -> _service:download_files:pipewire-1.5.84.tar.bz2/src/modules/module-avb/descriptors.h
Changed
@@ -1,15 +1,33 @@ /* PipeWire */ /* SPDX-FileCopyrightText: Copyright © 2022 Wim Taymans */ +/* SPDX-FileCopyrightText: Copyright © 2025 Alexandre Malki (alexandre.malki@kebag-logic.com) */ /* SPDX-License-Identifier: MIT */ #include "adp.h" #include "aecp-aem.h" #include "aecp-aem-descriptors.h" +#include "es-builder.h" #include "internal.h" +/** + * \todo This whole code needs to be re-factore, + * configuring the entity using such a "HARDCODED" + * header would does not allow an easy way to + * adjust parameters. + * + * Especially for the people involved in the project + * and do not have the programming skills to modify + * this file. + * + * \proposition use a YANG model directly derived from this + * or use the YAML for simplicity. + * + * Having the YANG would allow directly to know the + * capabilites/limits of the protocol + */ static inline void init_descriptors(struct server *server) { - server_add_descriptor(server, AVB_AEM_DESC_STRINGS, 0, + es_builder_add_descriptor(server, AVB_AEM_DESC_STRINGS, 0, sizeof(struct avb_aem_desc_strings), &(struct avb_aem_desc_strings) { @@ -17,7 +35,7 @@ .string_1 = "Configuration 1", .string_2 = "Wim Taymans", }); - server_add_descriptor(server, AVB_AEM_DESC_LOCALE, 0, + es_builder_add_descriptor(server, AVB_AEM_DESC_LOCALE, 0, sizeof(struct avb_aem_desc_locale), &(struct avb_aem_desc_locale) { @@ -25,7 +43,7 @@ .number_of_strings = htons(1), .base_strings = htons(0) }); - server_add_descriptor(server, AVB_AEM_DESC_ENTITY, 0, + es_builder_add_descriptor(server, AVB_AEM_DESC_ENTITY, 0, sizeof(struct avb_aem_desc_entity), &(struct avb_aem_desc_entity) { @@ -81,7 +99,7 @@ { htons(AVB_AEM_DESC_CLOCK_DOMAIN), htons(1) } } }; - server_add_descriptor(server, AVB_AEM_DESC_CONFIGURATION, 0, + es_builder_add_descriptor(server, AVB_AEM_DESC_CONFIGURATION, 0, sizeof(config), &config); struct { @@ -139,7 +157,7 @@ { .pull_frequency = htonl(192000) }, } }; - server_add_descriptor(server, AVB_AEM_DESC_AUDIO_UNIT, 0, + es_builder_add_descriptor(server, AVB_AEM_DESC_AUDIO_UNIT, 0, sizeof(audio_unit), &audio_unit); struct { @@ -178,7 +196,7 @@ htobe64(0x00a0060860000800ULL), }, }; - server_add_descriptor(server, AVB_AEM_DESC_STREAM_INPUT, 0, + es_builder_add_descriptor(server, AVB_AEM_DESC_STREAM_INPUT, 0, sizeof(stream_input_0), &stream_input_0); struct { @@ -216,7 +234,7 @@ htobe64(0x00a0060860000800ULL), }, }; - server_add_descriptor(server, AVB_AEM_DESC_STREAM_OUTPUT, 0, + es_builder_add_descriptor(server, AVB_AEM_DESC_STREAM_OUTPUT, 0, sizeof(stream_output_0), &stream_output_0); struct avb_aem_desc_avb_interface avb_interface = { @@ -237,7 +255,7 @@ }; strncpy(avb_interface.object_name, server->ifname, 63); memcpy(avb_interface.mac_address, server->mac_addr, 6); - server_add_descriptor(server, AVB_AEM_DESC_AVB_INTERFACE, 0, + es_builder_add_descriptor(server, AVB_AEM_DESC_AVB_INTERFACE, 0, sizeof(avb_interface), &avb_interface); struct avb_aem_desc_clock_source clock_source = { @@ -250,6 +268,6 @@ .clock_source_location_type = htons(AVB_AEM_DESC_STREAM_INPUT), .clock_source_location_index = htons(0), }; - server_add_descriptor(server, AVB_AEM_DESC_CLOCK_SOURCE, 0, + es_builder_add_descriptor(server, AVB_AEM_DESC_CLOCK_SOURCE, 0, sizeof(clock_source), &clock_source); }
View file
_service:download_files:pipewire-1.5.84.tar.bz2/src/modules/module-avb/es-builder.c
Added
@@ -0,0 +1,81 @@ +/* PipeWire */ +/* SPDX-FileCopyrightText: Copyright © 2025 Alexandre Malki <alexandre.malki@kebag-logic.com> */ +/* SPDX-License-Identifier: MIT */ + + +#include "es-builder.h" +#include "aecp-aem-descriptors.h" + +/** + * \brief The goal of this modules is to create a an entity and + * attache the necessary status or resources to it so they + * do no have to be seperated and referenced somewhere else. + * + * In a sense, it encapsulates the descriptor, and the states + * information that will be altered either by a aecp/acmp commands + * or internal state changes reflected into the counters. + */ + +/** The callback type used for the different entity descriptor */ +typedef void* (*es_builder_cb_t) (struct server *server, uint16_t type, + uint16_t index, size_t size, void *ptr); + +/** Structure holding all necessary cb + * \todo for the future of compatibility between milan's version + * and plain AVB, add the right callback, that would reduce + * code complexity and increase reusability. + * As well as having multiple entity model defined using different + * entity on the same machine + */ +struct es_builder_st { + es_builder_cb_t build_descriptor_cb; +}; + +/** All callback that needs a status information */ +static const struct es_builder_st es_builderAVB_AEM_DESC_LAST_RESERVED_17221 = +{ +}; + +/** + * \brief, should be called when creating an a descriptor, it will attach + * the right state variable that are necessary for counters, stream info + * and so on... + */ +void es_builder_add_descriptor(struct server *server, uint16_t type, + uint16_t index, size_t size, void *ptr_aem) +{ + void *desc_ptr; + struct descriptor *d; + + if (!server) { + pw_log_error("Invalid server, it is empty %p\n", server); + spa_assert(0); + } + + if (type >= AVB_AEM_DESC_LAST_RESERVED_17221) { + pw_log_error("Invalid Type %u\n", type); + spa_assert(0); + } + + /* Look if the descriptor has a callback to attach more status data */ + if (!es_buildertype.build_descriptor_cb) { + if (!server_add_descriptor(server, type, index, size, ptr_aem)) { + pw_log_error("Could not allocate descriptor %u at " + "index %u the avb aem type\n", type, index); + + spa_assert(0); + } + } else { + desc_ptr = es_buildertype.build_descriptor_cb(server, type, + index, size, ptr_aem); + if (!desc_ptr) { + pw_log_error("Could not allocate specific descriptr " + "%u at index %u the avb aem type\n", + type, index); + + spa_assert(0); + } + d = (struct descriptor *) desc_ptr; + d->size = size; + } +}
View file
_service:download_files:pipewire-1.5.84.tar.bz2/src/modules/module-avb/es-builder.h
Added
@@ -0,0 +1,19 @@ +/* PipeWire */ +/* SPDX-FileCopyrightText: Copyright © 2025 Alexandre Malki <alexandre.malki@kebag-logic.com> */ +/* SPDX-License-Identifier: MIT */ + + +#ifndef __ES_BUILDER_H__ +#define __ES_BUILDER_H__ + +#include "internal.h" + +/** + * This is a mandatory feature to add the necessary state information + * to create the right entity model + **/ +void es_builder_add_descriptor(struct server *server, uint16_t type, + uint16_t index, size_t size, void *ptr_aem); + + +#endif // __ES_BUILDER_H__
View file
_service:download_files:pipewire-1.5.83.tar.bz2/src/modules/module-avb/mrp.c -> _service:download_files:pipewire-1.5.84.tar.bz2/src/modules/module-avb/mrp.c
Changed
@@ -1,5 +1,7 @@ /* AVB support */ /* SPDX-FileCopyrightText: Copyright © 2022 Wim Taymans */ +/* SPDX-FileCopyrightText: Copyright © 2025 Kebag-Logic */ +/* SPDX-FileCopyrightText: Copyright © 2025 Alexandre Malki <alexandre.malki@kebag-logic.com> */ /* SPDX-License-Identifier: MIT */ #include <pipewire/pipewire.h> @@ -32,6 +34,16 @@ struct spa_hook_list listener_list; }; +enum fsm_lva { + FSM_LVA_ACTIVE, + FSM_LVA_PASSIVE +}; + +struct fsm_leave_all_timer { + enum fsm_lva state; + uint64_t leave_all_timeout; +}; + struct mrp { struct server *server; struct spa_hook server_listener; @@ -41,7 +53,7 @@ struct spa_list attributes; uint64_t periodic_timeout; - uint64_t leave_all_timeout; + struct fsm_leave_all_timer lva_timer; uint64_t join_timeout; }; @@ -60,6 +72,17 @@ mrp_emit_event(mrp, now, event); } +static void mrp_set_update_lva(struct mrp *mrp, uint64_t now, bool force_send) +{ + if (!force_send) { + mrp->lva_timer.leave_all_timeout = now + + (MRP_LVATIMER_MS + (pw_rand32() % (MRP_LVATIMER_MS / 2))) + * SPA_NSEC_PER_MSEC; + } else { + mrp->lva_timer.leave_all_timeout = now; + } +} + static void mrp_periodic(void *data, uint64_t now) { struct mrp *mrp = data; @@ -71,13 +94,15 @@ global_event(mrp, now, AVB_MRP_EVENT_PERIODIC); mrp->periodic_timeout = now + MRP_PERIODTIMER_MS * SPA_NSEC_PER_MSEC; } - if (now > mrp->leave_all_timeout) { - if (mrp->leave_all_timeout > 0) { + + + if (now > mrp->lva_timer.leave_all_timeout) { + /* 802.1Q-2014 Table 10-5 */ + mrp->lva_timer.state = FSM_LVA_ACTIVE; + if (mrp->lva_timer.leave_all_timeout > 0) { global_event(mrp, now, AVB_MRP_EVENT_RX_LVA); leave_all = true; } - mrp->leave_all_timeout = now + (MRP_LVATIMER_MS + (random() % (MRP_LVATIMER_MS / 2))) - * SPA_NSEC_PER_MSEC; } if (now > mrp->join_timeout) { @@ -89,7 +114,9 @@ } spa_list_for_each(a, &mrp->attributes, link) { - if (a->leave_timeout > 0 && now > a->leave_timeout) { + // 802.1Q Clause 10.7.4.2 + if (a->leave_timeout > 0 && now > a->leave_timeout && a->registrar_state == + AVB_MRP_LV) { a->leave_timeout = 0; avb_mrp_attribute_update_state(&a->attr, now, AVB_MRP_EVENT_LV_TIMER); } @@ -134,7 +161,7 @@ return -EPROTO; if (v->lva) - info->attr_event(data, now, attr_type, AVB_MRP_EVENT_RX_LVA); + info->attr_event(data, now, attr_type, AVB_MRP_ATTRIBUTE_EVENT_LVA); for (i = 0; i < num_values; i++) { if (i % 3 == 0) { @@ -160,6 +187,98 @@ return 0; } +const char *avb_applicant_state_name(uint8_t state) +{ + switch (state) { + case AVB_MRP_VO: + return "VO"; + case AVB_MRP_VP: + return "VP"; + case AVB_MRP_VN: + return "VN"; + case AVB_MRP_AN: + return "AN"; + case AVB_MRP_AA: + return "AA"; + case AVB_MRP_QA: + return "QA"; + case AVB_MRP_LA: + return "LA"; + case AVB_MRP_AO: + return "AO"; + case AVB_MRP_QO: + return "QO"; + case AVB_MRP_AP: + return "AP"; + case AVB_MRP_QP: + return "QP"; + case AVB_MRP_LO: + return "LO"; + } + + return "unknown-applicant-state"; +} + +const char *avb_registrar_state_name(uint8_t state) +{ + switch (state) { + case AVB_MRP_IN: + return "IN"; + case AVB_MRP_LV: + return "LV"; + case AVB_MRP_MT: + return "MT"; + } + + return "unknown-registrar-state"; +} + +const char *avb_mrp_event_name(uint8_t event) +{ + switch (event) { + case AVB_MRP_EVENT_BEGIN: + return "begin"; + case AVB_MRP_EVENT_NEW: + return "new"; + case AVB_MRP_EVENT_JOIN: + return "join"; + case AVB_MRP_EVENT_LV: + return "lv"; + case AVB_MRP_EVENT_TX: + return "tx"; + case AVB_MRP_EVENT_TX_LVA: + return "tx_lva"; + case AVB_MRP_EVENT_TX_LVAF: + return "tx_lvaf"; + case AVB_MRP_EVENT_RX_NEW: + return "rx_new"; + case AVB_MRP_EVENT_RX_JOININ: + return "rx_joinin"; + case AVB_MRP_EVENT_RX_IN: + return "rx_in"; + case AVB_MRP_EVENT_RX_JOINMT: + return "rx_joinmt"; + case AVB_MRP_EVENT_RX_MT: + return "rx_mt"; + case AVB_MRP_EVENT_RX_LV: + return "rx_lv"; + case AVB_MRP_EVENT_RX_LVA: + return "rx_lva"; + case AVB_MRP_EVENT_FLUSH: + return "flush"; + case AVB_MRP_EVENT_REDECLARE: + return "redeclare"; + case AVB_MRP_EVENT_PERIODIC: + return "periodic"; + case AVB_MRP_EVENT_LV_TIMER: + return "lv_timer"; + case AVB_MRP_EVENT_LVA_TIMER: + return "lva_timer"; + } + + return "unknown-event"; +} + const char *avb_mrp_notify_name(uint8_t notify) { switch(notify) { @@ -232,6 +351,22 @@ uint8_t notify = 0, state; uint8_t send = 0; + // Handle the LVA timer FSM + switch (event) { + case AVB_MRP_EVENT_RX_LVA: + mrp_set_update_lva(mrp, now, false); + mrp->lva_timer.state = FSM_LVA_PASSIVE; + break; + case AVB_MRP_EVENT_TX: + if (mrp->lva_timer.state == FSM_LVA_ACTIVE) { + mrp_set_update_lva(mrp, now, true); + } + mrp->lva_timer.state = FSM_LVA_PASSIVE; + break; + default: + break; + } + state = a->registrar_state; switch (event) { @@ -242,7 +377,7 @@ notify = AVB_MRP_NOTIFY_NEW; switch (state) { case AVB_MRP_LV: - a->leave_timeout = 0; + a->leave_timeout = INT64_MAX; break; } state = AVB_MRP_IN; @@ -251,7 +386,7 @@ case AVB_MRP_EVENT_RX_JOINMT: switch (state) { case AVB_MRP_LV: - a->leave_timeout = 0; + a->leave_timeout = INT64_MAX; break; case AVB_MRP_MT: notify = AVB_MRP_NOTIFY_JOIN; @@ -266,7 +401,7 @@ switch (state) { case AVB_MRP_IN: a->leave_timeout = now + MRP_LVTIMER_MS * SPA_NSEC_PER_MSEC; - //state = AVB_MRP_LV; + state = AVB_MRP_LV; break; } break; @@ -295,7 +430,10 @@ } if (a->registrar_state != state || notify) { - pw_log_debug("attr %p: %d %d -> %d %d", a, event, a->registrar_state, state, notify); + pw_log_debug("REG: attr %p: %s %s %s -> %s %s notify? %s", a, a->attr.name, + avb_mrp_event_name(event), avb_registrar_state_name(a->registrar_state), + avb_registrar_state_name(state), avb_mrp_send_name(notify), + notify ? "YES":"NO"); a->registrar_state = state; } @@ -519,10 +657,15 @@ default: break; } + if (a->applicant_state != state || send) { - pw_log_debug("attr %p: %d %d -> %d %d", a, event, a->applicant_state, state, send); + pw_log_debug("APP: attr %p: %s %s %s -> %s %d:%s joined? %s", a, a->attr.name, + avb_mrp_event_name(event), avb_applicant_state_name(a->applicant_state), + avb_registrar_state_name(state), send, avb_mrp_send_name(send), + a->joined? "YES" : " NO"); a->applicant_state = state; } + if (a->joined) a->attr.pending_send = send; } @@ -536,6 +679,7 @@ AVB_MRP_ATTRIBUTE_EVENT_JOINMT = AVB_MRP_EVENT_RX_JOINMT, AVB_MRP_ATTRIBUTE_EVENT_MT = AVB_MRP_EVENT_RX_MT, AVB_MRP_ATTRIBUTE_EVENT_LV = AVB_MRP_EVENT_RX_LV, + AVB_MRP_ATTRIBUTE_EVENT_LVA = AVB_MRP_EVENT_RX_LVA, }; avb_mrp_attribute_update_state(attr, now, mapevent); }
View file
_service:download_files:pipewire-1.5.83.tar.bz2/src/modules/module-avb/mrp.h -> _service:download_files:pipewire-1.5.84.tar.bz2/src/modules/module-avb/mrp.h
Changed
@@ -86,23 +86,29 @@ #define AVB_MRP_ATTRIBUTE_EVENT_JOINMT 3 #define AVB_MRP_ATTRIBUTE_EVENT_MT 4 #define AVB_MRP_ATTRIBUTE_EVENT_LV 5 +#define AVB_MRP_ATTRIBUTE_EVENT_LVA 6 -#define AVB_MRP_SEND_NEW 1 -#define AVB_MRP_SEND_JOININ 2 -#define AVB_MRP_SEND_IN 3 -#define AVB_MRP_SEND_JOINMT 4 -#define AVB_MRP_SEND_MT 5 -#define AVB_MRP_SEND_LV 6 +#define AVB_MRP_SEND_NEW 0 +#define AVB_MRP_SEND_JOININ 1 +#define AVB_MRP_SEND_IN 2 +#define AVB_MRP_SEND_JOINMT 3 +#define AVB_MRP_SEND_MT 4 +#define AVB_MRP_SEND_LV 5 +#define AVB_MRP_SEND_LVA 6 #define AVB_MRP_NOTIFY_NEW 1 #define AVB_MRP_NOTIFY_JOIN 2 #define AVB_MRP_NOTIFY_LEAVE 3 +const char *avb_applicant_state_name(uint8_t state); +const char *avb_registrar_state_name(uint8_t state); +const char *avb_mrp_event_name(uint8_t event); const char *avb_mrp_notify_name(uint8_t notify); const char *avb_mrp_send_name(uint8_t send); struct avb_mrp_attribute { uint8_t pending_send; + const char *name; void *user_data; };
View file
_service:download_files:pipewire-1.5.83.tar.bz2/src/modules/module-avb/msrp.c -> _service:download_files:pipewire-1.5.84.tar.bz2/src/modules/module-avb/msrp.c
Changed
@@ -1,5 +1,7 @@ /* AVB support */ /* SPDX-FileCopyrightText: Copyright © 2022 Wim Taymans */ +/* SPDX-FileCopyrightText: Copyright © 2025 Kebag-Logic */ +/* SPDX-FileCopyrightText: Copyright © 2025 Alexandre Malki <alexandre.malki@kebag-logic.com> */ /* SPDX-License-Identifier: MIT */ #include <unistd.h> @@ -351,6 +353,7 @@ a->msrp = msrp; a->attr.mrp = attr; a->attr.type = type; + attr->name = "MSRP"; spa_list_append(&msrp->attributes, &a->link); avb_mrp_attribute_add_listener(attr, &a->listener, &mrp_attr_events, a);
View file
_service:download_files:pipewire-1.5.83.tar.bz2/src/modules/module-avb/mvrp.c -> _service:download_files:pipewire-1.5.84.tar.bz2/src/modules/module-avb/mvrp.c
Changed
@@ -1,5 +1,7 @@ /* AVB support */ /* SPDX-FileCopyrightText: Copyright © 2022 Wim Taymans */ +/* SPDX-FileCopyrightText: Copyright © 2025 Kebag-Logic */ +/* SPDX-FileCopyrightText: Copyright © 2025 Alexandre Malki <alexandre.malki@kebag-logic.com> */ /* SPDX-License-Identifier: MIT */ #include <unistd.h> @@ -189,6 +191,7 @@ a = attr->user_data; a->attr.mrp = attr; a->attr.type = type; + attr->name = "MVRP"; spa_list_append(&mvrp->attributes, &a->link); avb_mrp_attribute_add_listener(attr, &a->listener, &mrp_attr_events, a);
View file
_service:download_files:pipewire-1.5.83.tar.bz2/src/modules/module-filter-chain.c -> _service:download_files:pipewire-1.5.84.tar.bz2/src/modules/module-filter-chain.c
Changed
@@ -401,11 +401,13 @@ * - `filename` The IR to load or create. Possible values are: * - `/hilbert` creates a hilbert function(https://en.wikipedia.org/wiki/Hilbert_transform) * that can be used to phase shift the signal by +/-90 degrees. The - * `length` will be used as the number of coefficients. + * `length` will be used as the number of coefficients. The default latency + * if the length/2. * - `/dirac` creates a Dirac function(https://en.wikipedia.org/wiki/Dirac_delta_function) that - * can be used as gain. + * can be used as gain. The default latency is 0. * - A filename to load as the IR. This needs to be a file format supported - * by sndfile. + * by sndfile or be an inline IR with "/ir:<rate>,<value1>,<value2>". The default + * latency of file IRs is 0. * - filename, ... an array of filenames. The file with the closest samplerate match * with the graph samplerate will be used. * - `offset` The sample offset in the file as the start of the IR. @@ -414,7 +416,7 @@ * - `resample_quality` The resample quality in case the IR does not match the graph * samplerate. * - `latency` The extra latency in seconds to report. When left unspecified (or < 0.0) - * the convolver latency will be the length of the IR. + * the default IR latency will be used, the the filename argument. * * ### Delay *
View file
_service:download_files:pipewire-1.5.83.tar.bz2/src/modules/module-protocol-pulse/pulse-server.c -> _service:download_files:pipewire-1.5.84.tar.bz2/src/modules/module-protocol-pulse/pulse-server.c
Changed
@@ -2051,6 +2051,7 @@ flags |= PW_STREAM_FLAG_DONT_RECONNECT; if (direct_on_input_idx != SPA_ID_INVALID) { + dont_inhibit_auto_suspend = false; source_index = direct_on_input_idx; } else if (source_name != NULL) { if ((id = atoi(source_name)) != 0) @@ -4674,6 +4675,10 @@ pw_log_info("%s %s tag:%u name:%s", client->name, commandscommand.name, tag, name); + /* @NONE@ is used to clear the setting */ + if (spa_streq(name, "@NONE@")) + name = NULL; + if (name != NULL && (o = find_device(client, SPA_ID_INVALID, name, sink, NULL)) == NULL) return -ENOENT;
View file
_service:download_files:pipewire-1.5.83.tar.bz2/src/modules/module-rtp-sap.c -> _service:download_files:pipewire-1.5.84.tar.bz2/src/modules/module-rtp-sap.c
Changed
@@ -981,7 +981,7 @@ } pw_net_get_ip(&impl->igmp_recovery.mcast_addr, addr, sizeof(addr), NULL, NULL); - pw_log_info("IGMP recovery triggered for %s", addr); + pw_log_debug("IGMP recovery triggered for %s", addr); /* Force IGMP membership refresh by leaving the group first, then rejoin */ if (impl->igmp_recovery.is_ipv6) { @@ -994,10 +994,10 @@ res = setsockopt(impl->igmp_recovery.socket_fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mr6, sizeof(mr6)); if (SPA_LIKELY(res == 0)) { - pw_log_info("left IPv6 multicast group"); + pw_log_debug("left IPv6 multicast group"); } else { if (errno == EADDRNOTAVAIL) { - pw_log_info("attempted to leave IPv6 multicast group, but " + pw_log_debug("attempted to leave IPv6 multicast group, but " "membership was already silently dropped"); } else { pw_log_warn("failed to leave IPv6 multicast group: %m"); @@ -1009,7 +1009,7 @@ if (res < 0) { pw_log_warn("failed to re-join IPv6 multicast group: %m"); } else { - pw_log_info("re-joined IPv6 multicast group successfully"); + pw_log_debug("re-joined IPv6 multicast group successfully"); } } else { struct ip_mreqn mr4; @@ -1021,10 +1021,10 @@ res = setsockopt(impl->igmp_recovery.socket_fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mr4, sizeof(mr4)); if (SPA_LIKELY(res == 0)) { - pw_log_info("left IPv4 multicast group"); + pw_log_debug("left IPv4 multicast group"); } else { if (errno == EADDRNOTAVAIL) { - pw_log_info("attempted to leave IPv4 multicast group, but " + pw_log_debug("attempted to leave IPv4 multicast group, but " "membership was already silently dropped"); } else { pw_log_warn("failed to leave IPv4 multicast group: %m"); @@ -1036,7 +1036,7 @@ if (res < 0) { pw_log_warn("failed to re-join IPv4 multicast group: %m"); } else { - pw_log_info("re-joined IPv4 multicast group successfully"); + pw_log_debug("re-joined IPv4 multicast group successfully"); } }
View file
_service:download_files:pipewire-1.5.83.tar.bz2/src/modules/module-rtp-source.c -> _service:download_files:pipewire-1.5.84.tar.bz2/src/modules/module-rtp-source.c
Changed
@@ -259,6 +259,19 @@ bool waiting; }; +static inline uint64_t get_time_ns(struct impl *impl) +{ + uint64_t res; + if (impl->stream) { + res = rtp_stream_get_nsec(impl->stream); + } else { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + res = SPA_TIMESPEC_TO_NSEC(&ts); + } + return res; +} + static int do_start(struct spa_loop *loop, bool async, uint32_t seq, const void *data, size_t size, void *user_data) { @@ -288,9 +301,10 @@ int suppressed; uint64_t current_time; - current_time = rtp_stream_get_nsec(impl->stream); + current_time = get_time_ns(impl); if (mask & SPA_IO_IN) { + if ((len = recv(fd, impl->buffer, impl->buffer_size, 0)) < 0) goto receive_error; @@ -349,10 +363,10 @@ res = setsockopt(impl->igmp_recovery.socket_fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mr6, sizeof(mr6)); if (SPA_LIKELY(res == 0)) { - pw_log_info("left IPv6 multicast group"); + pw_log_debug("left IPv6 multicast group"); } else { if (errno == EADDRNOTAVAIL) { - pw_log_info("attempted to leave IPv6 multicast group, but " + pw_log_debug("attempted to leave IPv6 multicast group, but " "membership was already silently dropped"); } else { pw_log_warn("failed to leave IPv6 multicast group: %m"); @@ -364,7 +378,7 @@ if (res < 0) { pw_log_warn("failed to re-join IPv6 multicast group: %m"); } else { - pw_log_info("re-joined IPv6 multicast group successfully"); + pw_log_debug("re-joined IPv6 multicast group successfully"); } } else { struct ip_mreqn mr4; @@ -376,10 +390,10 @@ res = setsockopt(impl->igmp_recovery.socket_fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mr4, sizeof(mr4)); if (SPA_LIKELY(res == 0)) { - pw_log_info("left IPv4 multicast group"); + pw_log_debug("left IPv4 multicast group"); } else { if (errno == EADDRNOTAVAIL) { - pw_log_info("attempted to leave IPv4 multicast group, but " + pw_log_debug("attempted to leave IPv4 multicast group, but " "membership was already silently dropped"); } else { pw_log_warn("failed to leave IPv4 multicast group: %m"); @@ -391,11 +405,11 @@ if (res < 0) { pw_log_warn("failed to re-join IPv4 multicast group: %m"); } else { - pw_log_info("re-joined IPv4 multicast group successfully"); + pw_log_debug("re-joined IPv4 multicast group successfully"); } } - current_time = rtp_stream_get_nsec(impl->stream); + current_time = get_time_ns(impl); SPA_ATOMIC_STORE(impl->last_packet_time, current_time); return res; @@ -420,7 +434,7 @@ * silently kicked out of the IGMP group (which causes data * to no longer arrive, thus leading to these states). */ - current_time = rtp_stream_get_nsec(impl->stream); + current_time = get_time_ns(impl); last_packet_time = SPA_ATOMIC_LOAD(impl->last_packet_time); elapsed_seconds = (current_time - last_packet_time) / SPA_NSEC_PER_SEC; @@ -433,7 +447,7 @@ } pw_net_get_ip(&impl->igmp_recovery.mcast_addr, addr, sizeof(addr), NULL, NULL); - pw_log_info("starting IGMP recovery for %s", addr); + pw_log_debug("starting IGMP recovery for %s", addr); /* Run the actual recovery in the data loop, since recovery involves * rejoining the socket to the IGMP group. By running this in the @@ -446,7 +460,7 @@ res = pw_loop_locked(impl->data_loop, rejoin_igmp_group, 1, NULL, 0, impl); if (SPA_LIKELY(res == 0)) { - pw_log_info("IGMP recovery for %s finished", addr); + pw_log_debug("IGMP recovery for %s finished", addr); } else { pw_log_error("error while finishing IGMP recovery for %s: %s", addr, spa_strerror(res));
View file
_service:download_files:pipewire-1.5.83.tar.bz2/src/pipewire/impl-link.c -> _service:download_files:pipewire-1.5.84.tar.bz2/src/pipewire/impl-link.c
Changed
@@ -924,6 +924,7 @@ spa_list_remove(&this->input_link); pw_impl_port_emit_link_removed(port, this); + pw_impl_port_recalc_capability(port); pw_impl_port_recalc_latency(port); pw_impl_port_recalc_tag(port); @@ -956,6 +957,7 @@ spa_list_remove(&this->output_link); pw_impl_port_emit_link_removed(port, this); + pw_impl_port_recalc_capability(port); pw_impl_port_recalc_latency(port); pw_impl_port_recalc_tag(port); @@ -1138,6 +1140,14 @@ pw_impl_port_recalc_tag(this->output); } +static void input_port_capability_changed(void *data) +{ + struct impl *impl = data; + struct pw_impl_link *this = &impl->this; + if (!this->feedback) + pw_impl_port_recalc_capability(this->output); +} + static void output_port_latency_changed(void *data) { struct impl *impl = data; @@ -1154,12 +1164,21 @@ pw_impl_port_recalc_tag(this->input); } +static void output_port_capability_changed(void *data) +{ + struct impl *impl = data; + struct pw_impl_link *this = &impl->this; + if (!this->feedback) + pw_impl_port_recalc_capability(this->input); +} + static const struct pw_impl_port_events input_port_events = { PW_VERSION_IMPL_PORT_EVENTS, .param_changed = input_port_param_changed, .state_changed = input_port_state_changed, .latency_changed = input_port_latency_changed, .tag_changed = input_port_tag_changed, + .capability_changed = input_port_capability_changed, }; static const struct pw_impl_port_events output_port_events = { @@ -1168,6 +1187,7 @@ .state_changed = output_port_state_changed, .latency_changed = output_port_latency_changed, .tag_changed = output_port_tag_changed, + .capability_changed = output_port_capability_changed, }; static void node_result(struct impl *impl, void *obj, @@ -1576,6 +1596,8 @@ try_link_controls(impl, output, input); + pw_impl_port_recalc_capability(output); + pw_impl_port_recalc_capability(input); pw_impl_port_recalc_latency(output); pw_impl_port_recalc_latency(input); pw_impl_port_recalc_tag(output);
View file
_service:download_files:pipewire-1.5.83.tar.bz2/src/pipewire/impl-port.c -> _service:download_files:pipewire-1.5.84.tar.bz2/src/pipewire/impl-port.c
Changed
@@ -10,6 +10,8 @@ #include <spa/pod/parser.h> #include <spa/param/audio/format-utils.h> #include <spa/param/tag-utils.h> +#include <spa/param/dict-utils.h> +#include <spa/param/peer-utils.h> #include <spa/node/utils.h> #include <spa/utils/names.h> #include <spa/utils/string.h> @@ -762,6 +764,35 @@ return 0; } +static int process_capability_param(void *data, int seq, + uint32_t id, uint32_t index, uint32_t next, struct spa_pod *param) +{ + struct pw_impl_port *this = data; + struct spa_param_dict_info info; + struct spa_pod *old; + + if (id != SPA_PARAM_Capability || param == NULL) + return -EINVAL; + if (spa_param_dict_parse(param, &info, sizeof(info)) < 0) + return 0; + + old = this->capthis->direction; + if (spa_param_dict_compare(old, param) == 0) + return 0; + + pw_log_debug("port %p: got %s capabilty %p", this, + pw_direction_as_string(this->direction), param); + if (param) + pw_log_pod(SPA_LOG_LEVEL_DEBUG, param); + + free(old); + this->capthis->direction = spa_pod_copy(param); + + pw_impl_port_emit_capability_changed(this); + + return 0; +} + static int process_latency_param(void *data, int seq, uint32_t id, uint32_t index, uint32_t next, struct spa_pod *param) { @@ -831,6 +862,7 @@ PW_IMPL_PORT_FLAG_BUFFERS); pw_impl_port_for_each_param(port, 0, SPA_PARAM_IO, 0, 0, NULL, check_param_io, port); + pw_impl_port_for_each_param(port, 0, SPA_PARAM_Capability, 0, 0, NULL, process_capability_param, port); pw_impl_port_for_each_param(port, 0, SPA_PARAM_Latency, 0, 0, NULL, process_latency_param, port); pw_impl_port_for_each_param(port, 0, SPA_PARAM_Tag, 0, 0, NULL, process_tag_param, port); } @@ -877,6 +909,15 @@ changed_idsn_changed_ids++ = id; switch (id) { + case SPA_PARAM_PeerCapability: + port->have_peer_capability_param = + SPA_FLAG_IS_SET(info->paramsi.flags, SPA_PARAM_INFO_WRITE); + break; + case SPA_PARAM_Capability: + if (port->node != NULL) + pw_impl_port_for_each_param(port, 0, id, 0, UINT32_MAX, + NULL, process_capability_param, port); + break; case SPA_PARAM_Latency: port->have_latency_param = SPA_FLAG_IS_SET(info->paramsi.flags, SPA_PARAM_INFO_WRITE); @@ -1918,6 +1959,66 @@ return pw_impl_port_set_param(port, SPA_PARAM_Tag, 0, port->tagdirection); } +int pw_impl_port_recalc_capability(struct pw_impl_port *port) +{ + struct pw_impl_link *l; + struct pw_impl_port *other; + struct spa_pod *param, *old; + struct spa_pod_dynamic_builder b = { 0 }; + struct spa_pod_frame f; + enum spa_direction direction; + uint8_t buffer1024; + int count = 0; + bool changed; + + if (port->destroying) + return 0; + + direction = SPA_DIRECTION_REVERSE(port->direction); + + spa_pod_dynamic_builder_init(&b, buffer, sizeof(buffer), 4096); + spa_peer_param_build_start(&b.b, &f, SPA_PARAM_PeerCapability); + + if (port->direction == PW_DIRECTION_OUTPUT) { + spa_list_for_each(l, &port->links, output_link) { + other = l->input; + spa_peer_param_build_add_param(&b.b, other->info.id, other->capother->direction); + count++; + } + } else { + spa_list_for_each(l, &port->links, input_link) { + other = l->output; + spa_peer_param_build_add_param(&b.b, other->info.id, other->capother->direction); + count++; + } + } + param = count == 0 ? NULL : spa_peer_param_build_end(&b.b, &f); + + old = port->capdirection; + + changed = spa_pod_memcmp(old, param); + + pw_log_info("port %d: %p %s %s cap %p %d", + port->info.id, port, changed ? "set" : "keep", + pw_direction_as_string(direction), param, port->have_peer_capability_param); + + if (changed) { + free(old); + port->capdirection = param ? spa_pod_copy(param) : NULL; + if (param) + pw_log_pod(SPA_LOG_LEVEL_INFO, param); + } + spa_pod_dynamic_builder_clean(&b); + + if (!changed) + return 0; + + if (!port->have_peer_capability_param) + return 0; + + return pw_impl_port_set_param(port, SPA_PARAM_PeerCapability, 0, port->capdirection); +} + SPA_EXPORT int pw_impl_port_is_linked(struct pw_impl_port *port) {
View file
_service:download_files:pipewire-1.5.83.tar.bz2/src/pipewire/impl-port.h -> _service:download_files:pipewire-1.5.84.tar.bz2/src/pipewire/impl-port.h
Changed
@@ -36,7 +36,7 @@ /** Port events, use \ref pw_impl_port_add_listener */ struct pw_impl_port_events { -#define PW_VERSION_IMPL_PORT_EVENTS 3 +#define PW_VERSION_IMPL_PORT_EVENTS 4 uint32_t version; /** The port is destroyed */ @@ -74,6 +74,8 @@ void (*latency_changed) (void *data); /** tag changed. Since version 3 */ void (*tag_changed) (void *data); + /** capability changed. Since version 4 */ + void (*capability_changed) (void *data); }; /** Create a new port
View file
_service:download_files:pipewire-1.5.83.tar.bz2/src/pipewire/private.h -> _service:download_files:pipewire-1.5.84.tar.bz2/src/pipewire/private.h
Changed
@@ -902,6 +902,7 @@ #define pw_impl_port_emit_param_changed(p,i) pw_impl_port_emit(p, param_changed, 1, i) #define pw_impl_port_emit_latency_changed(p) pw_impl_port_emit(p, latency_changed, 2) #define pw_impl_port_emit_tag_changed(p) pw_impl_port_emit(p, tag_changed, 3) +#define pw_impl_port_emit_capability_changed(p) pw_impl_port_emit(p, capability_changed, 4) #define PW_IMPL_PORT_IS_CONTROL(port) SPA_FLAG_MASK((port)->flags, \ PW_IMPL_PORT_FLAG_BUFFERS|PW_IMPL_PORT_FLAG_CONTROL,\ @@ -977,6 +978,9 @@ unsigned int have_tag_param:1; struct spa_pod *tag2; /**< tags */ + unsigned int have_peer_capability_param:1; + struct spa_pod *cap2; /**< capabilities */ + void *owner_data; /**< extra owner data */ void *user_data; /**< extra user data */ }; @@ -1332,6 +1336,7 @@ int pw_impl_port_use_buffers(struct pw_impl_port *port, struct pw_impl_port_mix *mix, uint32_t flags, struct spa_buffer **buffers, uint32_t n_buffers); +int pw_impl_port_recalc_capability(struct pw_impl_port *port); int pw_impl_port_recalc_latency(struct pw_impl_port *port); int pw_impl_port_recalc_tag(struct pw_impl_port *port);
View file
_service:download_files:pipewire-1.5.83.tar.bz2/src/pipewire/stream.c -> _service:download_files:pipewire-1.5.84.tar.bz2/src/pipewire/stream.c
Changed
@@ -11,6 +11,7 @@ #include <spa/buffer/alloc.h> #include <spa/param/props.h> #include <spa/param/format-utils.h> +#include <spa/param/peer-utils.h> #include <spa/node/io.h> #include <spa/node/utils.h> #include <spa/utils/cleanup.h> @@ -103,14 +104,16 @@ uint64_t port_change_mask_all; struct spa_port_info port_info; struct pw_properties *port_props; -#define PORT_EnumFormat 0 -#define PORT_Meta 1 -#define PORT_IO 2 -#define PORT_Format 3 -#define PORT_Buffers 4 -#define PORT_Latency 5 -#define PORT_Tag 6 -#define N_PORT_PARAMS 7 +#define PORT_EnumFormat 0 +#define PORT_Meta 1 +#define PORT_IO 2 +#define PORT_Format 3 +#define PORT_Buffers 4 +#define PORT_Latency 5 +#define PORT_Tag 6 +#define PORT_Capability 7 +#define PORT_PeerCapability 8 +#define N_PORT_PARAMS 9 struct spa_param_info port_paramsN_PORT_PARAMS; struct spa_list param_list; @@ -144,6 +147,7 @@ struct spa_callbacks rt_callbacks; + unsigned int have_peer_capability:1; unsigned int disconnecting:1; unsigned int disconnect_core:1; unsigned int draining:1; @@ -196,6 +200,10 @@ return PORT_Latency; case SPA_PARAM_Tag: return PORT_Tag; + case SPA_PARAM_Capability: + return PORT_Capability; + case SPA_PARAM_PeerCapability: + return PORT_PeerCapability; default: return -1; } @@ -909,6 +917,21 @@ return 0; } +static void emit_dummy_peer_capability(struct stream *impl, bool empty) +{ + struct spa_pod *param = NULL; + uint8_t buffer1024; + if (!empty) { + struct spa_pod_frame f; + struct spa_pod_builder b; + spa_pod_builder_init(&b, buffer, sizeof(buffer)); + spa_peer_param_build_start(&b, &f, SPA_PARAM_PeerCapability); + spa_peer_param_build_add_param(&b, SPA_ID_INVALID, NULL); + param = spa_peer_param_build_end(&b, &f); + } + emit_param_changed(impl, SPA_PARAM_PeerCapability, param); +} + static int impl_port_set_param(void *object, enum spa_direction direction, uint32_t port_id, uint32_t id, uint32_t flags, @@ -916,7 +939,7 @@ { struct stream *impl = object; struct pw_stream *stream = &impl->this; - uint32_t user, fl = 0; + uint32_t user = 0, fl = 0; int res; const struct spa_pod *params1; uint32_t n_params = 0; @@ -936,7 +959,12 @@ n_params = param ? 1 : 0; switch (id) { + case SPA_PARAM_PeerCapability: + impl->have_peer_capability = true; + break; case SPA_PARAM_Latency: + if (!impl->have_peer_capability) + emit_dummy_peer_capability(impl, param == NULL); parse_latency(stream, param, &fl); break; } @@ -2015,6 +2043,8 @@ impl->port_paramsPORT_Buffers = SPA_PARAM_INFO(SPA_PARAM_Buffers, 0); impl->port_paramsPORT_Latency = SPA_PARAM_INFO(SPA_PARAM_Latency, SPA_PARAM_INFO_WRITE); impl->port_paramsPORT_Tag = SPA_PARAM_INFO(SPA_PARAM_Tag, SPA_PARAM_INFO_WRITE); + impl->port_paramsPORT_Capability = SPA_PARAM_INFO(SPA_PARAM_Capability, 0); + impl->port_paramsPORT_PeerCapability = SPA_PARAM_INFO(SPA_PARAM_PeerCapability, SPA_PARAM_INFO_WRITE); impl->port_info.props = &impl->port_props->dict; impl->port_info.params = impl->port_params; impl->port_info.n_params = N_PORT_PARAMS;
View file
_service:download_files:pipewire-1.5.83.tar.bz2/src/tools/pw-cat.c -> _service:download_files:pipewire-1.5.84.tar.bz2/src/tools/pw-cat.c
Changed
@@ -91,11 +91,6 @@ typedef int (*fill_fn)(struct data *d, void *dest, unsigned int n_frames, bool *null_frame); -struct channelmap { - uint32_t n_channels; - uint32_t channelsMAX_CHANNELS; -}; - struct data { struct pw_main_loop *loop; struct pw_context *context; @@ -135,7 +130,7 @@ unsigned int bitrate; unsigned int rate; uint32_t channels; - struct channelmap channelmap; + struct spa_audio_layout_info channelmap; unsigned int stride; enum unit latency_unit; unsigned int latency_value; @@ -634,7 +629,7 @@ return NULL; } -static int channelmap_from_sf(struct channelmap *map) +static int channelmap_from_sf(struct spa_audio_layout_info *map) { static const enum spa_audio_channel table = { SF_CHANNEL_MAP_MONO = SPA_AUDIO_CHANNEL_MONO, @@ -663,78 +658,75 @@ uint32_t i; for (i = 0; i < map->n_channels; i++) { - if (map->channelsi < SPA_N_ELEMENTS(table)) - map->channelsi = tablemap->channelsi; + if (map->positioni < SPA_N_ELEMENTS(table)) + map->positioni = tablemap->positioni; else - map->channelsi = SPA_AUDIO_CHANNEL_UNKNOWN; + map->positioni = SPA_AUDIO_CHANNEL_UNKNOWN; } return 0; } -struct mapping { +struct mapping_alias { const char *name; - uint32_t channels; - uint32_t values32; + const char *alias; }; -static const struct mapping maps = +static const struct mapping_alias maps = { - { "mono", SPA_AUDIO_LAYOUT_Mono }, - { "stereo", SPA_AUDIO_LAYOUT_Stereo }, - { "surround-21", SPA_AUDIO_LAYOUT_2_1 }, - { "quad", SPA_AUDIO_LAYOUT_Quad }, - { "surround-22", SPA_AUDIO_LAYOUT_2_2 }, - { "surround-40", SPA_AUDIO_LAYOUT_4_0 }, - { "surround-31", SPA_AUDIO_LAYOUT_3_1 }, - { "surround-41", SPA_AUDIO_LAYOUT_4_1 }, - { "surround-50", SPA_AUDIO_LAYOUT_5_0 }, - { "surround-51", SPA_AUDIO_LAYOUT_5_1 }, - { "surround-51r", SPA_AUDIO_LAYOUT_5_1R }, - { "surround-70", SPA_AUDIO_LAYOUT_7_0 }, - { "surround-71", SPA_AUDIO_LAYOUT_7_1 }, + { "mono", "Mono" }, + { "stereo", "Stereo" }, + { "surround-21", "2.1" }, + { "quad", "Quad" }, + { "surround-22", "2.2" }, + { "surround-40", "4.0" }, + { "surround-31", "3.1" }, + { "surround-41", "4.1" }, + { "surround-50", "5.0" }, + { "surround-51", "5.1" }, + { "surround-51r", "5.1R" }, + { "surround-70", "7.0" }, + { "surround-71", "7.1" }, }; -static int parse_channelmap(const char *channel_map, struct channelmap *map) +static int parse_channelmap(const char *channel_map, struct spa_audio_layout_info *map) { + if (spa_audio_layout_info_parse_name(map, sizeof(*map), channel_map) >= 0) + return 0; + SPA_FOR_EACH_ELEMENT_VAR(maps, m) { - if (spa_streq(m->name, channel_map)) { - map->n_channels = m->channels; - spa_memcpy(map->channels, &m->values, - map->n_channels * sizeof(unsigned int)); - return 0; - } + if (spa_streq(m->name, channel_map)) + return spa_audio_layout_info_parse_name(map, sizeof(*map), m->alias); } - spa_audio_parse_position_n(channel_map, strlen(channel_map), - map->channels, SPA_N_ELEMENTS(map->channels), &map->n_channels); + map->position, SPA_N_ELEMENTS(map->position), &map->n_channels); return 0; } -static int channelmap_default(struct channelmap *map, int n_channels) +static int channelmap_default(struct spa_audio_layout_info *map, int n_channels) { switch(n_channels) { case 1: - parse_channelmap("mono", map); + parse_channelmap("Mono", map); break; case 2: - parse_channelmap("stereo", map); + parse_channelmap("Stereo", map); break; case 3: - parse_channelmap("surround-21", map); + parse_channelmap("2.1", map); break; case 4: - parse_channelmap("quad", map); + parse_channelmap("Quad", map); break; case 5: - parse_channelmap("surround-50", map); + parse_channelmap("5.0", map); break; case 6: - parse_channelmap("surround-51", map); + parse_channelmap("5.1", map); break; case 7: - parse_channelmap("surround-70", map); + parse_channelmap("7.0", map); break; case 8: - parse_channelmap("surround-71", map); + parse_channelmap("7.1", map); break; default: n_channels = 0; @@ -744,13 +736,13 @@ return 0; } -static void channelmap_print(struct channelmap *map) +static void channelmap_print(struct spa_audio_layout_info *map) { uint32_t i; char pos8; for (i = 0; i < map->n_channels; i++) { fprintf(stderr, "%s%s", i ? "," : "", - spa_type_audio_channel_make_short_name(map->channelsi, + spa_type_audio_channel_make_short_name(map->positioni, pos, sizeof(pos), "UNK")); } } @@ -1051,16 +1043,24 @@ OPT_VOLUME, }; +#ifdef HAVE_PW_CAT_FFMPEG_INTEGRATION +#define OPTIONS "hvprmdosR:P:q:aM:n:c" +#else +#define OPTIONS "hvprmdsR:P:q:aM:n:c" +#endif + static const struct option long_options = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, OPT_VERSION}, { "verbose", no_argument, NULL, 'v' }, - { "record", no_argument, NULL, 'r' }, { "playback", no_argument, NULL, 'p' }, + { "record", no_argument, NULL, 'r' }, { "midi", no_argument, NULL, 'm' }, { "dsd", no_argument, NULL, 'd' }, +#ifdef HAVE_PW_CAT_FFMPEG_INTEGRATION { "encoded", no_argument, NULL, 'o' }, +#endif { "sysex", no_argument, NULL, 's' }, { "remote", required_argument, NULL, 'R' }, @@ -1121,7 +1121,7 @@ _(" --rate Sample rate (req. for rec) (default %u)\n" " --channels Number of channels (req. for rec) (default %u)\n" " --channel-map Channel map\n" - " one of: \"stereo\", \"surround-51\",... or\n" + " one of: \"Stereo\", \"5.1\",... or\n" " comma separated list of channel names: eg. \"FL,FR\"\n" " --format Sample format %s (req. for rec) (default %s)\n" " --volume Stream volume 0-1.0 (default %.3f)\n" @@ -1854,8 +1854,8 @@ bool def = false; if (sf_command(data->file, SFC_GET_CHANNEL_MAP_INFO, - data->channelmap.channels, - sizeof(data->channelmap.channels0) * data->channels)) { + data->channelmap.position, + sizeof(data->channelmap.position0) * data->channels)) { data->channelmap.n_channels = data->channels; if (channelmap_from_sf(&data->channelmap) < 0) data->channelmap.n_channels = 0; @@ -2043,12 +2043,7 @@ goto error_no_props; } -#ifdef HAVE_PW_CAT_FFMPEG_INTEGRATION - while ((c = getopt_long(argc, argv, "hvprmdosR:q:P:aM:n:c", long_options, NULL)) != -1) { -#else - while ((c = getopt_long(argc, argv, "hvprmdsR:q:P:aM:n:c", long_options, NULL)) != -1) { -#endif - + while ((c = getopt_long(argc, argv, OPTIONS, long_options, NULL)) != -1) { switch (c) { case 'h': @@ -2361,7 +2356,7 @@ } uint32_t i; for (i = 0; i < data.channelmap.n_channels; i++) - info.positioni = data.channelmap.channelsi; + info.positioni = data.channelmap.positioni; for (; i < data.channels; i++) info.positioni = SPA_AUDIO_CHANNEL_AUX0 + i; } @@ -2393,13 +2388,30 @@ info.rate = data.dff.info.rate / 8; channel_type = data.dff.info.channel_type; } - - SPA_FOR_EACH_ELEMENT_VAR(dsd_layouts, i) { - if (i->type != channel_type) - continue; - info.channels = i->info.n_channels; - memcpy(info.position, i->info.position, - info.channels * sizeof(uint32_t)); + if (info.channels > MAX_CHANNELS) { + fprintf(stderr, "error: too many channels in DSD %d > %d\n", + info.channels, MAX_CHANNELS); + goto error_bad_file; + } + if (data.channelmap.n_channels) { + if (data.channelmap.n_channels > MAX_CHANNELS) { + fprintf(stderr, "error: too many channels in channelmap %d > %d\n", + data.channelmap.n_channels, MAX_CHANNELS); + goto error_bad_file; + } + uint32_t i; + for (i = 0; i < data.channelmap.n_channels; i++) + info.positioni = data.channelmap.positioni; + for (; i < info.channels; i++) + info.positioni = SPA_AUDIO_CHANNEL_AUX0 + i; + } else { + SPA_FOR_EACH_ELEMENT_VAR(dsd_layouts, i) { + if (i->type != channel_type) + continue; + info.channels = i->info.n_channels; + memcpy(info.position, i->info.position, + info.channels * sizeof(uint32_t)); + } } paramsn_params++ = spa_format_audio_dsd_build(&b, SPA_PARAM_EnumFormat, &info); break;
View file
_service:download_files:pipewire-1.5.83.tar.bz2/test/test-spa-utils.c -> _service:download_files:pipewire-1.5.84.tar.bz2/test/test-spa-utils.c
Changed
@@ -127,7 +127,9 @@ pwtest_int_eq(SPA_TYPE_OBJECT_ParamLatency, 0x4000b); pwtest_int_eq(SPA_TYPE_OBJECT_ParamProcessLatency, 0x4000c); pwtest_int_eq(SPA_TYPE_OBJECT_ParamTag, 0x4000d); - pwtest_int_eq(_SPA_TYPE_OBJECT_LAST, 0x4000e); + pwtest_int_eq(SPA_TYPE_OBJECT_PeerParam, 0x4000e); + pwtest_int_eq(SPA_TYPE_OBJECT_ParamDict, 0x4000f); + pwtest_int_eq(_SPA_TYPE_OBJECT_LAST, 0x40010); pwtest_int_eq(SPA_TYPE_VENDOR_PipeWire, 0x02000000); pwtest_int_eq(SPA_TYPE_VENDOR_Other, 0x7f000000);
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.