Compare commits

..

No commits in common. "master" and "1.5.85" have entirely different histories.

197 changed files with 5458 additions and 12782 deletions

View file

@ -410,15 +410,13 @@ build_on_fedora_html_docs:
-Dsndfile=enabled
-Dsession-managers=[]
before_script:
- git fetch origin 1.0 1.2 1.4 1.6 master
- git fetch origin 1.0 1.2 1.4 master
- git branch -f 1.0 origin/1.0
- git clone -b 1.0 . branch-1.0
- git branch -f 1.2 origin/1.2
- git clone -b 1.2 . branch-1.2
- git branch -f 1.4 origin/1.4
- git clone -b 1.4 . branch-1.4
- git branch -f 1.6 origin/1.6
- git clone -b 1.6 . branch-1.6
- git branch -f master origin/master
- git clone -b master . branch-master
- !reference [.build, before_script]
@ -435,10 +433,6 @@ build_on_fedora_html_docs:
- meson setup builddir $MESON_OPTIONS
- meson compile -C builddir doc/pipewire-docs
- cd ..
- cd branch-1.6
- meson setup builddir $MESON_OPTIONS
- meson compile -C builddir doc/pipewire-docs
- cd ..
- cd branch-master
- meson setup builddir $MESON_OPTIONS
- meson compile -C builddir doc/pipewire-docs
@ -664,7 +658,7 @@ doccheck:
- cat pipewire_module_pages
- |
for page in $(cat pipewire_module_pages); do
git grep -q -e "\\\subpage $page" || (echo "\\page $page is missing \\subpage entry in doc/dox/modules.dox" && false)
git grep -q -e "\\\subpage $page" || (echo "\\page $page is missing \\subpage entry in doc/pipewire-modules.dox" && false)
done
check_missing_headers:
@ -688,13 +682,12 @@ pages:
- job: build_on_fedora_html_docs
artifacts: true
script:
- mkdir public public/1.0 public/1.2 public/1.4 public/1.6 public/devel
- mkdir public public/1.0 public/1.2 public/1.4 public/devel
- cp -R branch-1.0/builddir/doc/html/* public/1.0/
- cp -R branch-1.2/builddir/doc/html/* public/1.2/
- cp -R branch-1.4/builddir/doc/html/* public/1.4/
- cp -R branch-1.6/builddir/doc/html/* public/1.6/
- cp -R branch-master/builddir/doc/html/* public/devel/
- (cd public && ln -s 1.6/* .)
- (cd public && ln -s 1.4/* .)
artifacts:
paths:
- public

102
NEWS
View file

@ -1,102 +1,3 @@
# PipeWire 1.6.0 (2026-02-19)
This is the 1.6 release that is API and ABI compatible with previous
1.4.x releases.
This release contains some of the bigger changes that happened since
the 1.4 release last year, including:
* An LDAC decoder was added for bluetooth.
* SpanDSP for bluetooth packet loss concealment.
* Safe parsing and building of PODs in shared memory.
* Added support for metadata features. This is used to signal that
the sync_timeline metadata supports the RELEASE operation.
* Node commands and events can contain extra user data.
* Support for more compressed format helper functions to create
and parse formats.
* Support for compile time max channels. The max channels was
increased to 128.
* Support for audio channel layouts was added. This makes it possible
to set "audio.layout" = "5.1" instead of the more verbose
audio.position = [ FL, FR, FC, LFE, SL, SR ]
* Support for Capability Params was added. This can be used to
negotiate capabilities on a link before format and buffer
negotiation takes place.
* More HDR colortypes are added.
* Loops now have locking with priority inversion. Most code was adapted
to use the faster locks instead of epoll/eventfd to update shared state.
* Channel position are parsed from EDID data.
* Channel maps are now set on ALSA.
* The resampler now supports configurable window functions such
as blackman and kaiser windows. The phases are now also calculated
with fixed point math, which makes it more accurate.
* Many bluetooth updates and improvements.
* The filter-graph has an ffmpeg and ONNX plugin. The ffmpeg plugin
can run an audio AVFilterGraph. The ONNX plugin can run some models
such as the silero VAD.
* Many AVB updates. Work is ongoing to merge the Milan protocol.
* Support for v0 clients was removed.
* The jack-tunnel module can now autoconnect ports.
* ROC support multitrack layouts now.
* Many RTP updates.
* rlimits can now be set in the config file.
* Thread reset on fork can now be configured. JACK clients expect this
to be disabled.
* node.exclusive is now enforced.
* node.reliable enables reliable transport.
* pw-cat supports sysex and midiclip as well as some more uncompressed
formats. Options were added to set the container and codec formats
as well as list the supported containers, codecs, layouts and channel
names.
* Documentation updates.
## Highlights (since the previous 1.5.85 prerelease)
- Fix a 64 channel limit in the channel mixer.
- Fix an fd leak in pulse-server in some error cases.
- Some small fixes and improvements.
## PipeWire
- Fix Capability leaks.
- Return an error in pw-stream get-time when not STREAMING.
- Set the current time in the driver position before starting.
Some followers might look at it.
## Modules
- Improve default channel handling in module-filter-chain.
- Support source and sink only module-filter-chain.
- Tweak the filter-chain spatializer example gains.
- Handle new snapcast service type. (#5104)
- Implement socket activation without depending on libsystemd.
- Support ipv4 link-local addresses in RAOP and snapcast. (#4830)
- Forward ROC-toolkit logs to pipewire.
## SPA
- Improve default channel handling in filter-graph. (#5084)
- Clamp control values to min/max. (#5088)
- Support mode JBL gaming headsets.
- Handle some SOFA errors and add gain option.
- Really handle more than 64 channels in the channelmixer. (#5118)
- Allow removal in ALSA-udev of ignored cards.
# pulse-server
- Fix mono mixdown query.
- Expose headset autoswitch message.
- Handle EPROTO errors by disconnecting.
- Handle timeouts in play-sample streams. (#5099)
## GStreamer
- Fix crop metadata.
- Fix a race in the buffer release function.
## Tools
- Improve format support and detection in pw-cat.
- Add some more options to pw-cat to list supported containers
and formats. (#5117)
Older versions:
# PipeWire 1.5.85 (2026-01-19)
This is the fifth and hopefully last 1.6 release candidate that
@ -156,6 +57,9 @@ releases.
## Docs
- Document the resampler properties better.
Older versions:
# PipeWire 1.5.84 (2025-11-27)
This is the fourth 1.6 release candidate that is API and ABI

View file

@ -44,7 +44,6 @@
<tab type="usergroup" title="PipeWire Versions">
<tab type="user" url="https://docs.pipewire.org/1.2/" title="1.2.x"/>
<tab type="user" url="https://docs.pipewire.org/1.4/" title="1.4.x"/>
<tab type="user" url="https://docs.pipewire.org/1.6/" title="1.6.x"/>
<tab type="user" url="https://docs.pipewire.org/devel/" title="Development"/>
</tab>
</navindex>

View file

@ -80,9 +80,6 @@ stream.properties = {
#channelmix.fc-cutoff = 12000.0
#channelmix.rear-delay = 12.0
#channelmix.stereo-widen = 0.0
#channelmix.center-level = 0.707106781
#channelmix.surround-level = 0.707106781
#channelmix.lfe-level = 0.5
#channelmix.hilbert-taps = 0
#dither.noise = 0
#dither.method = none # rectangular, triangular, triangular-hf, wannamaker3, shaped5

View file

@ -450,25 +450,11 @@ Whether the node target may be changed using metadata.
@PAR@ node-prop node.passive = false
\parblock
This can be used to configure the port.passive property for all ports of this node.
Possible values are:
* "out": output ports are passive, They will not make the peers active and active peers will
not make this node active.
* "in": input ports are passive, They will not make the peers active and active peers will
not make this node active.
* "true": A combination in "in" and "out", both input and output ports are passive.
* "out-follow": output ports will not make the peer active but when the peer is activated via
some other way, this node will also become active.
* "in-follow": input ports will not make the peer active but when the peer is activated via
some other way, this node will also become active.
* "follow": A combination of "in-follow" and "out-follow".
This is a passive node and so it should not keep sinks/sources busy. This property makes the session manager create passive links to the sink/sources. If the node is not otherwise linked (via a non-passive link), the node and the sink it is linked to are idle (and eventually suspended).
This is used for filter nodes that sit in front of sinks/sources and need to suspend together with the sink/source.
\endparblock
@PAR@ node-prop node.link-group = ID
Add the node to a certain link group. Nodes from the same link group are not automatically linked to each other by the session manager. And example is a coupled stream where you don't want the output to link to the input streams, making a useless loop.
@ -783,15 +769,6 @@ more to the center speaker and leaves the ambient sound in the stereo channels.
This is only active when up-mix is enabled and a Front Center channel is mixed.
\endparblock
@PAR@ node-prop channelmix.center-level = 0.707106781
The level of the center channel when up/downmixing.
@PAR@ node-prop channelmix.surround-level = 0.707106781
The level of the surround channels when up/downmixing.
@PAR@ node-prop channelmix.lfe-level = 0.5
The level of the LFE channel when up/downmixing.
@PAR@ node-prop channelmix.hilbert-taps = 0
\parblock
This option will apply a 90 degree phase shift to the rear channels to improve specialization.
@ -1194,15 +1171,6 @@ in a platform-specific way. See `tests/examples/bt-pinephone.lua` in WirePlumber
Do not enable this setting if you don't know what all this means, as it won't work.
\endparblock
@PAR@ monitor-prop bluez5.hw-offload-datapath # integer
\parblock
HFP/HSP hardware offload data path ID (default: 0).
This feature configures the SCO hardwareoffload data path for HFP/HSP using the Bluetooth
SIGspecified procedure. It is intended for advanced setups and vendor integrations. Do not
edit this unless required; incorrect values can disable SCO offload.
\endparblock
@PAR@ monitor-prop bluez5.a2dp.opus.pro.channels = 3 # integer
PipeWire Opus Pro audio profile channel count.
@ -1234,7 +1202,6 @@ PipeWire Opus Pro audio profile duplex max bitrate.
PipeWire Opus Pro audio profile duplex frame duration (1/10 ms).
@PAR@ monitor-prop bluez5.bcast_source.config = [] # JSON
For a per-adapter configuration of multiple BIGs use an "adapter" entry in the BIG with the BD address.
\parblock
Example:
```
@ -1396,12 +1363,6 @@ BAP QoS framing that needs to be applied for vendor defined preset
This property is experimental.
Default: as per QoS preset.
@PAR@ device-prop bluez5.bap.force-target-latency = "balanced" # string
BAP QoS target latency profile forced for QoS configuration selection.
If not set or set to "balanced", both low-latency and high-reliability QoS configuration table are used.
This property is experimental.
Available: low-latency, high-reliability, balanced
## Node properties
@PAR@ node-prop bluez5.media-source-role # string
@ -1443,11 +1404,6 @@ them. Below are some port properties may interesting for users:
\copydoc PW_KEY_PORT_ALIAS
\endparblock
@PAR@ port-prop port.passive # string
\parblock
\copydoc PW_KEY_PORT_PASSIVE
\endparblock
\see pw_keys in the API documentation for a full list.
# LINK PROPERTIES @IDX@ props

View file

@ -93,9 +93,6 @@ stream.properties = {
#channelmix.fc-cutoff = 12000.0
#channelmix.rear-delay = 12.0
#channelmix.stereo-widen = 0.0
#channelmix.center-level = 0.707106781
#channelmix.surround-level = 0.707106781
#channelmix.lfe-level = 0.5
#channelmix.hilbert-taps = 0
#dither.noise = 0
#dither.method = none # rectangular, triangular, triangular-hf, wannamaker3, shaped5

View file

@ -313,13 +313,12 @@ performed.
Device ID negotiation needs explicit support by both end points of a stream, thus, the
first step of negotiation is discovering whether other peer has support for it. This is
done by advertising a \ref SPA_PARAM_Capability with the key \ref
PW_CAPABILITY_DEVICE_ID_NEGOTIATION and value `1` which corresponds to the
current negotiation API version.
PW_CAPABILITY_DEVICE_ID_NEGOTIATION and value `true`
```
spa_param_dict_build_dict(&b, SPA_PARAM_Capability,
&SPA_DICT_ITEMS(
SPA_DICT_ITEM(PW_CAPABILITY_DEVICE_ID_NEGOTIATION, "1")));
SPA_DICT_ITEM(PW_CAPABILITY_DEVICE_ID_NEGOTIATION, "true")));
```
To do this, when connecting to the stream, the \ref PW_STREAM_FLAG_INACTIVE flag must be
@ -349,10 +348,10 @@ rectangles. For example
params[n_params++] = spa_pod_builder_pop(&b, &f);
```
After having received the first \ref SPA_PARAM_PeerCapability param, if it contained the
\ref PW_CAPABILITY_DEVICE_ID_NEGOTIATION set to a supported API version number, the full
set of formats can be sent using \ref pw_stream_update_params following by activating the
stream usina supported API version numberstream_set_active(stream, true)`.
After having received the first \ref SPA_PARAM_PeerCapability param, if it contained the \ref
PW_CAPABILITY_DEVICE_ID set to `true`, the full set of formats can be sent using \ref
pw_stream_update_params following by activating the stream using
`pw_stream_set_active(stream, true)`.
Note that the first \ref SPA_PARAM_Format received may be the result of the initial format
negotian with bare minimum parameters, and will be superseded by the result of the format
@ -365,15 +364,12 @@ with. This can be used to reduce the amount of devices that are queried for form
metadata, which can be a time consuming task, if devices needs to be woken up.
To achieve this, the consumer adds another \ref SPA_PARAM_PeerCapability item with the key
\ref PW_CAPABILITY_DEVICE_IDS set to a JSON object describing what device IDs are supported.
This JSON object as of version 1 contains a single key "available-devices" that contain
a list of hexadecimal encoded `dev_t` device IDs.
\ref PW_CAPABILITY_DEVICE_IDS set to a string of base 64 encoded `dev_t` device IDs.
```
char *device_ids = "{\"available-devices\": [\"6464000000000000\",\"c8c8000000000000\"]}";
char *device_ids = ...; /* Base 64 encoding of a dev_t. */.
&SPA_DICT_ITEMS(
SPA_DICT_ITEM(PW_CAPABILITY_DEVICE_ID_NEGOTIATION, "1"),
SPA_DICT_ITEM(PW_CAPABILITY_DEVICE_ID_NEGOTIATION, "true"),
SPA_DICT_ITEM(PW_CAPABILITY_DEVICE_IDS, device_ids)));
```

View file

@ -32,11 +32,8 @@ updated as follows:
- \ref spa_io_clock::nsec : Must be set to the time (according to the monotonic
system clock) when the cycle that the driver is about to trigger started. To
minimize jitter, it is usually a good idea to increment this by a computed
amount (instead of sampling a timestamp from the monotonic system clock)
minimize jitter, it is usually a good idea to increment this by a fixed amount
except for when the driver starts and when discontinuities occur in its clock.
The computed amount can be fixed, or varying over time, for example due to
adjustments made by a DLL (more on that below).
- \ref spa_io_clock::rate : Set to a value that can translate samples to nanoseconds.
- \ref spa_io_clock::position : Current cycle position, in samples. This is the
ideal position of the graph cycle (this is explained in greater detail further below).
@ -55,7 +52,7 @@ updated as follows:
some cases, this may actually be in the past relative to nsec, for example, when
some internal driver clock experienced a discontinuity. Consider setting the
\ref SPA_IO_CLOCK_FLAG_DISCONT flag in such a case. Just like with nsec, to
minimize jitter, it is usually a good idea to increment this by a computed amount
minimize jitter, it is usually a good idea to increment this by a fixed amount
except for when the driver starts and when discontinuities occur in its clock.
The driver node signals the start of the graph cycle by calling \ref spa_node_call_ready
@ -63,11 +60,6 @@ with the \ref SPA_STATUS_HAVE_DATA and \ref SPA_STATUS_NEED_DATA flags passed
to that function call. That call must happen inside the thread that runs the
data loop assigned to the driver node.
Drivers must make sure that the next cycle is started at the time indicated by
the \ref spa_io_clock::next_nsec timestamp. They do not have to use the monotonic
clock itself for scheduling the next cycle. If for example the internal clock
can directly be used with \c timerfd , the next cycle can be triggered that way.
As mentioned above, the \ref spa_io_clock::position field is the _ideal_ position
of the graph cycle, in samples. This contrasts with \ref spa_io_clock::nsec, which
is the moment in monotonic clock time when the cycle _actually_ happens. This is an
@ -111,12 +103,11 @@ expected position (in samples) and the actual position (derived from the current
of the driver's internal clock), passes the delta between these two quantities into the
DLL, and the DLL computes a correction factor (2.0 in the above example) which is used
for scaling durations between \c timerfd timeouts. This forms a control loop, since the
correction factor causes the \ref spa_io_clock::next_nsec increments (that is, the
durations between the timerfd timeouts) to be adjusted such that, over time, the difference
between the expected position and the actual position reaches zero. Keep in mind the
notes above about \ref spa_io_clock::position being the ideal position of the graph
cycle, meaning that even in this case, the duration it is incremented by is _not_
scaled by the correction factor; the duration in samples remains unchanged.
correction factor causes the durations between the timeouts to be adjusted such that the
difference between the expected position and the actual position reaches zero. Keep in
mind the notes above about \ref spa_io_clock::position being the ideal position of the
graph cycle, meaning that even in this case, the duration it is incremented by is
_not_ scaled by the correction factor; the duration in samples remains unchanged.
(Other popular control loop mechanisms that are suitable alternatives to the DLL are
PID controllers and Kalman filters.)

View file

@ -62,13 +62,6 @@ As of 1.4, SPA_CONTROL_UMP (Universal Midi Packet) is the prefered format
for the MIDI 1.0 and 2.0 messages in the \ref spa_pod_sequence. Conversion
to SPA_CONTROL_Midi is performed for legacy applications.
As of 1.7 the prefered format is Midi1 again because most devices and
applications are still Midi1 and conversions between Midi1 and UMP are not
completely transparent in ALSA and PipeWire. UMP in the ALSA sequencer
and consumers must be enabled explicitly. UMP in producers is supported
still and will be converted to Midi1 by all consumers that did not explicitly
enable UMP support.
## The PipeWire Daemon
Nothing special is implemented for MIDI. Negotiation of formats
@ -111,14 +104,13 @@ filtering out the \ref SPA_CONTROL_Midi, \ref SPA_CONTROL_OSC and
\ref SPA_CONTROL_UMP types. On output ports, the JACK event stream is
converted to control messages in a similar way.
Normally, all MIDI and UMP input messages are converted to MIDI1 jack
events unless the JACK port was created with an explcit "32 bit raw UMP"
format or with the JackPortIsMIDI2 flag, in which case the messages are
converted to UMP or passed on directly.
For output ports, the JACK events are assumed to be
MIDI1 unless the port has the "32 bit raw UMP" format or the JackPortIsMIDI2
flag, in which case the control messages are assumed to be UMP.
Normally, all MIDI and UMP messages are converted to MIDI1 jack events unless
the JACK port was created with an explcit "32 bit raw UMP" format or with
the JackPortIsMIDI2 flag, in which case the raw UMP is passed to the JACK
application directly. For output ports,
the JACK events are assumed to be MIDI1 and converted to UMP unless the port
has the "32 bit raw UMP" format or the JackPortIsMIDI2 flag, in which case
the UMP messages are simply passed on.
There is a 1 to 1 mapping between the JACK events and control
messages so there is no information loss or need for complicated

View file

@ -81,7 +81,6 @@ List of known modules:
- \subpage page_module_raop_discover
- \subpage page_module_roc_sink
- \subpage page_module_roc_source
- \subpage page_module_scheduler_v1
- \subpage page_module_rtp_sap
- \subpage page_module_rtp_sink
- \subpage page_module_rtp_source
@ -91,8 +90,6 @@ List of known modules:
- \subpage page_module_spa_node_factory
- \subpage page_module_spa_device
- \subpage page_module_spa_device_factory
- \subpage page_module_sendspin_recv
- \subpage page_module_sendspin_send
- \subpage page_module_session_manager
- \subpage page_module_snapcast_discover
- \subpage page_module_vban_recv

View file

@ -77,7 +77,7 @@ Certain properties are, by convention, expected for specific object types.
Each object type has a list of methods that it needs to implement.
The session manager is responsible for defining the list of permissions each client has. Each permission entry is an object ID and five flags. The five flags are:
The session manager is responsible for defining the list of permissions each client has. Each permission entry is an object ID and four flags. The four flags are:
- Read: the object can be seen and events can be received;
- Write: the object can be modified, usually through methods (which requires the execute flag)
@ -109,7 +109,7 @@ Modules in PipeWire can only be loaded in their own process. A client, for examp
Nodes are the core data processing entities in PipeWire.
They may produce data (capture devices, signal generators, ...), consume data (playback devices, network endpoints, ...) or both (filters).
Nodes have a method `process`, which eats up data from input ports and provides data for each output port.
Notes have a method `process`, which eats up data from input ports and provides data for each output port.
#### Ports

View file

@ -24,9 +24,9 @@ Play and record media with PipeWire
**pw-cat** is a simple tool for playing back or capturing raw or encoded
media files on a PipeWire server. It understands all audio file formats
supported by `libsndfile` for PCM capture and playback. When no container
is specified for capturing PCM, the filename extension is used to guess
the file format with the WAV file format as the default.
supported by `libsndfile` for PCM capture and playback. When capturing
PCM, the filename extension is used to guess the file format with the
WAV file format as the default.
It understands standard MIDI files and MIDI 2.0 clip files for playback
and recording. This tool will not render MIDI files, it will simply make
@ -37,15 +37,8 @@ DSD playback is supported with the DSF file format. This tool will only
work with native DSD capable hardware and will produce an error when no
such hardware was found.
When the *FILE* is - input will be from STDIN. If no format is specified,
libsndfile will attempt to parse and stream the format from STDIN. For
some formats, this is not possible and libsndfile will give an error.
Raw, MIDI and DSD formats are all streamable from STDIN.
When the *FILE* is - output will be to STDOUT. If no format is specified,
libsndfile is instructed to output the .au format, which is streamble and
preserves the format, rate and channels.
Raw and DSD formats are all streamable to STDOUT.
When the *FILE* is - input and output will be raw data from STDIN and
STDOUT respectively.
# OPTIONS
@ -94,11 +87,6 @@ DSD mode. *FILE* is a DSF file. If the tool is called under the name
render the DSD audio. You need a DSD capable device to play DSD content
or this program will exit with an error.
\par -s | \--sysex
SysEx mode. *FILE* is a File that contains a raw SysEx MIDI message.
If the tool is called under the name **pw-sysex** this is the default.
The File is read and sent as a MIDI control message into the graph.
\par \--media-type=VALUE
Set the media type property (default Audio/Midi depending on mode). The
media type is used by the session manager to select a suitable target to
@ -124,9 +112,6 @@ Set a node target (default auto). The value can be:
- <b>\<id\></b>: The object.serial or the node.name of a target node
\endparblock
\par -C | \--monitor
In recording mode, record from monitor ports.
\par \--latency=VALUE\[*units*\]
\parblock
Set the node latency (default 100ms)
@ -153,17 +138,6 @@ does not match the samplerate of the server, the data will be resampled.
Higher quality uses more CPU. Values between 0 and 15 are allowed, the
default quality is 4.
\par -a | \--raw
Raw samples will be read or written. The \--rate, \--format, \--channels
and \--channelmap can be used to specify the raw format.
\par -M | \--force-midi
Force midi format, one of "midi" or "ump", (default ump).
When reading or writing midi, for one of midi or UMP.
\par -n | \--sample-count=COUNT
Stop after COUNT samples.
\par \--rate=VALUE
The sample rate, default 48000.
@ -171,38 +145,19 @@ The sample rate, default 48000.
The number of channels, default 2.
\par \--channel-map=VALUE
The channelmap. Possible values include are either a channel layout
such as **mono**, **stereo**,
The channelmap. Possible values include: **mono**, **stereo**,
**surround-21**, **quad**, **surround-22**, **surround-40**,
or comma separated array of channel names such as **FL,FR**.
See \--list-layouts and \--list-channel-names to get a complete
list of possible values.
\par \--list-layouts
List all known channel layouts. One of these can be used as the
\--channel-map value.
\par \--list-channel-names
List all known channel names. An array of these can be used as the
\--channel-map value.
**surround-31**, **surround-41**, **surround-50**, **surround-51**,
**surround-51r**, **surround-70**, **surround-71** or a comma separated
list of channel names: **FL**, **FR**, **FC**, **LFE**, **SL**, **SR**,
**FLC**, **FRC**, **RC**, **RL**, **RR**, **TC**, **TFL**, **TFC**,
**TFR**, **TRL**, **TRC**, **TRR**, **RLC**, **RRC**, **FLW**, **FRW**,
**LFE2**, **FLH**, **FCH**, **FRH**, **TFLC**, **TFRC**, **TSL**,
**TSR**, **LLFR**, **RLFE**, **BC**, **BLC**, **BRC**
\par \--format=VALUE
The sample format to use. Some possible values include: **u8**, **s8**,
**s16** (default), **s24**, **s32**, **f32**, **f64**. See
\--list-formats to get a complete list of values.
\par \--list-formats
List all known format values.
\par \--container=VALUE
Specify the container to use when saving. This is usually guessed from
the filename extension but can be specified explicitly. When using
STDOUT and no container is specified, the AU container will be used.
Then using a filename and the container was not specified and it could
not be derived from the filename, the WAV container is used.
\par \--list-containers
List all known container values.
The sample format to use. One of: **u8**, **s8**, **s16** (default),
**s24**, **s32**, **f32**, **f64**.
\par \--volume=VALUE
The stream volume, default 1.000. Depending on the locale you have

View file

@ -13,7 +13,7 @@ node and device statistics.
A hierarchical view is shown of Driver nodes and follower nodes. The
Driver nodes are actively using a timer to schedule dataflow in the
followers. The followers of a driver node are shown below their driver
followers. The followers of a driver node as shown below their driver
with a + sign (or = for async nodes) in a tree-like representation.
The columns presented are as follows:

View file

@ -1,5 +1,5 @@
project('pipewire', ['c' ],
version : '1.7.0',
version : '1.5.85',
license : [ 'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' ],
meson_version : '>= 0.61.1',
default_options : [ 'warning_level=3',
@ -82,7 +82,6 @@ common_flags = [
'-fvisibility=hidden',
'-fno-strict-aliasing',
'-fno-strict-overflow',
'-DSPA_AUDIO_MAX_CHANNELS=128u',
'-Werror=suggest-attribute=format',
'-Wsign-compare',
'-Wpointer-arith',
@ -116,7 +115,7 @@ cc_flags = common_flags + [
'-Werror=old-style-definition',
'-Werror=missing-parameter-type',
'-Werror=strict-prototypes',
'-Werror=discarded-qualifiers',
'-DSPA_AUDIO_MAX_CHANNELS=128u',
]
add_project_arguments(cc.get_supported_arguments(cc_flags), language: 'c')
add_project_arguments(cc_native.get_supported_arguments(cc_flags),
@ -368,7 +367,7 @@ cdata.set('HAVE_OPUS', opus_dep.found())
summary({'readline (for pw-cli)': readline_dep.found()}, bool_yn: true, section: 'Misc dependencies')
cdata.set('HAVE_READLINE', readline_dep.found())
ncurses_dep = dependency('ncursesw', required : false)
sndfile_dep = dependency('sndfile', version : '>= 1.1.0', required : get_option('sndfile'))
sndfile_dep = dependency('sndfile', version : '>= 1.0.20', required : get_option('sndfile'))
summary({'sndfile': sndfile_dep.found()}, bool_yn: true, section: 'pw-cat/pw-play/pw-dump/filter-chain')
cdata.set('HAVE_SNDFILE', sndfile_dep.found())
pulseaudio_dep = dependency('libpulse', required : get_option('libpulse'))
@ -412,7 +411,7 @@ gst_deps_def = {
'gio-unix-2.0': {},
'gstreamer-1.0': {'version': '>= 1.10.0'},
'gstreamer-base-1.0': {},
'gstreamer-video-1.0': {'version': '>= 1.22.0'},
'gstreamer-video-1.0': {},
'gstreamer-audio-1.0': {},
'gstreamer-allocators-1.0': {},
}

View file

@ -55,7 +55,7 @@ pipewire_jackserver = shared_library('jackserver',
pipewire_jackserver_sources,
soversion : soversion,
version : libjackversion,
c_args : pipewire_jack_c_args + '-DLIBJACKSERVER',
c_args : pipewire_jack_c_args,
include_directories : [configinc, jack_inc],
dependencies : [pipewire_dep, mathlib],
install : true,

View file

@ -86,7 +86,7 @@ PW_LOG_TOPIC_STATIC(jack_log_topic, "jack");
#define OTHER_CONNECT_FAIL -1
#define OTHER_CONNECT_IGNORE 0
#define NOTIFY_BUFFER_SIZE (1u<<16)
#define NOTIFY_BUFFER_SIZE (1u<<13)
#define NOTIFY_BUFFER_MASK (NOTIFY_BUFFER_SIZE-1)
struct notify {
@ -104,8 +104,8 @@ struct notify {
#define NOTIFY_TYPE_TOTAL_LATENCY ((9<<4)|NOTIFY_ACTIVE_FLAG)
#define NOTIFY_TYPE_PORT_RENAME ((10<<4)|NOTIFY_ACTIVE_FLAG)
int type;
int arg1;
struct object *object;
int arg1;
const char *msg;
};
@ -492,8 +492,6 @@ struct client {
jack_position_t jack_position;
jack_transport_state_t jack_state;
struct frame_times jack_times;
struct object dummy_port;
};
#define return_val_if_fail(expr, val) \
@ -1448,9 +1446,8 @@ static size_t convert_from_event(void *midi, void *buffer, size_t size, uint32_t
switch (type) {
case TYPE_ID_MIDI:
event_type = SPA_CONTROL_Midi;
break;
case TYPE_ID_OSC:
/* we handle MIDI as OSC, check below */
event_type = SPA_CONTROL_OSC;
break;
case TYPE_ID_UMP:
@ -1467,15 +1464,27 @@ static size_t convert_from_event(void *midi, void *buffer, size_t size, uint32_t
for (i = 0; i < count; i++) {
jack_midi_event_t ev;
jack_midi_event_get(&ev, midi, i);
uint32_t ev_type;
if (type == TYPE_ID_MIDI && is_osc(&ev))
ev_type = SPA_CONTROL_OSC;
else
ev_type = event_type;
spa_pod_builder_control(&b, ev.time, ev_type);
if (type != TYPE_ID_MIDI || is_osc(&ev)) {
/* no midi port or it's OSC */
spa_pod_builder_control(&b, ev.time, event_type);
spa_pod_builder_bytes(&b, ev.buffer, ev.size);
} else {
/* midi port and it's not OSC, convert to UMP */
uint8_t *data = ev.buffer;
size_t size = ev.size;
uint64_t state = 0;
while (size > 0) {
uint32_t ump[4];
int ump_size = spa_ump_from_midi(&data, &size,
ump, sizeof(ump), 0, &state);
if (ump_size <= 0)
break;
spa_pod_builder_control(&b, ev.time, SPA_CONTROL_UMP);
spa_pod_builder_bytes(&b, ump, ump_size);
}
}
}
spa_pod_builder_pop(&b, &f);
return b.state.offset;
@ -2199,7 +2208,7 @@ on_rtsocket_condition(void *data, int fd, uint32_t mask)
}
} else if (SPA_LIKELY(mask & SPA_IO_IN)) {
uint32_t buffer_frames;
int status = -EBUSY;
int status = 0;
buffer_frames = cycle_run(c);
@ -4459,11 +4468,6 @@ jack_client_t * jack_client_open (const char *client_name,
0, NULL, &client->info);
client->info.change_mask = 0;
client->dummy_port.type = INTERFACE_Port;
snprintf(client->dummy_port.port.name, sizeof(client->dummy_port.port.name), "%s:dummy", client_name);
snprintf(client->dummy_port.port.alias1, sizeof(client->dummy_port.port.alias1), "%s:dummy", client_name);
snprintf(client->dummy_port.port.alias2, sizeof(client->dummy_port.port.alias2), "%s:dummy", client_name);
client->show_monitor = pw_properties_get_bool(client->props, "jack.show-monitor", true);
client->show_midi = pw_properties_get_bool(client->props, "jack.show-midi", true);
client->merge_monitor = pw_properties_get_bool(client->props, "jack.merge-monitor", true);
@ -4864,7 +4868,7 @@ int jack_activate (jack_client_t *client)
freeze_callbacks(c);
/* reemit buffer_frames */
c->buffer_frames = (uint32_t)-1;
c->buffer_frames = 0;
pw_data_loop_start(c->loop);
c->active = true;
@ -4876,21 +4880,9 @@ int jack_activate (jack_client_t *client)
c->activation->pending_sync = true;
spa_list_for_each(o, &c->context.objects, link) {
#if !defined(LIBJACKSERVER)
if (o->type != INTERFACE_Port || o->port.port == NULL ||
o->port.port->client != c || !o->port.port->valid)
continue;
#else
/* emits all foreign active ports, skips own (already announced via jack_port_register) */
if (o->type != INTERFACE_Port || o->removed)
continue;
/* own ports are handled by jack_port_register */
if (o->port.port != NULL && o->port.port->client == c)
continue;
/* only announce ports whose node is active */
if (o->port.node != NULL && !node_is_active(c, o->port.node))
continue;
#endif
o->registered = 0;
queue_notify(c, NOTIFY_TYPE_PORTREGISTRATION, o, 1, NULL);
}
@ -5326,7 +5318,7 @@ int jack_set_freewheel(jack_client_t* client, int onoff)
pw_thread_loop_lock(c->context.loop);
str = pw_properties_get(c->props, PW_KEY_NODE_GROUP);
if (str != NULL) {
const char *p = strstr(str, ",pipewire.freewheel");
char *p = strstr(str, ",pipewire.freewheel");
if (p == NULL)
p = strstr(str, "pipewire.freewheel");
if (p == NULL && onoff)
@ -5445,7 +5437,7 @@ SPA_EXPORT
jack_nframes_t jack_get_buffer_size (jack_client_t *client)
{
struct client *c = (struct client *) client;
uint32_t res = -1;
jack_nframes_t res = -1;
return_val_if_fail(c != NULL, 0);
@ -5462,7 +5454,7 @@ jack_nframes_t jack_get_buffer_size (jack_client_t *client)
}
c->buffer_frames = res;
pw_log_debug("buffer_frames: %u", res);
return (jack_nframes_t)res;
return res;
}
SPA_EXPORT
@ -5959,7 +5951,9 @@ static const char *port_name(struct object *o)
{
const char *name;
struct client *c = o->client;
if (c != NULL && c->default_as_system && is_port_default(c, o))
if (c == NULL)
return NULL;
if (c->default_as_system && is_port_default(c, o))
name = o->port.system;
else
name = o->port.name;
@ -6013,16 +6007,7 @@ jack_port_type_id_t jack_port_type_id (const jack_port_t *port)
return_val_if_fail(o != NULL, 0);
if (o->type != INTERFACE_Port)
return TYPE_ID_OTHER;
/* map internal type IDs to jack1/jack2 compatible public values */
switch (o->port.type_id) {
case TYPE_ID_AUDIO: return 0;
case TYPE_ID_MIDI:
case TYPE_ID_OSC:
case TYPE_ID_UMP: return 1; /* all MIDI variants map to 1 */
case TYPE_ID_VIDEO: return 3; /* video maps to 3 */
default: return o->port.type_id;
}
return o->port.type_id;
}
SPA_EXPORT
@ -7014,11 +6999,13 @@ jack_port_t * jack_port_by_id (jack_client_t *client,
pthread_mutex_lock(&c->context.lock);
res = find_by_serial(c, port_id);
pthread_mutex_unlock(&c->context.lock);
if (res == NULL || res->type != INTERFACE_Port)
res = &c->dummy_port;
if (res && res->type != INTERFACE_Port)
res = NULL;
pw_log_debug("%p: port %d -> %p", c, port_id, res);
pthread_mutex_unlock(&c->context.lock);
if (res == NULL)
pw_log_info("%p: port %d not found", c, port_id);
return object_to_port(res);
}

573
po/kk.po
View file

@ -1,14 +1,15 @@
# Kazakh translation of pipewire.
# Copyright (C) 2020 The pipewire authors.
# This file is distributed under the same license as the pipewire package.
# Baurzhan Muftakhidinov <baurthefirst@gmail.com>, 2020-2026.
# Baurzhan Muftakhidinov <baurthefirst@gmail.com>, 2020.
#
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/-/issues\n"
"POT-Creation-Date: 2026-03-09 12:19+0000\n"
"PO-Revision-Date: 2026-03-17 00:04+0500\n"
"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/"
"issues/new\n"
"POT-Creation-Date: 2021-04-18 16:54+0800\n"
"PO-Revision-Date: 2020-06-30 08:04+0500\n"
"Last-Translator: Baurzhan Muftakhidinov <baurthefirst@gmail.com>\n"
"Language-Team: \n"
"Language: kk\n"
@ -16,199 +17,96 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 3.9\n"
"X-Generator: Poedit 2.3.1\n"
#: src/daemon/pipewire.c:29
#: src/daemon/pipewire.c:43
#, c-format
msgid ""
"%s [options]\n"
" -h, --help Show this help\n"
" -v, --verbose Increase verbosity by one level\n"
" --version Show version\n"
" -c, --config Load config (Default %s)\n"
" -P --properties Set context properties\n"
msgstr ""
"%s [опциялар]\n"
" -h, --help Осы көмекті көрсету\n"
" -v, --verbose Ақпараттылығын бір деңгейге арттыру\n"
" --version Нұсқасын көрсету\n"
" -c, --config Конфигурацияны жүктеу (Бастапқы %s)\n"
" -P --properties Контекст қасиеттерін орнату\n"
#: src/daemon/pipewire.desktop.in:3
msgid "PipeWire Media System"
msgstr "PipeWire медиа жүйесі"
#: src/daemon/pipewire.desktop.in:4
msgid "PipeWire Media System"
msgstr ""
#: src/daemon/pipewire.desktop.in:5
msgid "Start the PipeWire Media System"
msgstr "PipeWire медиа жүйесін іске қосу"
msgstr ""
#: src/modules/module-protocol-pulse/modules/module-tunnel-sink.c:159
#: src/modules/module-protocol-pulse/modules/module-tunnel-source.c:159
#, c-format
msgid "Tunnel to %s%s%s"
msgstr "%s%s%s бағытына туннель"
#: src/examples/media-session/alsa-monitor.c:526
#: spa/plugins/alsa/acp/compat.c:187
msgid "Built-in Audio"
msgstr "Құрамындағы аудио"
#: src/modules/module-fallback-sink.c:40
msgid "Dummy Output"
msgstr "Жалған шығыс"
#: src/examples/media-session/alsa-monitor.c:530
#: spa/plugins/alsa/acp/compat.c:192
msgid "Modem"
msgstr "Модем"
#: src/modules/module-pulse-tunnel.c:761
#, c-format
msgid "Tunnel for %s@%s"
msgstr "%s@%s үшін туннель"
#: src/modules/module-zeroconf-discover.c:290
#: src/examples/media-session/alsa-monitor.c:539
msgid "Unknown device"
msgstr "Белгісіз құрылғы"
msgstr ""
#: src/modules/module-zeroconf-discover.c:302
#, c-format
msgid "%s on %s@%s"
msgstr "%s, %s@%s ішінде"
#: src/modules/module-zeroconf-discover.c:306
#, c-format
msgid "%s on %s"
msgstr "%s, %s ішінде"
#: src/tools/pw-cat.c:269
#, c-format
msgid "Supported formats:\n"
msgstr "Қолдау көрсетілетін пішімдер:\n"
#: src/tools/pw-cat.c:754
#, c-format
msgid "Supported channel layouts:\n"
msgstr "Қолдау көрсетілетін арна жаймалары:\n"
#: src/tools/pw-cat.c:764
#, c-format
msgid "Supported channel layout aliases:\n"
msgstr "Қолдау көрсетілетін арна жаймаларының алиастары:\n"
#: src/tools/pw-cat.c:766
#, c-format
msgid " %s -> %s\n"
msgstr " %s -> %s\n"
#: src/tools/pw-cat.c:771
#, c-format
msgid "Supported channel names:\n"
msgstr "Қолдау көрсетілетін арна атаулары:\n"
#: src/tools/pw-cat.c:1182
#: src/tools/pw-cat.c:991
#, c-format
msgid ""
"%s [options] [<file>|-]\n"
"%s [options] <file>\n"
" -h, --help Show this help\n"
" --version Show version\n"
" -v, --verbose Enable verbose operations\n"
"\n"
msgstr ""
"%s [опциялар] [<файл>|-]\n"
" -h, --help Осы көмекті көрсету\n"
" --version Нұсқасын көрсету\n"
" -v, --verbose Толық ақпаратты іске қосу\n"
"\n"
#: src/tools/pw-cat.c:1189
#: src/tools/pw-cat.c:998
#, c-format
msgid ""
" -R, --remote Remote daemon name\n"
" --media-type Set media type (default %s)\n"
" --media-category Set media category (default %s)\n"
" --media-role Set media role (default %s)\n"
" --target Set node target serial or name (default %s)\n"
" --target Set node target (default %s)\n"
" 0 means don't link\n"
" --latency Set node latency (default %s)\n"
" Xunit (unit = s, ms, us, ns)\n"
" or direct samples (256)\n"
" the rate is the one of the source file\n"
" -P --properties Set node properties\n"
" the rate is the one of the source "
"file\n"
" --list-targets List available targets for --target\n"
"\n"
msgstr ""
" -R, --remote Қашықтағы қызмет атауы\n"
" --media-type Медиа түрін орнату (бастапқы %s)\n"
" --media-category Медиа категориясын орнату (бастапқы %s)\n"
" --media-role Медиа рөлін орнату (бастапқы %s)\n"
" --target Түйін мақсатының сериялық нөмірін немесе атын орнату (бастапқы "
"%s)\n"
" 0 байланыстырмауды білдіреді\n"
" --latency Түйін кідірісін орнату (бастапқы %s)\n"
" Xюнит (юнит = с, мс, мкс, нс)\n"
" немесе тікелей үлгілер (256)\n"
" жиілік бастапқы файлдың жиілігі болып табылады\n"
" -P --properties Түйін қасиеттерін орнату\n"
"\n"
#: src/tools/pw-cat.c:1207
#: src/tools/pw-cat.c:1016
#, c-format
msgid ""
" --rate Sample rate (default %u)\n"
" --channels Number of channels (default %u)\n"
" --rate Sample rate (req. for rec) (default "
"%u)\n"
" --channels Number of channels (req. for rec) "
"(default %u)\n"
" --channel-map Channel map\n"
" a channel layout: \"Stereo\", \"5.1\",... or\n"
" comma separated list of channel names: eg. \"FL,FR\"\n"
" --list-layouts List supported channel layouts\n"
" --list-channel-names List supported channel maps\n"
" --format Sample format (default %s)\n"
" --list-formats List supported sample formats\n"
" --container Container format\n"
" --list-containers List supported containers and extensions\n"
" one of: \"stereo\", "
"\"surround-51\",... or\n"
" comma separated list of channel "
"names: eg. \"FL,FR\"\n"
" --format Sample format %s (req. for rec) "
"(default %s)\n"
" --volume Stream volume 0-1.0 (default %.3f)\n"
" -q --quality Resampler quality (0 - 15) (default %d)\n"
" -a, --raw RAW mode\n"
" -M, --force-midi Force midi format, one of \"midi\" or \"ump\", (default ump)\n"
" -n, --sample-count COUNT Stop after COUNT samples\n"
" -q --quality Resampler quality (0 - 15) (default "
"%d)\n"
"\n"
msgstr ""
" --rate Дискреттеу жиілігі (бастапқы %u)\n"
" --channels Арналар саны (бастапқы %u)\n"
" --channel-map Арналар картасы\n"
" арна жаймасы: «Stereo», «5.1»,... немесе\n"
" үтірмен ажыратылған арна атауларының тізімі: мысалы, "
"«FL,FR»\n"
" --list-layouts Қолдау көрсетілетін арна жаймаларын тізімдеу\n"
" --list-channel-names Қолдау көрсетілетін арналар картасын тізімдеу\n"
" --format Дискреттеу пішімі (бастапқы %s)\n"
" --list-formats Қолдау көрсетілетін дискреттеу пішімдерін тізімдеу\n"
" --container Контейнер пішімі\n"
" --list-containers Қолдау көрсетілетін контейнерлер мен кеңейтулерді тізімдеу\n"
" --volume Ағын дыбыс деңгейі 0-1.0 (бастапқы %.3f)\n"
" -q --quality Қайта дискреттеу сапасы (0 - 15) (бастапқы %d)\n"
" -a, --raw RAW режимі\n"
" -M, --force-midi Midi пішімін мәжбүрлеу, «midi» немесе «ump» біреуі, (бастапқы "
"ump)\n"
" -n, --sample-count COUNT COUNT үлгісінен кейін тоқтату\n"
"\n"
#: src/tools/pw-cat.c:1232
#: src/tools/pw-cat.c:1033
msgid ""
" -p, --playback Playback mode\n"
" -r, --record Recording mode\n"
" -m, --midi Midi mode\n"
" -d, --dsd DSD mode\n"
" -o, --encoded Encoded mode\n"
" -s, --sysex SysEx mode\n"
" -c, --midi-clip MIDI clip mode\n"
"\n"
msgstr ""
" -p, --playback Ойнату режимі\n"
" -r, --record Жазу режимі\n"
" -m, --midi Midi режимі\n"
" -d, --dsd DSD режимі\n"
" -o, --encoded Шифрленген режим\n"
" -s, --sysex SysEx режимі\n"
" -c, --midi-clip MIDI clip режимі\n"
"\n"
#: src/tools/pw-cat.c:1837
#, c-format
msgid "Supported containers and extensions:\n"
msgstr "Қолдау көрсетілетін контейнерлер мен кеңейтулер:\n"
#: src/tools/pw-cli.c:2386
#: src/tools/pw-cli.c:2932
#, c-format
msgid ""
"%s [options] [command]\n"
@ -216,506 +114,465 @@ msgid ""
" --version Show version\n"
" -d, --daemon Start as daemon (Default false)\n"
" -r, --remote Remote daemon name\n"
" -m, --monitor Monitor activity\n"
"\n"
msgstr ""
"%s [опциялар] [команда]\n"
" -h, --help Осы көмекті көрсету\n"
" --version Нұсқасын көрсету\n"
" -d, --daemon Қызмет ретінде іске қосу (Бастапқы false)\n"
" -r, --remote Қашықтағы қызмет атауы\n"
" -m, --monitor Белсенділікті бақылау\n"
"\n"
#: spa/plugins/alsa/acp/acp.c:361
#: spa/plugins/alsa/acp/acp.c:290
msgid "Pro Audio"
msgstr "Кәсіби аудио"
msgstr ""
#: spa/plugins/alsa/acp/acp.c:535 spa/plugins/alsa/acp/alsa-mixer.c:4699
#: spa/plugins/bluez5/bluez5-device.c:2021
#: spa/plugins/alsa/acp/acp.c:411 spa/plugins/alsa/acp/alsa-mixer.c:4704
#: spa/plugins/bluez5/bluez5-device.c:1000
msgid "Off"
msgstr "Сөнд."
#: spa/plugins/alsa/acp/acp.c:618
#, c-format
msgid "%s [ALSA UCM error]"
msgstr "%s [ALSA UCM қатесі]"
#: spa/plugins/alsa/acp/channelmap.h:466
msgid "(invalid)"
msgstr "(жарамсыз)"
#: spa/plugins/alsa/acp/alsa-mixer.c:2721
#: spa/plugins/alsa/acp/alsa-mixer.c:2709
msgid "Input"
msgstr "Кіріс"
#: spa/plugins/alsa/acp/alsa-mixer.c:2722
#: spa/plugins/alsa/acp/alsa-mixer.c:2710
msgid "Docking Station Input"
msgstr "Док-станция кірісі"
#: spa/plugins/alsa/acp/alsa-mixer.c:2723
#: spa/plugins/alsa/acp/alsa-mixer.c:2711
msgid "Docking Station Microphone"
msgstr "Док-станция микрофоны"
#: spa/plugins/alsa/acp/alsa-mixer.c:2724
#: spa/plugins/alsa/acp/alsa-mixer.c:2712
msgid "Docking Station Line In"
msgstr "Док-станцияның сызықтық кірісі"
#: spa/plugins/alsa/acp/alsa-mixer.c:2725 spa/plugins/alsa/acp/alsa-mixer.c:2816
#: spa/plugins/alsa/acp/alsa-mixer.c:2713
#: spa/plugins/alsa/acp/alsa-mixer.c:2804
msgid "Line In"
msgstr "Сызықтық кіріс"
#: spa/plugins/alsa/acp/alsa-mixer.c:2726 spa/plugins/alsa/acp/alsa-mixer.c:2810
#: spa/plugins/bluez5/bluez5-device.c:2422
#: spa/plugins/alsa/acp/alsa-mixer.c:2714
#: spa/plugins/alsa/acp/alsa-mixer.c:2798
#: spa/plugins/bluez5/bluez5-device.c:1145
msgid "Microphone"
msgstr "Микрофон"
#: spa/plugins/alsa/acp/alsa-mixer.c:2727 spa/plugins/alsa/acp/alsa-mixer.c:2811
#: spa/plugins/alsa/acp/alsa-mixer.c:2715
#: spa/plugins/alsa/acp/alsa-mixer.c:2799
msgid "Front Microphone"
msgstr "Алдыңғы микрофон"
#: spa/plugins/alsa/acp/alsa-mixer.c:2728 spa/plugins/alsa/acp/alsa-mixer.c:2812
#: spa/plugins/alsa/acp/alsa-mixer.c:2716
#: spa/plugins/alsa/acp/alsa-mixer.c:2800
msgid "Rear Microphone"
msgstr "Артқы микрофон"
#: spa/plugins/alsa/acp/alsa-mixer.c:2729
#: spa/plugins/alsa/acp/alsa-mixer.c:2717
msgid "External Microphone"
msgstr "Сыртқы микрофон"
#: spa/plugins/alsa/acp/alsa-mixer.c:2730 spa/plugins/alsa/acp/alsa-mixer.c:2814
#: spa/plugins/alsa/acp/alsa-mixer.c:2718
#: spa/plugins/alsa/acp/alsa-mixer.c:2802
msgid "Internal Microphone"
msgstr "Ішкі микрофон"
#: spa/plugins/alsa/acp/alsa-mixer.c:2731 spa/plugins/alsa/acp/alsa-mixer.c:2817
#: spa/plugins/alsa/acp/alsa-mixer.c:2719
#: spa/plugins/alsa/acp/alsa-mixer.c:2805
msgid "Radio"
msgstr "Радио"
#: spa/plugins/alsa/acp/alsa-mixer.c:2732 spa/plugins/alsa/acp/alsa-mixer.c:2818
#: spa/plugins/alsa/acp/alsa-mixer.c:2720
#: spa/plugins/alsa/acp/alsa-mixer.c:2806
msgid "Video"
msgstr "Видео"
#: spa/plugins/alsa/acp/alsa-mixer.c:2733
#: spa/plugins/alsa/acp/alsa-mixer.c:2721
msgid "Automatic Gain Control"
msgstr "Күшейтуді автореттеу"
#: spa/plugins/alsa/acp/alsa-mixer.c:2734
#: spa/plugins/alsa/acp/alsa-mixer.c:2722
msgid "No Automatic Gain Control"
msgstr "Күшейтуді автореттеу жоқ"
#: spa/plugins/alsa/acp/alsa-mixer.c:2735
#: spa/plugins/alsa/acp/alsa-mixer.c:2723
msgid "Boost"
msgstr "Күшейту"
#: spa/plugins/alsa/acp/alsa-mixer.c:2736
#: spa/plugins/alsa/acp/alsa-mixer.c:2724
msgid "No Boost"
msgstr "Күшейту жоқ"
#: spa/plugins/alsa/acp/alsa-mixer.c:2737
#: spa/plugins/alsa/acp/alsa-mixer.c:2725
msgid "Amplifier"
msgstr "Күшейткіш"
#: spa/plugins/alsa/acp/alsa-mixer.c:2738
#: spa/plugins/alsa/acp/alsa-mixer.c:2726
msgid "No Amplifier"
msgstr "Күшейткіш жоқ"
#: spa/plugins/alsa/acp/alsa-mixer.c:2739
#: spa/plugins/alsa/acp/alsa-mixer.c:2727
msgid "Bass Boost"
msgstr "Бас күшейту"
#: spa/plugins/alsa/acp/alsa-mixer.c:2740
#: spa/plugins/alsa/acp/alsa-mixer.c:2728
msgid "No Bass Boost"
msgstr "Бас күшейту жоқ"
#: spa/plugins/alsa/acp/alsa-mixer.c:2741 spa/plugins/bluez5/bluez5-device.c:2428
#: spa/plugins/alsa/acp/alsa-mixer.c:2729
#: spa/plugins/bluez5/bluez5-device.c:1150
msgid "Speaker"
msgstr "Динамик"
#. Don't call it "headset", the HF one has the mic
#: spa/plugins/alsa/acp/alsa-mixer.c:2742 spa/plugins/alsa/acp/alsa-mixer.c:2820
#: spa/plugins/bluez5/bluez5-device.c:2434 spa/plugins/bluez5/bluez5-device.c:2501
#: spa/plugins/alsa/acp/alsa-mixer.c:2730
#: spa/plugins/alsa/acp/alsa-mixer.c:2808
msgid "Headphones"
msgstr "Құлаққаптар"
#: spa/plugins/alsa/acp/alsa-mixer.c:2809
#: spa/plugins/alsa/acp/alsa-mixer.c:2797
msgid "Analog Input"
msgstr "Аналогтық кіріс"
#: spa/plugins/alsa/acp/alsa-mixer.c:2813
#: spa/plugins/alsa/acp/alsa-mixer.c:2801
msgid "Dock Microphone"
msgstr "Док-станция микрофоны"
#: spa/plugins/alsa/acp/alsa-mixer.c:2815
#: spa/plugins/alsa/acp/alsa-mixer.c:2803
msgid "Headset Microphone"
msgstr "Гарнитура микрофоны"
#: spa/plugins/alsa/acp/alsa-mixer.c:2819
#: spa/plugins/alsa/acp/alsa-mixer.c:2807
msgid "Analog Output"
msgstr "Аналогтық шығыс"
#: spa/plugins/alsa/acp/alsa-mixer.c:2821
#: spa/plugins/alsa/acp/alsa-mixer.c:2809
#, fuzzy
msgid "Headphones 2"
msgstr "Құлаққап 2"
msgstr "Құлаққаптар"
#: spa/plugins/alsa/acp/alsa-mixer.c:2822
#: spa/plugins/alsa/acp/alsa-mixer.c:2810
msgid "Headphones Mono Output"
msgstr "Құлаққаптардың моно шығысы"
#: spa/plugins/alsa/acp/alsa-mixer.c:2823
#: spa/plugins/alsa/acp/alsa-mixer.c:2811
msgid "Line Out"
msgstr "Сызықтық шығыс"
#: spa/plugins/alsa/acp/alsa-mixer.c:2824
#: spa/plugins/alsa/acp/alsa-mixer.c:2812
msgid "Analog Mono Output"
msgstr "Аналогтық моно шығысы"
#: spa/plugins/alsa/acp/alsa-mixer.c:2825
#: spa/plugins/alsa/acp/alsa-mixer.c:2813
msgid "Speakers"
msgstr "Динамиктер"
#: spa/plugins/alsa/acp/alsa-mixer.c:2826
#: spa/plugins/alsa/acp/alsa-mixer.c:2814
msgid "HDMI / DisplayPort"
msgstr "HDMI / DisplayPort"
#: spa/plugins/alsa/acp/alsa-mixer.c:2827
#: spa/plugins/alsa/acp/alsa-mixer.c:2815
msgid "Digital Output (S/PDIF)"
msgstr "Цифрлық шығыс (S/PDIF)"
#: spa/plugins/alsa/acp/alsa-mixer.c:2828
#: spa/plugins/alsa/acp/alsa-mixer.c:2816
msgid "Digital Input (S/PDIF)"
msgstr "Цифрлық кіріс (S/PDIF)"
#: spa/plugins/alsa/acp/alsa-mixer.c:2829
#: spa/plugins/alsa/acp/alsa-mixer.c:2817
msgid "Multichannel Input"
msgstr "Көпарналы кіріс"
#: spa/plugins/alsa/acp/alsa-mixer.c:2830
#: spa/plugins/alsa/acp/alsa-mixer.c:2818
msgid "Multichannel Output"
msgstr "Көпарналы шығыс"
#: spa/plugins/alsa/acp/alsa-mixer.c:2831
#: spa/plugins/alsa/acp/alsa-mixer.c:2819
msgid "Game Output"
msgstr "Ойын шығысы"
#: spa/plugins/alsa/acp/alsa-mixer.c:2832 spa/plugins/alsa/acp/alsa-mixer.c:2833
#: spa/plugins/alsa/acp/alsa-mixer.c:2820
#: spa/plugins/alsa/acp/alsa-mixer.c:2821
msgid "Chat Output"
msgstr "Чат шығысы"
#: spa/plugins/alsa/acp/alsa-mixer.c:2834
#: spa/plugins/alsa/acp/alsa-mixer.c:2822
#, fuzzy
msgid "Chat Input"
msgstr "Чат кірісі"
msgstr "Чат шығысы"
#: spa/plugins/alsa/acp/alsa-mixer.c:2835
#: spa/plugins/alsa/acp/alsa-mixer.c:2823
#, fuzzy
msgid "Virtual Surround 7.1"
msgstr "Виртуалды көлемді дыбыс 7.1"
msgstr "Виртуалды көлемді аудиоқабылдағыш"
#: spa/plugins/alsa/acp/alsa-mixer.c:4522
#: spa/plugins/alsa/acp/alsa-mixer.c:4527
msgid "Analog Mono"
msgstr "Аналогтық моно"
#: spa/plugins/alsa/acp/alsa-mixer.c:4523
#: spa/plugins/alsa/acp/alsa-mixer.c:4528
#, fuzzy
msgid "Analog Mono (Left)"
msgstr "Аналогты моно (Сол жақ)"
msgstr "Аналогтық моно"
#: spa/plugins/alsa/acp/alsa-mixer.c:4524
#: spa/plugins/alsa/acp/alsa-mixer.c:4529
#, fuzzy
msgid "Analog Mono (Right)"
msgstr "Аналогты моно (Оң жақ)"
msgstr "Аналогтық моно"
#. Note: Not translated to "Analog Stereo Input", because the source
#. * name gets "Input" appended to it automatically, so adding "Input"
#. * 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:4525 spa/plugins/alsa/acp/alsa-mixer.c:4533
#: spa/plugins/alsa/acp/alsa-mixer.c:4534
#: spa/plugins/alsa/acp/alsa-mixer.c:4530
#: spa/plugins/alsa/acp/alsa-mixer.c:4538
#: spa/plugins/alsa/acp/alsa-mixer.c:4539
msgid "Analog Stereo"
msgstr "Аналогтық стерео"
#: spa/plugins/alsa/acp/alsa-mixer.c:4526
#: spa/plugins/alsa/acp/alsa-mixer.c:4531
msgid "Mono"
msgstr "Моно"
#: spa/plugins/alsa/acp/alsa-mixer.c:4527
#: spa/plugins/alsa/acp/alsa-mixer.c:4532
msgid "Stereo"
msgstr "Стерео"
#: spa/plugins/alsa/acp/alsa-mixer.c:4535 spa/plugins/alsa/acp/alsa-mixer.c:4693
#: spa/plugins/bluez5/bluez5-device.c:2410
#: spa/plugins/alsa/acp/alsa-mixer.c:4540
#: spa/plugins/alsa/acp/alsa-mixer.c:4698
#: spa/plugins/bluez5/bluez5-device.c:1135
msgid "Headset"
msgstr "Гарнитура"
#: spa/plugins/alsa/acp/alsa-mixer.c:4536 spa/plugins/alsa/acp/alsa-mixer.c:4694
#: spa/plugins/alsa/acp/alsa-mixer.c:4541
#: spa/plugins/alsa/acp/alsa-mixer.c:4699
#, fuzzy
msgid "Speakerphone"
msgstr "Динамик"
#: spa/plugins/alsa/acp/alsa-mixer.c:4537 spa/plugins/alsa/acp/alsa-mixer.c:4538
#: spa/plugins/alsa/acp/alsa-mixer.c:4542
#: spa/plugins/alsa/acp/alsa-mixer.c:4543
msgid "Multichannel"
msgstr "Көпарналы"
#: spa/plugins/alsa/acp/alsa-mixer.c:4539
#: spa/plugins/alsa/acp/alsa-mixer.c:4544
msgid "Analog Surround 2.1"
msgstr "Аналогтық көлемді 2.1"
#: spa/plugins/alsa/acp/alsa-mixer.c:4540
#: spa/plugins/alsa/acp/alsa-mixer.c:4545
msgid "Analog Surround 3.0"
msgstr "Аналогтық көлемді 3.0"
#: spa/plugins/alsa/acp/alsa-mixer.c:4541
#: spa/plugins/alsa/acp/alsa-mixer.c:4546
msgid "Analog Surround 3.1"
msgstr "Аналогтық көлемді 3.1"
#: spa/plugins/alsa/acp/alsa-mixer.c:4542
#: spa/plugins/alsa/acp/alsa-mixer.c:4547
msgid "Analog Surround 4.0"
msgstr "Аналогтық көлемді 4.0"
#: spa/plugins/alsa/acp/alsa-mixer.c:4543
#: spa/plugins/alsa/acp/alsa-mixer.c:4548
msgid "Analog Surround 4.1"
msgstr "Аналогтық көлемді 4.1"
#: spa/plugins/alsa/acp/alsa-mixer.c:4544
#: spa/plugins/alsa/acp/alsa-mixer.c:4549
msgid "Analog Surround 5.0"
msgstr "Аналогтық көлемді 5.0"
#: spa/plugins/alsa/acp/alsa-mixer.c:4545
#: spa/plugins/alsa/acp/alsa-mixer.c:4550
msgid "Analog Surround 5.1"
msgstr "Аналогтық көлемді 5.1"
#: spa/plugins/alsa/acp/alsa-mixer.c:4546
#: spa/plugins/alsa/acp/alsa-mixer.c:4551
msgid "Analog Surround 6.0"
msgstr "Аналогтық көлемді 6.0"
#: spa/plugins/alsa/acp/alsa-mixer.c:4547
#: spa/plugins/alsa/acp/alsa-mixer.c:4552
msgid "Analog Surround 6.1"
msgstr "Аналогтық көлемді 6.1"
#: spa/plugins/alsa/acp/alsa-mixer.c:4548
#: spa/plugins/alsa/acp/alsa-mixer.c:4553
msgid "Analog Surround 7.0"
msgstr "Аналогтық көлемді 7.0"
#: spa/plugins/alsa/acp/alsa-mixer.c:4549
#: spa/plugins/alsa/acp/alsa-mixer.c:4554
msgid "Analog Surround 7.1"
msgstr "Аналогтық көлемді 7.1"
#: spa/plugins/alsa/acp/alsa-mixer.c:4550
#: spa/plugins/alsa/acp/alsa-mixer.c:4555
msgid "Digital Stereo (IEC958)"
msgstr "Цифрлық стерео (IEC958)"
#: spa/plugins/alsa/acp/alsa-mixer.c:4551
#: spa/plugins/alsa/acp/alsa-mixer.c:4556
msgid "Digital Surround 4.0 (IEC958/AC3)"
msgstr "Цифрлық көлемді 4.0 (IEC958/AC3)"
#: spa/plugins/alsa/acp/alsa-mixer.c:4552
#: spa/plugins/alsa/acp/alsa-mixer.c:4557
msgid "Digital Surround 5.1 (IEC958/AC3)"
msgstr "Цифрлық көлемді 5.1 (IEC958/AC3)"
#: spa/plugins/alsa/acp/alsa-mixer.c:4553
#: spa/plugins/alsa/acp/alsa-mixer.c:4558
msgid "Digital Surround 5.1 (IEC958/DTS)"
msgstr "Цифрлық көлемді 5.1 (IEC958/DTS)"
#: spa/plugins/alsa/acp/alsa-mixer.c:4554
#: spa/plugins/alsa/acp/alsa-mixer.c:4559
msgid "Digital Stereo (HDMI)"
msgstr "Цифрлық стерео (HDMI)"
#: spa/plugins/alsa/acp/alsa-mixer.c:4555
#: spa/plugins/alsa/acp/alsa-mixer.c:4560
msgid "Digital Surround 5.1 (HDMI)"
msgstr "Цифрлық көлемді 5.1 (HDMI)"
#: spa/plugins/alsa/acp/alsa-mixer.c:4556
#: spa/plugins/alsa/acp/alsa-mixer.c:4561
msgid "Chat"
msgstr "Чат"
msgstr ""
#: spa/plugins/alsa/acp/alsa-mixer.c:4557
#: spa/plugins/alsa/acp/alsa-mixer.c:4562
msgid "Game"
msgstr "Ойын"
msgstr ""
#: spa/plugins/alsa/acp/alsa-mixer.c:4691
#: spa/plugins/alsa/acp/alsa-mixer.c:4696
msgid "Analog Mono Duplex"
msgstr "Аналогтық моно дуплекс"
#: spa/plugins/alsa/acp/alsa-mixer.c:4692
#: spa/plugins/alsa/acp/alsa-mixer.c:4697
msgid "Analog Stereo Duplex"
msgstr "Аналогтық стерео дуплекс"
#: spa/plugins/alsa/acp/alsa-mixer.c:4695
#: spa/plugins/alsa/acp/alsa-mixer.c:4700
msgid "Digital Stereo Duplex (IEC958)"
msgstr "Цифрлық стерео дуплекс (IEC958)"
#: spa/plugins/alsa/acp/alsa-mixer.c:4696
#: spa/plugins/alsa/acp/alsa-mixer.c:4701
msgid "Multichannel Duplex"
msgstr "Көпарналы дуплекс"
#: spa/plugins/alsa/acp/alsa-mixer.c:4697
#: spa/plugins/alsa/acp/alsa-mixer.c:4702
msgid "Stereo Duplex"
msgstr "Стерео дуплекс"
#: spa/plugins/alsa/acp/alsa-mixer.c:4698
#: spa/plugins/alsa/acp/alsa-mixer.c:4703
msgid "Mono Chat + 7.1 Surround"
msgstr "Моно чат + 7.1 көлемді дыбыс"
msgstr ""
#: spa/plugins/alsa/acp/alsa-mixer.c:4799
#: spa/plugins/alsa/acp/alsa-mixer.c:4806
#, c-format
msgid "%s Output"
msgstr "%s шығысы"
#: spa/plugins/alsa/acp/alsa-mixer.c:4807
#: spa/plugins/alsa/acp/alsa-mixer.c:4813
#, c-format
msgid "%s Input"
msgstr "%s кірісі"
#: spa/plugins/alsa/acp/alsa-util.c:1233 spa/plugins/alsa/acp/alsa-util.c:1327
#: spa/plugins/alsa/acp/alsa-util.c:1175 spa/plugins/alsa/acp/alsa-util.c:1269
#, c-format
msgid ""
"snd_pcm_avail() returned a value that is exceptionally large: %lu byte (%lu ms).\n"
"Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."
"snd_pcm_avail() returned a value that is exceptionally large: %lu byte (%lu "
"ms).\n"
"Most likely this is a bug in the ALSA driver '%s'. Please report this issue "
"to the ALSA developers."
msgid_plural ""
"snd_pcm_avail() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
"Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."
"snd_pcm_avail() returned a value that is exceptionally large: %lu bytes (%lu "
"ms).\n"
"Most likely this is a bug in the ALSA driver '%s'. Please report this issue "
"to the ALSA developers."
msgstr[0] ""
"snd_pcm_avail() өте үлкен мән қайтарды: %lu байт (%lu мс).\n"
"Бұл ALSA драйверіндегі («%s») қате болуы әбден мүмкін. Бұл мәселе туралы ALSA әзірлеушілеріне хабарлаңыз."
msgstr[1] ""
"snd_pcm_avail() өте үлкен мән қайтарды: %lu байт (%lu мс).\n"
"Бұл ALSA драйверіндегі («%s») қате болуы әбден мүмкін. Бұл мәселе туралы ALSA әзірлеушілеріне хабарлаңыз."
#: spa/plugins/alsa/acp/alsa-util.c:1299
#: spa/plugins/alsa/acp/alsa-util.c:1241
#, c-format
msgid ""
"snd_pcm_delay() returned a value that is exceptionally large: %li byte (%s%lu ms).\n"
"Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."
"snd_pcm_delay() returned a value that is exceptionally large: %li byte (%s"
"%lu ms).\n"
"Most likely this is a bug in the ALSA driver '%s'. Please report this issue "
"to the ALSA developers."
msgid_plural ""
"snd_pcm_delay() returned a value that is exceptionally large: %li bytes (%s%lu ms).\n"
"Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."
"snd_pcm_delay() returned a value that is exceptionally large: %li bytes (%s"
"%lu ms).\n"
"Most likely this is a bug in the ALSA driver '%s'. Please report this issue "
"to the ALSA developers."
msgstr[0] ""
"snd_pcm_delay() өте үлкен мән қайтарды: %li байт (%s%lu мс).\n"
"Бұл ALSA драйверіндегі («%s») қате болуы әбден мүмкін. Бұл мәселе туралы ALSA әзірлеушілеріне хабарлаңыз."
msgstr[1] ""
"snd_pcm_delay() өте үлкен мән қайтарды: %li байт (%s%lu мс).\n"
"Бұл ALSA драйверіндегі («%s») қате болуы әбден мүмкін. Бұл мәселе туралы ALSA әзірлеушілеріне хабарлаңыз."
#: spa/plugins/alsa/acp/alsa-util.c:1346
#: spa/plugins/alsa/acp/alsa-util.c:1288
#, c-format
msgid ""
"snd_pcm_avail_delay() returned strange values: delay %lu is less than avail %lu.\n"
"Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."
"snd_pcm_avail_delay() returned strange values: delay %lu is less than avail "
"%lu.\n"
"Most likely this is a bug in the ALSA driver '%s'. Please report this issue "
"to the ALSA developers."
msgstr ""
"snd_pcm_avail_delay() оғаш мәндер қайтарды: кідіріс %lu мәні қолжетімді %lu мәнінен аз.\n"
"Бұл ALSA драйверіндегі («%s») қате болуы әбден мүмкін. Бұл мәселе туралы ALSA әзірлеушілеріне хабарлаңыз."
#: spa/plugins/alsa/acp/alsa-util.c:1389
#: spa/plugins/alsa/acp/alsa-util.c:1331
#, c-format
msgid ""
"snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu byte (%lu ms).\n"
"Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."
"snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu byte "
"(%lu ms).\n"
"Most likely this is a bug in the ALSA driver '%s'. Please report this issue "
"to the ALSA developers."
msgid_plural ""
"snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu bytes (%lu ms).\n"
"Most likely this is a bug in the ALSA driver '%s'. Please report this issue to the ALSA developers."
"snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu bytes "
"(%lu ms).\n"
"Most likely this is a bug in the ALSA driver '%s'. Please report this issue "
"to the ALSA developers."
msgstr[0] ""
"snd_pcm_mmap_begin() өте үлкен мән қайтарды: %lu байт (%lu мс).\n"
"Бұл ALSA драйверіндегі («%s») қате болуы әбден мүмкін. Бұл мәселе туралы ALSA әзірлеушілеріне хабарлаңыз."
msgstr[1] ""
"snd_pcm_mmap_begin() өте үлкен мән қайтарды: %lu байт (%lu мс).\n"
"Бұл ALSA драйверіндегі («%s») қате болуы әбден мүмкін. Бұл мәселе туралы ALSA әзірлеушілеріне хабарлаңыз."
#: spa/plugins/alsa/acp/channelmap.h:460
msgid "(invalid)"
msgstr "(жарамсыз)"
#: spa/plugins/alsa/acp/compat.c:194
msgid "Built-in Audio"
msgstr "Құрамындағы аудио"
#: spa/plugins/alsa/acp/compat.c:199
msgid "Modem"
msgstr "Модем"
#: spa/plugins/bluez5/bluez5-device.c:2032
#: spa/plugins/bluez5/bluez5-device.c:1010
msgid "Audio Gateway (A2DP Source & HSP/HFP AG)"
msgstr "Аудио шлюзі (A2DP бастапқы көзі және HSP/HFP AG)"
msgstr ""
#: spa/plugins/bluez5/bluez5-device.c:2061
msgid "Audio Streaming for Hearing Aids (ASHA Sink)"
msgstr "Есту аппараттарына арналған аудио ағыны (ASHA қабылдағышы)"
#: spa/plugins/bluez5/bluez5-device.c:2104
#: spa/plugins/bluez5/bluez5-device.c:1033
#, c-format
msgid "High Fidelity Playback (A2DP Sink, codec %s)"
msgstr "Жоғары сапалы ойнату (A2DP қабылдағышы, кодек %s)"
msgstr ""
#: spa/plugins/bluez5/bluez5-device.c:2107
#: spa/plugins/bluez5/bluez5-device.c:1035
#, c-format
msgid "High Fidelity Duplex (A2DP Source/Sink, codec %s)"
msgstr "Жоғары сапалы дуплекс (A2DP бастапқы көзі/қабылдағышы, кодек %s)"
msgstr ""
#: spa/plugins/bluez5/bluez5-device.c:2115
#: spa/plugins/bluez5/bluez5-device.c:1041
msgid "High Fidelity Playback (A2DP Sink)"
msgstr "Жоғары сапалы ойнату (A2DP қабылдағышы)"
msgstr ""
#: spa/plugins/bluez5/bluez5-device.c:2117
#: spa/plugins/bluez5/bluez5-device.c:1043
msgid "High Fidelity Duplex (A2DP Source/Sink)"
msgstr "Жоғары сапалы дуплекс (A2DP бастапқы көзі/қабылдағышы)"
msgstr ""
#: spa/plugins/bluez5/bluez5-device.c:2194
#, c-format
msgid "High Fidelity Playback (BAP Sink, codec %s)"
msgstr "Жоғары сапалы ойнату (BAP қабылдағышы, кодек %s)"
#: spa/plugins/bluez5/bluez5-device.c:2199
#, c-format
msgid "High Fidelity Input (BAP Source, codec %s)"
msgstr "Жоғары сапалы кіріс (BAP бастапқы көзі, кодек %s)"
#: spa/plugins/bluez5/bluez5-device.c:2203
#, c-format
msgid "High Fidelity Duplex (BAP Source/Sink, codec %s)"
msgstr "Жоғары сапалы дуплекс (BAP бастапқы көзі/қабылдағышы, кодек %s)"
#: spa/plugins/bluez5/bluez5-device.c:2212
msgid "High Fidelity Playback (BAP Sink)"
msgstr "Жоғары сапалы ойнату (BAP қабылдағышы)"
#: spa/plugins/bluez5/bluez5-device.c:2216
msgid "High Fidelity Input (BAP Source)"
msgstr "Жоғары сапалы кіріс (BAP бастапқы көзі)"
#: spa/plugins/bluez5/bluez5-device.c:2219
msgid "High Fidelity Duplex (BAP Source/Sink)"
msgstr "Жоғары сапалы дуплекс (BAP бастапқы көзі/қабылдағышы)"
#: spa/plugins/bluez5/bluez5-device.c:2259
#: spa/plugins/bluez5/bluez5-device.c:1070
#, c-format
msgid "Headset Head Unit (HSP/HFP, codec %s)"
msgstr "Гарнитура (HSP/HFP, кодек %s)"
msgstr ""
#: spa/plugins/bluez5/bluez5-device.c:2411 spa/plugins/bluez5/bluez5-device.c:2416
#: spa/plugins/bluez5/bluez5-device.c:2423 spa/plugins/bluez5/bluez5-device.c:2429
#: spa/plugins/bluez5/bluez5-device.c:2435 spa/plugins/bluez5/bluez5-device.c:2441
#: spa/plugins/bluez5/bluez5-device.c:2447 spa/plugins/bluez5/bluez5-device.c:2453
#: spa/plugins/bluez5/bluez5-device.c:2459
#: spa/plugins/bluez5/bluez5-device.c:1074
msgid "Headset Head Unit (HSP/HFP)"
msgstr ""
#: spa/plugins/bluez5/bluez5-device.c:1140
msgid "Handsfree"
msgstr "Хендс-фри"
#: spa/plugins/bluez5/bluez5-device.c:2417
msgid "Handsfree (HFP)"
msgstr "Гарнитура (HFP)"
#: spa/plugins/bluez5/bluez5-device.c:1155
msgid "Headphone"
msgstr "Құлаққап"
#: spa/plugins/bluez5/bluez5-device.c:2440
#: spa/plugins/bluez5/bluez5-device.c:1160
msgid "Portable"
msgstr "Портативті динамик"
#: spa/plugins/bluez5/bluez5-device.c:2446
#: spa/plugins/bluez5/bluez5-device.c:1165
msgid "Car"
msgstr "Автомобильдік динамик"
#: spa/plugins/bluez5/bluez5-device.c:2452
#: spa/plugins/bluez5/bluez5-device.c:1170
msgid "HiFi"
msgstr "HiFi"
#: spa/plugins/bluez5/bluez5-device.c:2458
#: spa/plugins/bluez5/bluez5-device.c:1175
msgid "Phone"
msgstr "Телефон"
#: spa/plugins/bluez5/bluez5-device.c:2465
#: spa/plugins/bluez5/bluez5-device.c:1181
msgid "Bluetooth"
msgstr "Bluetooth"
#: spa/plugins/bluez5/bluez5-device.c:2466
msgid "Bluetooth Handsfree"
msgstr "Bluetooth гарнитурасы"
#~ msgid "Headphone"
#~ msgstr "Құлаққап"

155
po/sl.po
View file

@ -2,21 +2,23 @@
# Copyright (C) 2024 PipeWire's COPYRIGHT HOLDER
# This file is distributed under the same license as the PipeWire package.
#
# Martin <miles@filmsi.net>, 2024, 2025, 2026.
# Martin <miles@filmsi.net>, 2024, 2025.
#
msgid ""
msgstr ""
"Project-Id-Version: PipeWire master\n"
"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/-/issues\n"
"POT-Creation-Date: 2026-02-09 12:55+0000\n"
"PO-Revision-Date: 2026-02-15 16:18+0100\n"
"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/-/"
"issues\n"
"POT-Creation-Date: 2025-12-04 15:34+0000\n"
"PO-Revision-Date: 2025-12-07 08:53+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
@ -33,7 +35,8 @@ msgstr ""
" -h, --help Pokaži to pomoč\n"
" -v, --verbose Povečaj opisnost za eno raven\n"
" --version Pokaži različico\n"
" -c, --config Naloži prilagoditev config (privzeto %s)\n"
" -c, --config Naloži prilagoditev config (privzeto "
"%s)\n"
" -P --properties Določi lastnosti konteksta\n"
#: src/daemon/pipewire.desktop.in:3
@ -59,46 +62,21 @@ msgstr "Lažni izhod"
msgid "Tunnel for %s@%s"
msgstr "Prehod za %s@%s"
#: src/modules/module-zeroconf-discover.c:326
#: src/modules/module-zeroconf-discover.c:320
msgid "Unknown device"
msgstr "Neznana naprava"
#: src/modules/module-zeroconf-discover.c:338
#: src/modules/module-zeroconf-discover.c:332
#, c-format
msgid "%s on %s@%s"
msgstr "%s na %s@%s"
#: src/modules/module-zeroconf-discover.c:342
#: src/modules/module-zeroconf-discover.c:336
#, c-format
msgid "%s on %s"
msgstr "%s na %s"
#: src/tools/pw-cat.c:264
#, c-format
msgid "Supported formats:\n"
msgstr "Podprti zapisi:\n"
#: src/tools/pw-cat.c:749
#, c-format
msgid "Supported channel layouts:\n"
msgstr "Podprte postavitve kanalov:\n"
#: src/tools/pw-cat.c:759
#, c-format
msgid "Supported channel layout aliases:\n"
msgstr "Podprti vzdevki postavitev kanalov:\n"
#: src/tools/pw-cat.c:761
#, c-format
msgid " %s -> %s\n"
msgstr " %s -> %s\n"
#: src/tools/pw-cat.c:766
#, c-format
msgid "Supported channel names:\n"
msgstr "Podprta imena kanalov:\n"
#: src/tools/pw-cat.c:1177
#: src/tools/pw-cat.c:1103
#, c-format
msgid ""
"%s [options] [<file>|-]\n"
@ -114,7 +92,7 @@ msgstr ""
"\n"
"</file>\n"
#: src/tools/pw-cat.c:1184
#: src/tools/pw-cat.c:1110
#, c-format
msgid ""
" -R, --remote Remote daemon name\n"
@ -151,23 +129,20 @@ msgstr ""
" -P --properties Nastavi lastnosti vozlišča\n"
"\n"
#: src/tools/pw-cat.c:1202
#: src/tools/pw-cat.c:1128
#, c-format
msgid ""
" --rate Sample rate (default %u)\n"
" --channels Number of channels (default %u)\n"
" --rate Sample rate (req. for rec) (default "
"%u)\n"
" --channels Number of channels (req. for rec) "
"(default %u)\n"
" --channel-map Channel map\n"
" a channel layout: \"Stereo\", "
"\"5.1\",... or\n"
" one of: \"Stereo\", \"5.1\",... "
"or\n"
" comma separated list of channel "
"names: eg. \"FL,FR\"\n"
" --list-layouts List supported channel layouts\n"
" --list-channel-names List supported channel maps\n"
" --format Sample format (default %s)\n"
" --list-formats List supported sample formats\n"
" --container Container format\n"
" --list-containers List supported containers and "
"extensions\n"
" --format Sample format %s (req. for rec) "
"(default %s)\n"
" --volume Stream volume 0-1.0 (default %.3f)\n"
" -q --quality Resampler quality (0 - 15) (default "
"%d)\n"
@ -186,13 +161,8 @@ msgstr ""
"\"5.1\",... ali\n"
" seznam imen kanalov, ločen z "
"vejico: npr. \"FL,FR\"\n"
" —list-layouts Izpiše podprte postavitve kanalov\n"
" —list-channel-names Izpiše podprte preslikave kanalov\n"
" --format Oblika zapisa vzorcev (privzeto %s)\n"
" —list-formats Izpiše podprte zapise vzorcev\n"
" —container Oblika vsebnika\n"
" —list-containers Seznam podprtih vsebnikov in "
"razširitev\n"
" --format Vzorčne oblike zapisa %s (zahtevano "
"za rec) (privzeto %s)\n"
" --volume Glasnost toka 0-1.0 (privzeto %.3f)\n"
" -q --quality Kakovost prevzorčenja (0 - 15) "
"(privzeto %d)\n"
@ -202,7 +172,7 @@ msgstr ""
" -n, --sample-count ŠTEVEC Ustavi po ŠTEVEC vzorcih\n"
"\n"
#: src/tools/pw-cat.c:1227
#: src/tools/pw-cat.c:1148
msgid ""
" -p, --playback Playback mode\n"
" -r, --record Recording mode\n"
@ -222,11 +192,6 @@ msgstr ""
" -c, --midi-clip Način posnetka MIDI\n"
"\n"
#: src/tools/pw-cat.c:1827
#, c-format
msgid "Supported containers and extensions:\n"
msgstr "Podprti vsebniki in razširitve:\n"
#: src/tools/pw-cli.c:2386
#, c-format
msgid ""
@ -252,7 +217,7 @@ msgid "Pro Audio"
msgstr "Profesionalni zvok"
#: spa/plugins/alsa/acp/acp.c:537 spa/plugins/alsa/acp/alsa-mixer.c:4699
#: spa/plugins/bluez5/bluez5-device.c:2021
#: spa/plugins/bluez5/bluez5-device.c:1976
msgid "Off"
msgstr "Izklopljeno"
@ -284,7 +249,7 @@ msgstr "Linijski vhod"
#: spa/plugins/alsa/acp/alsa-mixer.c:2726
#: spa/plugins/alsa/acp/alsa-mixer.c:2810
#: spa/plugins/bluez5/bluez5-device.c:2422
#: spa/plugins/bluez5/bluez5-device.c:2374
msgid "Microphone"
msgstr "Mikrofon"
@ -350,15 +315,15 @@ msgid "No Bass Boost"
msgstr "Brez ojačitve nizkih tonov"
#: spa/plugins/alsa/acp/alsa-mixer.c:2741
#: spa/plugins/bluez5/bluez5-device.c:2428
#: 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:2742
#: spa/plugins/alsa/acp/alsa-mixer.c:2820
#: spa/plugins/bluez5/bluez5-device.c:2434
#: spa/plugins/bluez5/bluez5-device.c:2501
#: spa/plugins/bluez5/bluez5-device.c:2386
#: spa/plugins/bluez5/bluez5-device.c:2453
msgid "Headphones"
msgstr "Slušalke"
@ -468,7 +433,7 @@ msgstr "Stereo"
#: spa/plugins/alsa/acp/alsa-mixer.c:4535
#: spa/plugins/alsa/acp/alsa-mixer.c:4693
#: spa/plugins/bluez5/bluez5-device.c:2410
#: spa/plugins/bluez5/bluez5-device.c:2362
msgid "Headset"
msgstr "Slušalka"
@ -715,100 +680,100 @@ msgstr "Vgrajen zvok"
msgid "Modem"
msgstr "Modem"
#: spa/plugins/bluez5/bluez5-device.c:2032
#: 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:2061
#: 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:2104
#: 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:2107
#: 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:2115
#: 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:2117
#: 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:2194
#: 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:2199
#: 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:2203
#: 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:2212
#: 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:2216
#: 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:2219
#: 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:2259
#: 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: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
#: spa/plugins/bluez5/bluez5-device.c:2416
#: spa/plugins/bluez5/bluez5-device.c:2423
#: spa/plugins/bluez5/bluez5-device.c:2429
#: spa/plugins/bluez5/bluez5-device.c:2435
#: spa/plugins/bluez5/bluez5-device.c:2441
#: spa/plugins/bluez5/bluez5-device.c:2447
#: spa/plugins/bluez5/bluez5-device.c:2453
#: spa/plugins/bluez5/bluez5-device.c:2459
msgid "Handsfree"
msgstr "Prostoročno telefoniranje"
#: spa/plugins/bluez5/bluez5-device.c:2417
#: spa/plugins/bluez5/bluez5-device.c:2369
msgid "Handsfree (HFP)"
msgstr "Prostoročno telefoniranje (HFP)"
#: spa/plugins/bluez5/bluez5-device.c:2440
#: spa/plugins/bluez5/bluez5-device.c:2392
msgid "Portable"
msgstr "Prenosna naprava"
#: spa/plugins/bluez5/bluez5-device.c:2446
#: spa/plugins/bluez5/bluez5-device.c:2398
msgid "Car"
msgstr "Avtomobil"
#: spa/plugins/bluez5/bluez5-device.c:2452
#: spa/plugins/bluez5/bluez5-device.c:2404
msgid "HiFi"
msgstr "HiFi"
#: spa/plugins/bluez5/bluez5-device.c:2458
#: spa/plugins/bluez5/bluez5-device.c:2410
msgid "Phone"
msgstr "Telefon"
#: spa/plugins/bluez5/bluez5-device.c:2465
#: spa/plugins/bluez5/bluez5-device.c:2417
msgid "Bluetooth"
msgstr "Bluetooth"
#: spa/plugins/bluez5/bluez5-device.c:2466
#: spa/plugins/bluez5/bluez5-device.c:2418
msgid "Bluetooth Handsfree"
msgstr "Bluetooth - prostoročno"

382
po/sv.po
View file

@ -1,9 +1,9 @@
# Swedish translation for pipewire.
# Copyright © 2008-2026 Free Software Foundation, Inc.
# Copyright © 2008-2025 Free Software Foundation, Inc.
# This file is distributed under the same license as the pipewire package.
# Daniel Nylander <po@danielnylander.se>, 2008, 2012.
# Josef Andersson <josef.andersson@fripost.org>, 2014, 2017.
# Anders Jonsson <anders.jonsson@norsjovallen.se>, 2021, 2022, 2023, 2024, 2025, 2026.
# Anders Jonsson <anders.jonsson@norsjovallen.se>, 2021, 2022, 2023, 2024, 2025.
#
# Termer:
# input/output: ingång/utgång (det handlar om ljud)
@ -19,8 +19,8 @@ msgstr ""
"Project-Id-Version: pipewire\n"
"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/-/"
"issues\n"
"POT-Creation-Date: 2026-02-09 12:55+0000\n"
"PO-Revision-Date: 2026-02-22 21:48+0100\n"
"POT-Creation-Date: 2025-04-16 15:31+0000\n"
"PO-Revision-Date: 2025-04-22 10:43+0200\n"
"Last-Translator: Anders Jonsson <anders.jonsson@norsjovallen.se>\n"
"Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
"Language: sv\n"
@ -28,7 +28,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Poedit 3.8\n"
"X-Generator: Poedit 3.5\n"
#: src/daemon/pipewire.c:29
#, c-format
@ -47,11 +47,11 @@ msgstr ""
" -c, --config Läs in konfig (standard %s)\n"
" -P --properties Ställ in kontextegenskaper\n"
#: src/daemon/pipewire.desktop.in:3
#: src/daemon/pipewire.desktop.in:4
msgid "PipeWire Media System"
msgstr "PipeWire mediasystem"
#: src/daemon/pipewire.desktop.in:4
#: src/daemon/pipewire.desktop.in:5
msgid "Start the PipeWire Media System"
msgstr "Starta mediasystemet PipeWire"
@ -65,51 +65,26 @@ msgstr "Tunnel till %s%s%s"
msgid "Dummy Output"
msgstr "Attrapputgång"
#: src/modules/module-pulse-tunnel.c:761
#: src/modules/module-pulse-tunnel.c:760
#, c-format
msgid "Tunnel for %s@%s"
msgstr "Tunnel för %s@%s"
#: src/modules/module-zeroconf-discover.c:326
#: src/modules/module-zeroconf-discover.c:320
msgid "Unknown device"
msgstr "Okänd enhet"
#: src/modules/module-zeroconf-discover.c:338
#: src/modules/module-zeroconf-discover.c:332
#, c-format
msgid "%s on %s@%s"
msgstr "%s på %s@%s"
#: src/modules/module-zeroconf-discover.c:342
#: src/modules/module-zeroconf-discover.c:336
#, c-format
msgid "%s on %s"
msgstr "%s på %s"
#: src/tools/pw-cat.c:264
#, c-format
msgid "Supported formats:\n"
msgstr "Format som stöds:\n"
#: src/tools/pw-cat.c:749
#, c-format
msgid "Supported channel layouts:\n"
msgstr "Kanallayouter som stöds:\n"
#: src/tools/pw-cat.c:759
#, c-format
msgid "Supported channel layout aliases:\n"
msgstr "Kanallayoutalias som stöds:\n"
#: src/tools/pw-cat.c:761
#, c-format
msgid " %s -> %s\n"
msgstr " %s -> %s\n"
#: src/tools/pw-cat.c:766
#, c-format
msgid "Supported channel names:\n"
msgstr "Kanalnamn som stöds:\n"
#: src/tools/pw-cat.c:1177
#: src/tools/pw-cat.c:973
#, c-format
msgid ""
"%s [options] [<file>|-]\n"
@ -124,7 +99,7 @@ msgstr ""
" -v, --verbose Aktivera utförliga operationer\n"
"\n"
#: src/tools/pw-cat.c:1184
#: src/tools/pw-cat.c:980
#, c-format
msgid ""
" -R, --remote Remote daemon name\n"
@ -156,64 +131,50 @@ msgstr ""
" -P --properties Sätt nodegenskaper\n"
"\n"
#: src/tools/pw-cat.c:1202
#: src/tools/pw-cat.c:998
#, c-format
msgid ""
" --rate Sample rate (default %u)\n"
" --channels Number of channels (default %u)\n"
" --rate Sample rate (req. for rec) (default "
"%u)\n"
" --channels Number of channels (req. for rec) "
"(default %u)\n"
" --channel-map Channel map\n"
" a channel layout: \"Stereo\", "
"\"5.1\",... or\n"
" one of: \"stereo\", "
"\"surround-51\",... or\n"
" comma separated list of channel "
"names: eg. \"FL,FR\"\n"
" --list-layouts List supported channel layouts\n"
" --list-channel-names List supported channel maps\n"
" --format Sample format (default %s)\n"
" --list-formats List supported sample formats\n"
" --container Container format\n"
" --list-containers List supported containers and "
"extensions\n"
" --format Sample format %s (req. for rec) "
"(default %s)\n"
" --volume Stream volume 0-1.0 (default %.3f)\n"
" -q --quality Resampler quality (0 - 15) (default "
"%d)\n"
" -a, --raw RAW mode\n"
" -M, --force-midi Force midi format, one of \"midi\" "
"or \"ump\", (default ump)\n"
" -n, --sample-count COUNT Stop after COUNT samples\n"
"\n"
msgstr ""
" --rate Samplingsfrekvens (standard %u)\n"
" --channels Antal kanaler (standard %u)\n"
" --rate Samplingsfrekvens (krävs för insp.) "
"(standard %u)\n"
" --channels Antal kanaler (krävs för insp.) "
"(standard %u)\n"
" --channel-map Kanalmappning\n"
" en kanallayout: \"Stereo\", "
"\"5.1\",... eller\n"
" en av: \"stereo\", "
"\"surround-51\",... eller\n"
" kommaseparerad lista av "
"kanalnamn: t.ex. \"FL,FR\"\n"
" --list-layouts Lista kanallayouter som stöds\n"
" --list-channel-names Lista kanalmappningar som stöds\n"
" --format Samplingsformat (standard %s)\n"
" --list-formats Lista samplingsformat som stöds\n"
" --container Behållarformat\n"
" --list-containers Lista behållare och tillägg som "
"stöds\n"
" --format Samplingsformat %s (krävs för insp.) "
"(standard %s)\n"
" --volume Strömvolym 0-1.0 (standard %.3f)\n"
" -q --quality Omsamplarkvalitet (0 - 15) (standard "
"%d)\n"
" -a, --raw RAW-läge\n"
" -M, --force-midi Tvinga midi-format, en av \"midi\" "
"eller \"ump\", (standard ump)\n"
" -n, --sample-count ANTAL Stoppa efter ANTAL samplar\n"
"\n"
#: src/tools/pw-cat.c:1227
#: src/tools/pw-cat.c:1016
msgid ""
" -p, --playback Playback mode\n"
" -r, --record Recording mode\n"
" -m, --midi Midi mode\n"
" -d, --dsd DSD mode\n"
" -o, --encoded Encoded mode\n"
" -s, --sysex SysEx mode\n"
" -c, --midi-clip MIDI clip mode\n"
"\n"
msgstr ""
" -p, --playback Uppspelningsläge\n"
@ -221,16 +182,9 @@ msgstr ""
" -m, --midi Midiläge\n"
" -d, --dsd DSD-läge\n"
" -o, --encoded Kodat läge\n"
" -s, --sysex SysEx-läge\n"
" -c, --midi-clip MIDI-klippläge\n"
"\n"
#: src/tools/pw-cat.c:1827
#, c-format
msgid "Supported containers and extensions:\n"
msgstr "Behållare och tillägg som stöds:\n"
#: src/tools/pw-cli.c:2386
#: src/tools/pw-cli.c:2306
#, c-format
msgid ""
"%s [options] [command]\n"
@ -249,203 +203,200 @@ msgstr ""
" -m, --monitor Övervaka aktivitet\n"
"\n"
#: spa/plugins/alsa/acp/acp.c:361
#: spa/plugins/alsa/acp/acp.c:350
msgid "Pro Audio"
msgstr "Professionellt ljud"
#: spa/plugins/alsa/acp/acp.c:537 spa/plugins/alsa/acp/alsa-mixer.c:4699
#: spa/plugins/bluez5/bluez5-device.c:2021
#: spa/plugins/alsa/acp/acp.c:511 spa/plugins/alsa/acp/alsa-mixer.c:4635
#: spa/plugins/bluez5/bluez5-device.c:1802
msgid "Off"
msgstr "Av"
#: spa/plugins/alsa/acp/acp.c:620
#: spa/plugins/alsa/acp/acp.c:593
#, c-format
msgid "%s [ALSA UCM error]"
msgstr "%s [ALSA UCM-fel]"
#: spa/plugins/alsa/acp/alsa-mixer.c:2721
#: spa/plugins/alsa/acp/alsa-mixer.c:2652
msgid "Input"
msgstr "Ingång"
#: spa/plugins/alsa/acp/alsa-mixer.c:2722
#: spa/plugins/alsa/acp/alsa-mixer.c:2653
msgid "Docking Station Input"
msgstr "Ingång för dockningsstation"
#: spa/plugins/alsa/acp/alsa-mixer.c:2723
#: spa/plugins/alsa/acp/alsa-mixer.c:2654
msgid "Docking Station Microphone"
msgstr "Mikrofon för dockningsstation"
#: spa/plugins/alsa/acp/alsa-mixer.c:2724
#: spa/plugins/alsa/acp/alsa-mixer.c:2655
msgid "Docking Station Line In"
msgstr "Linje in för dockningsstation"
#: spa/plugins/alsa/acp/alsa-mixer.c:2725
#: spa/plugins/alsa/acp/alsa-mixer.c:2816
#: spa/plugins/alsa/acp/alsa-mixer.c:2656
#: spa/plugins/alsa/acp/alsa-mixer.c:2747
msgid "Line In"
msgstr "Linje in"
#: spa/plugins/alsa/acp/alsa-mixer.c:2726
#: spa/plugins/alsa/acp/alsa-mixer.c:2810
#: spa/plugins/bluez5/bluez5-device.c:2422
#: spa/plugins/alsa/acp/alsa-mixer.c:2657
#: spa/plugins/alsa/acp/alsa-mixer.c:2741
#: spa/plugins/bluez5/bluez5-device.c:2146
msgid "Microphone"
msgstr "Mikrofon"
#: spa/plugins/alsa/acp/alsa-mixer.c:2727
#: spa/plugins/alsa/acp/alsa-mixer.c:2811
#: spa/plugins/alsa/acp/alsa-mixer.c:2658
#: spa/plugins/alsa/acp/alsa-mixer.c:2742
msgid "Front Microphone"
msgstr "Frontmikrofon"
#: spa/plugins/alsa/acp/alsa-mixer.c:2728
#: spa/plugins/alsa/acp/alsa-mixer.c:2812
#: spa/plugins/alsa/acp/alsa-mixer.c:2659
#: spa/plugins/alsa/acp/alsa-mixer.c:2743
msgid "Rear Microphone"
msgstr "Bakre mikrofon"
#: spa/plugins/alsa/acp/alsa-mixer.c:2729
#: spa/plugins/alsa/acp/alsa-mixer.c:2660
msgid "External Microphone"
msgstr "Extern mikrofon"
#: spa/plugins/alsa/acp/alsa-mixer.c:2730
#: spa/plugins/alsa/acp/alsa-mixer.c:2814
#: spa/plugins/alsa/acp/alsa-mixer.c:2661
#: spa/plugins/alsa/acp/alsa-mixer.c:2745
msgid "Internal Microphone"
msgstr "Intern mikrofon"
#: spa/plugins/alsa/acp/alsa-mixer.c:2731
#: spa/plugins/alsa/acp/alsa-mixer.c:2817
#: spa/plugins/alsa/acp/alsa-mixer.c:2662
#: spa/plugins/alsa/acp/alsa-mixer.c:2748
msgid "Radio"
msgstr "Radio"
#: spa/plugins/alsa/acp/alsa-mixer.c:2732
#: spa/plugins/alsa/acp/alsa-mixer.c:2818
#: spa/plugins/alsa/acp/alsa-mixer.c:2663
#: spa/plugins/alsa/acp/alsa-mixer.c:2749
msgid "Video"
msgstr "Video"
#: spa/plugins/alsa/acp/alsa-mixer.c:2733
#: spa/plugins/alsa/acp/alsa-mixer.c:2664
msgid "Automatic Gain Control"
msgstr "Automatisk förstärkningskontroll"
#: spa/plugins/alsa/acp/alsa-mixer.c:2734
#: spa/plugins/alsa/acp/alsa-mixer.c:2665
msgid "No Automatic Gain Control"
msgstr "Ingen automatisk förstärkningskontroll"
#: spa/plugins/alsa/acp/alsa-mixer.c:2735
#: spa/plugins/alsa/acp/alsa-mixer.c:2666
msgid "Boost"
msgstr "Ökning"
#: spa/plugins/alsa/acp/alsa-mixer.c:2736
#: spa/plugins/alsa/acp/alsa-mixer.c:2667
msgid "No Boost"
msgstr "Ingen ökning"
#: spa/plugins/alsa/acp/alsa-mixer.c:2737
#: spa/plugins/alsa/acp/alsa-mixer.c:2668
msgid "Amplifier"
msgstr "Förstärkare"
#: spa/plugins/alsa/acp/alsa-mixer.c:2738
#: spa/plugins/alsa/acp/alsa-mixer.c:2669
msgid "No Amplifier"
msgstr "Ingen förstärkare"
#: spa/plugins/alsa/acp/alsa-mixer.c:2739
#: spa/plugins/alsa/acp/alsa-mixer.c:2670
msgid "Bass Boost"
msgstr "Basökning"
#: spa/plugins/alsa/acp/alsa-mixer.c:2740
#: spa/plugins/alsa/acp/alsa-mixer.c:2671
msgid "No Bass Boost"
msgstr "Ingen basökning"
#: spa/plugins/alsa/acp/alsa-mixer.c:2741
#: spa/plugins/bluez5/bluez5-device.c:2428
#: spa/plugins/alsa/acp/alsa-mixer.c:2672
#: spa/plugins/bluez5/bluez5-device.c:2152
msgid "Speaker"
msgstr "Högtalare"
#. Don't call it "headset", the HF one has the mic
#: spa/plugins/alsa/acp/alsa-mixer.c:2742
#: spa/plugins/alsa/acp/alsa-mixer.c:2820
#: spa/plugins/bluez5/bluez5-device.c:2434
#: spa/plugins/bluez5/bluez5-device.c:2501
#: spa/plugins/alsa/acp/alsa-mixer.c:2673
#: spa/plugins/alsa/acp/alsa-mixer.c:2751
msgid "Headphones"
msgstr "Hörlurar"
#: spa/plugins/alsa/acp/alsa-mixer.c:2809
#: spa/plugins/alsa/acp/alsa-mixer.c:2740
msgid "Analog Input"
msgstr "Analog ingång"
#: spa/plugins/alsa/acp/alsa-mixer.c:2813
#: spa/plugins/alsa/acp/alsa-mixer.c:2744
msgid "Dock Microphone"
msgstr "Dockmikrofon"
#: spa/plugins/alsa/acp/alsa-mixer.c:2815
#: spa/plugins/alsa/acp/alsa-mixer.c:2746
msgid "Headset Microphone"
msgstr "Headset-mikrofon"
#: spa/plugins/alsa/acp/alsa-mixer.c:2819
#: spa/plugins/alsa/acp/alsa-mixer.c:2750
msgid "Analog Output"
msgstr "Analog utgång"
#: spa/plugins/alsa/acp/alsa-mixer.c:2821
#: spa/plugins/alsa/acp/alsa-mixer.c:2752
msgid "Headphones 2"
msgstr "Hörlurar 2"
#: spa/plugins/alsa/acp/alsa-mixer.c:2822
#: spa/plugins/alsa/acp/alsa-mixer.c:2753
msgid "Headphones Mono Output"
msgstr "Monoutgång för hörlurar"
#: spa/plugins/alsa/acp/alsa-mixer.c:2823
#: spa/plugins/alsa/acp/alsa-mixer.c:2754
msgid "Line Out"
msgstr "Linje ut"
#: spa/plugins/alsa/acp/alsa-mixer.c:2824
#: spa/plugins/alsa/acp/alsa-mixer.c:2755
msgid "Analog Mono Output"
msgstr "Analog monoutgång"
#: spa/plugins/alsa/acp/alsa-mixer.c:2825
#: spa/plugins/alsa/acp/alsa-mixer.c:2756
msgid "Speakers"
msgstr "Högtalare"
#: spa/plugins/alsa/acp/alsa-mixer.c:2826
#: spa/plugins/alsa/acp/alsa-mixer.c:2757
msgid "HDMI / DisplayPort"
msgstr "HDMI / DisplayPort"
#: spa/plugins/alsa/acp/alsa-mixer.c:2827
#: spa/plugins/alsa/acp/alsa-mixer.c:2758
msgid "Digital Output (S/PDIF)"
msgstr "Digital utgång (S/PDIF)"
#: spa/plugins/alsa/acp/alsa-mixer.c:2828
#: spa/plugins/alsa/acp/alsa-mixer.c:2759
msgid "Digital Input (S/PDIF)"
msgstr "Digital ingång (S/PDIF)"
#: spa/plugins/alsa/acp/alsa-mixer.c:2829
#: spa/plugins/alsa/acp/alsa-mixer.c:2760
msgid "Multichannel Input"
msgstr "Multikanalingång"
#: spa/plugins/alsa/acp/alsa-mixer.c:2830
#: spa/plugins/alsa/acp/alsa-mixer.c:2761
msgid "Multichannel Output"
msgstr "Multikanalutgång"
#: spa/plugins/alsa/acp/alsa-mixer.c:2831
#: spa/plugins/alsa/acp/alsa-mixer.c:2762
msgid "Game Output"
msgstr "Spelutgång"
#: spa/plugins/alsa/acp/alsa-mixer.c:2832
#: spa/plugins/alsa/acp/alsa-mixer.c:2833
#: spa/plugins/alsa/acp/alsa-mixer.c:2763
#: spa/plugins/alsa/acp/alsa-mixer.c:2764
msgid "Chat Output"
msgstr "Chatt-utgång"
#: spa/plugins/alsa/acp/alsa-mixer.c:2834
#: spa/plugins/alsa/acp/alsa-mixer.c:2765
msgid "Chat Input"
msgstr "Chatt-ingång"
#: spa/plugins/alsa/acp/alsa-mixer.c:2835
#: spa/plugins/alsa/acp/alsa-mixer.c:2766
msgid "Virtual Surround 7.1"
msgstr "Virtual surround 7.1"
#: spa/plugins/alsa/acp/alsa-mixer.c:4522
#: spa/plugins/alsa/acp/alsa-mixer.c:4458
msgid "Analog Mono"
msgstr "Analog mono"
#: spa/plugins/alsa/acp/alsa-mixer.c:4523
#: spa/plugins/alsa/acp/alsa-mixer.c:4459
msgid "Analog Mono (Left)"
msgstr "Analog mono (vänster)"
#: spa/plugins/alsa/acp/alsa-mixer.c:4524
#: spa/plugins/alsa/acp/alsa-mixer.c:4460
msgid "Analog Mono (Right)"
msgstr "Analog mono (höger)"
@ -454,142 +405,142 @@ msgstr "Analog mono (höger)"
#. * 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:4525
#: spa/plugins/alsa/acp/alsa-mixer.c:4533
#: spa/plugins/alsa/acp/alsa-mixer.c:4534
#: spa/plugins/alsa/acp/alsa-mixer.c:4461
#: spa/plugins/alsa/acp/alsa-mixer.c:4469
#: spa/plugins/alsa/acp/alsa-mixer.c:4470
msgid "Analog Stereo"
msgstr "Analog stereo"
#: spa/plugins/alsa/acp/alsa-mixer.c:4526
#: spa/plugins/alsa/acp/alsa-mixer.c:4462
msgid "Mono"
msgstr "Mono"
#: spa/plugins/alsa/acp/alsa-mixer.c:4527
#: spa/plugins/alsa/acp/alsa-mixer.c:4463
msgid "Stereo"
msgstr "Stereo"
#: spa/plugins/alsa/acp/alsa-mixer.c:4535
#: spa/plugins/alsa/acp/alsa-mixer.c:4693
#: spa/plugins/bluez5/bluez5-device.c:2410
#: spa/plugins/alsa/acp/alsa-mixer.c:4471
#: spa/plugins/alsa/acp/alsa-mixer.c:4629
#: spa/plugins/bluez5/bluez5-device.c:2134
msgid "Headset"
msgstr "Headset"
#: spa/plugins/alsa/acp/alsa-mixer.c:4536
#: spa/plugins/alsa/acp/alsa-mixer.c:4694
#: spa/plugins/alsa/acp/alsa-mixer.c:4472
#: spa/plugins/alsa/acp/alsa-mixer.c:4630
msgid "Speakerphone"
msgstr "Högtalartelefon"
#: spa/plugins/alsa/acp/alsa-mixer.c:4537
#: spa/plugins/alsa/acp/alsa-mixer.c:4538
#: spa/plugins/alsa/acp/alsa-mixer.c:4473
#: spa/plugins/alsa/acp/alsa-mixer.c:4474
msgid "Multichannel"
msgstr "Multikanal"
#: spa/plugins/alsa/acp/alsa-mixer.c:4539
#: spa/plugins/alsa/acp/alsa-mixer.c:4475
msgid "Analog Surround 2.1"
msgstr "Analog surround 2.1"
#: spa/plugins/alsa/acp/alsa-mixer.c:4540
#: spa/plugins/alsa/acp/alsa-mixer.c:4476
msgid "Analog Surround 3.0"
msgstr "Analog surround 3.0"
#: spa/plugins/alsa/acp/alsa-mixer.c:4541
#: spa/plugins/alsa/acp/alsa-mixer.c:4477
msgid "Analog Surround 3.1"
msgstr "Analog surround 3.1"
#: spa/plugins/alsa/acp/alsa-mixer.c:4542
#: spa/plugins/alsa/acp/alsa-mixer.c:4478
msgid "Analog Surround 4.0"
msgstr "Analog surround 4.0"
#: spa/plugins/alsa/acp/alsa-mixer.c:4543
#: spa/plugins/alsa/acp/alsa-mixer.c:4479
msgid "Analog Surround 4.1"
msgstr "Analog surround 4.1"
#: spa/plugins/alsa/acp/alsa-mixer.c:4544
#: spa/plugins/alsa/acp/alsa-mixer.c:4480
msgid "Analog Surround 5.0"
msgstr "Analog surround 5.0"
#: spa/plugins/alsa/acp/alsa-mixer.c:4545
#: spa/plugins/alsa/acp/alsa-mixer.c:4481
msgid "Analog Surround 5.1"
msgstr "Analog surround 5.1"
#: spa/plugins/alsa/acp/alsa-mixer.c:4546
#: spa/plugins/alsa/acp/alsa-mixer.c:4482
msgid "Analog Surround 6.0"
msgstr "Analog surround 6.0"
#: spa/plugins/alsa/acp/alsa-mixer.c:4547
#: spa/plugins/alsa/acp/alsa-mixer.c:4483
msgid "Analog Surround 6.1"
msgstr "Analog surround 6.1"
#: spa/plugins/alsa/acp/alsa-mixer.c:4548
#: spa/plugins/alsa/acp/alsa-mixer.c:4484
msgid "Analog Surround 7.0"
msgstr "Analog surround 7.0"
#: spa/plugins/alsa/acp/alsa-mixer.c:4549
#: spa/plugins/alsa/acp/alsa-mixer.c:4485
msgid "Analog Surround 7.1"
msgstr "Analog surround 7.1"
#: spa/plugins/alsa/acp/alsa-mixer.c:4550
#: spa/plugins/alsa/acp/alsa-mixer.c:4486
msgid "Digital Stereo (IEC958)"
msgstr "Digital stereo (IEC958)"
#: spa/plugins/alsa/acp/alsa-mixer.c:4551
#: spa/plugins/alsa/acp/alsa-mixer.c:4487
msgid "Digital Surround 4.0 (IEC958/AC3)"
msgstr "Digital surround 4.0 (IEC958/AC3)"
#: spa/plugins/alsa/acp/alsa-mixer.c:4552
#: spa/plugins/alsa/acp/alsa-mixer.c:4488
msgid "Digital Surround 5.1 (IEC958/AC3)"
msgstr "Digital surround 5.1 (IEC958/AC3)"
#: spa/plugins/alsa/acp/alsa-mixer.c:4553
#: spa/plugins/alsa/acp/alsa-mixer.c:4489
msgid "Digital Surround 5.1 (IEC958/DTS)"
msgstr "Digital surround 5.1 (IEC958/DTS)"
#: spa/plugins/alsa/acp/alsa-mixer.c:4554
#: spa/plugins/alsa/acp/alsa-mixer.c:4490
msgid "Digital Stereo (HDMI)"
msgstr "Digital stereo (HDMI)"
#: spa/plugins/alsa/acp/alsa-mixer.c:4555
#: spa/plugins/alsa/acp/alsa-mixer.c:4491
msgid "Digital Surround 5.1 (HDMI)"
msgstr "Digital surround 5.1 (HDMI)"
#: spa/plugins/alsa/acp/alsa-mixer.c:4556
#: spa/plugins/alsa/acp/alsa-mixer.c:4492
msgid "Chat"
msgstr "Chatt"
#: spa/plugins/alsa/acp/alsa-mixer.c:4557
#: spa/plugins/alsa/acp/alsa-mixer.c:4493
msgid "Game"
msgstr "Spel"
#: spa/plugins/alsa/acp/alsa-mixer.c:4691
#: spa/plugins/alsa/acp/alsa-mixer.c:4627
msgid "Analog Mono Duplex"
msgstr "Analog mono duplex"
#: spa/plugins/alsa/acp/alsa-mixer.c:4692
#: spa/plugins/alsa/acp/alsa-mixer.c:4628
msgid "Analog Stereo Duplex"
msgstr "Analog stereo duplex"
#: spa/plugins/alsa/acp/alsa-mixer.c:4695
#: spa/plugins/alsa/acp/alsa-mixer.c:4631
msgid "Digital Stereo Duplex (IEC958)"
msgstr "Digital stereo duplex (IEC958)"
#: spa/plugins/alsa/acp/alsa-mixer.c:4696
#: spa/plugins/alsa/acp/alsa-mixer.c:4632
msgid "Multichannel Duplex"
msgstr "Multikanalduplex"
#: spa/plugins/alsa/acp/alsa-mixer.c:4697
#: spa/plugins/alsa/acp/alsa-mixer.c:4633
msgid "Stereo Duplex"
msgstr "Stereo duplex"
#: spa/plugins/alsa/acp/alsa-mixer.c:4698
#: spa/plugins/alsa/acp/alsa-mixer.c:4634
msgid "Mono Chat + 7.1 Surround"
msgstr "Mono Chatt + 7.1 Surround"
#: spa/plugins/alsa/acp/alsa-mixer.c:4799
#: spa/plugins/alsa/acp/alsa-mixer.c:4735
#, c-format
msgid "%s Output"
msgstr "%s-utgång"
#: spa/plugins/alsa/acp/alsa-mixer.c:4807
#: spa/plugins/alsa/acp/alsa-mixer.c:4743
#, c-format
msgid "%s Input"
msgstr "%s-ingång"
@ -676,115 +627,116 @@ msgstr[1] ""
"Förmodligen är detta ett fel i ALSA-drivrutinen ”%s”. Vänligen rapportera "
"problemet till ALSA-utvecklarna."
#: spa/plugins/alsa/acp/channelmap.h:460
#: spa/plugins/alsa/acp/channelmap.h:457
msgid "(invalid)"
msgstr "(ogiltig)"
#: spa/plugins/alsa/acp/compat.c:194
#: spa/plugins/alsa/acp/compat.c:193
msgid "Built-in Audio"
msgstr "Inbyggt ljud"
#: spa/plugins/alsa/acp/compat.c:199
#: spa/plugins/alsa/acp/compat.c:198
msgid "Modem"
msgstr "Modem"
#: spa/plugins/bluez5/bluez5-device.c:2032
#: spa/plugins/bluez5/bluez5-device.c:1813
msgid "Audio Gateway (A2DP Source & HSP/HFP AG)"
msgstr "Audio gateway (A2DP-källa & HSP/HFP AG)"
#: spa/plugins/bluez5/bluez5-device.c:2061
#: spa/plugins/bluez5/bluez5-device.c:1841
msgid "Audio Streaming for Hearing Aids (ASHA Sink)"
msgstr "Ljudströmning för hörhjälpmedel (ASHA-utgång)"
#: spa/plugins/bluez5/bluez5-device.c:2104
#: spa/plugins/bluez5/bluez5-device.c:1881
#, c-format
msgid "High Fidelity Playback (A2DP Sink, codec %s)"
msgstr "High fidelity-uppspelning (A2DP-utgång, kodek %s)"
#: spa/plugins/bluez5/bluez5-device.c:2107
#: spa/plugins/bluez5/bluez5-device.c:1884
#, c-format
msgid "High Fidelity Duplex (A2DP Source/Sink, codec %s)"
msgstr "High fidelity duplex (A2DP-källa/utgång, kodek %s)"
#: spa/plugins/bluez5/bluez5-device.c:2115
#: spa/plugins/bluez5/bluez5-device.c:1892
msgid "High Fidelity Playback (A2DP Sink)"
msgstr "High fidelity-uppspelning (A2DP-utgång)"
#: spa/plugins/bluez5/bluez5-device.c:2117
#: spa/plugins/bluez5/bluez5-device.c:1894
msgid "High Fidelity Duplex (A2DP Source/Sink)"
msgstr "High fidelity duplex (A2DP-källa/utgång)"
#: spa/plugins/bluez5/bluez5-device.c:2194
#: spa/plugins/bluez5/bluez5-device.c:1944
#, c-format
msgid "High Fidelity Playback (BAP Sink, codec %s)"
msgstr "High fidelity-uppspelning (BAP-utgång, kodek %s)"
#: spa/plugins/bluez5/bluez5-device.c:2199
#: spa/plugins/bluez5/bluez5-device.c:1949
#, c-format
msgid "High Fidelity Input (BAP Source, codec %s)"
msgstr "High fidelity-ingång (BAP-källa, kodek %s)"
#: spa/plugins/bluez5/bluez5-device.c:2203
#: spa/plugins/bluez5/bluez5-device.c:1953
#, c-format
msgid "High Fidelity Duplex (BAP Source/Sink, codec %s)"
msgstr "High fidelity duplex (BAP-källa/utgång, kodek %s)"
#: spa/plugins/bluez5/bluez5-device.c:2212
#: spa/plugins/bluez5/bluez5-device.c:1962
msgid "High Fidelity Playback (BAP Sink)"
msgstr "High fidelity-uppspelning (BAP-utgång)"
#: spa/plugins/bluez5/bluez5-device.c:2216
#: spa/plugins/bluez5/bluez5-device.c:1966
msgid "High Fidelity Input (BAP Source)"
msgstr "High fidelity-ingång (BAP-källa)"
#: spa/plugins/bluez5/bluez5-device.c:2219
#: spa/plugins/bluez5/bluez5-device.c:1969
msgid "High Fidelity Duplex (BAP Source/Sink)"
msgstr "High fidelity duplex (BAP-källa/utgång)"
#: spa/plugins/bluez5/bluez5-device.c:2259
#: spa/plugins/bluez5/bluez5-device.c:2015
#, c-format
msgid "Headset Head Unit (HSP/HFP, codec %s)"
msgstr "Headset-huvudenhet (HSP/HFP, kodek %s)"
#: spa/plugins/bluez5/bluez5-device.c:2411
#: spa/plugins/bluez5/bluez5-device.c:2416
#: spa/plugins/bluez5/bluez5-device.c:2423
#: spa/plugins/bluez5/bluez5-device.c:2429
#: spa/plugins/bluez5/bluez5-device.c:2435
#: spa/plugins/bluez5/bluez5-device.c:2441
#: spa/plugins/bluez5/bluez5-device.c:2447
#: spa/plugins/bluez5/bluez5-device.c:2453
#: spa/plugins/bluez5/bluez5-device.c:2459
#: spa/plugins/bluez5/bluez5-device.c:2135
#: spa/plugins/bluez5/bluez5-device.c:2140
#: spa/plugins/bluez5/bluez5-device.c:2147
#: spa/plugins/bluez5/bluez5-device.c:2153
#: spa/plugins/bluez5/bluez5-device.c:2159
#: spa/plugins/bluez5/bluez5-device.c:2165
#: spa/plugins/bluez5/bluez5-device.c:2171
#: spa/plugins/bluez5/bluez5-device.c:2177
#: spa/plugins/bluez5/bluez5-device.c:2183
msgid "Handsfree"
msgstr "Handsfree"
#: spa/plugins/bluez5/bluez5-device.c:2417
#: spa/plugins/bluez5/bluez5-device.c:2141
msgid "Handsfree (HFP)"
msgstr "Handsfree (HFP)"
#: spa/plugins/bluez5/bluez5-device.c:2440
#: spa/plugins/bluez5/bluez5-device.c:2158
msgid "Headphone"
msgstr "Hörlurar"
#: spa/plugins/bluez5/bluez5-device.c:2164
msgid "Portable"
msgstr "Bärbar"
#: spa/plugins/bluez5/bluez5-device.c:2446
#: spa/plugins/bluez5/bluez5-device.c:2170
msgid "Car"
msgstr "Bil"
#: spa/plugins/bluez5/bluez5-device.c:2452
#: spa/plugins/bluez5/bluez5-device.c:2176
msgid "HiFi"
msgstr "HiFi"
#: spa/plugins/bluez5/bluez5-device.c:2458
#: spa/plugins/bluez5/bluez5-device.c:2182
msgid "Phone"
msgstr "Telefon"
#: spa/plugins/bluez5/bluez5-device.c:2465
#: spa/plugins/bluez5/bluez5-device.c:2189
msgid "Bluetooth"
msgstr "Bluetooth"
#: spa/plugins/bluez5/bluez5-device.c:2466
msgid "Bluetooth Handsfree"
msgstr "Bluetooth-handsfree"
#~ msgid "Headphone"
#~ msgstr "Hörlurar"
#: spa/plugins/bluez5/bluez5-device.c:2190
msgid "Bluetooth (HFP)"
msgstr "Bluetooth (HFP)"

View file

@ -6,15 +6,15 @@
# Cheng-Chia Tseng <pswo10680@gmail.com>, 2010, 2012.
# Frank Hill <hxf.prc@gmail.com>, 2015.
# Mingye Wang (Arthur2e5) <arthur200126@gmail.com>, 2015.
# lumingzh <lumingzh@qq.com>, 2024-2026.
# lumingzh <lumingzh@qq.com>, 2024-2025.
#
msgid ""
msgstr ""
"Project-Id-Version: pipewire.master-tx\n"
"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/-/"
"issues\n"
"POT-Creation-Date: 2026-03-19 15:38+0000\n"
"PO-Revision-Date: 2026-03-23 08:48+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"
@ -22,7 +22,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2016-03-22 13:23+0000\n"
"X-Generator: Gtranslator 50.0\n"
"X-Generator: Gtranslator 49.0\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: src/daemon/pipewire.c:29
@ -65,46 +65,21 @@ msgstr "虚拟输出"
msgid "Tunnel for %s@%s"
msgstr "用于 %s@%s 的隧道"
#: src/modules/module-zeroconf-discover.c:290
#: src/modules/module-zeroconf-discover.c:320
msgid "Unknown device"
msgstr "未知设备"
#: src/modules/module-zeroconf-discover.c:302
#: src/modules/module-zeroconf-discover.c:332
#, c-format
msgid "%s on %s@%s"
msgstr "%2$s@%3$s 上的 %1$s"
#: src/modules/module-zeroconf-discover.c:306
#: src/modules/module-zeroconf-discover.c:336
#, c-format
msgid "%s on %s"
msgstr "%2$s 上的 %1$s"
#: src/tools/pw-cat.c:269
#, c-format
msgid "Supported formats:\n"
msgstr "支持的格式:\n"
#: src/tools/pw-cat.c:754
#, c-format
msgid "Supported channel layouts:\n"
msgstr "支持的声道布局:\n"
#: src/tools/pw-cat.c:764
#, c-format
msgid "Supported channel layout aliases:\n"
msgstr "支持的声道布局别名:\n"
#: src/tools/pw-cat.c:766
#, c-format
msgid " %s -> %s\n"
msgstr " %s -> %s\n"
#: src/tools/pw-cat.c:771
#, c-format
msgid "Supported channel names:\n"
msgstr "支持的声道名称:\n"
#: src/tools/pw-cat.c:1182
#: src/tools/pw-cat.c:1088
#, c-format
msgid ""
"%s [options] [<file>|-]\n"
@ -119,7 +94,7 @@ msgstr ""
" -v, --verbose 输出详细操作\n"
"\n"
#: src/tools/pw-cat.c:1189
#: src/tools/pw-cat.c:1095
#, c-format
msgid ""
" -R, --remote Remote daemon name\n"
@ -151,23 +126,20 @@ msgstr ""
" -P --properties 设置节点属性\n"
"\n"
#: src/tools/pw-cat.c:1207
#: src/tools/pw-cat.c:1113
#, c-format
msgid ""
" --rate Sample rate (default %u)\n"
" --channels Number of channels (default %u)\n"
" --rate Sample rate (req. for rec) (default "
"%u)\n"
" --channels Number of channels (req. for rec) "
"(default %u)\n"
" --channel-map Channel map\n"
" a channel layout: \"Stereo\", "
"\"5.1\",... or\n"
" one of: \"Stereo\", \"5.1\",... "
"or\n"
" comma separated list of channel "
"names: eg. \"FL,FR\"\n"
" --list-layouts List supported channel layouts\n"
" --list-channel-names List supported channel maps\n"
" --format Sample format (default %s)\n"
" --list-formats List supported sample formats\n"
" --container Container format\n"
" --list-containers List supported containers and "
"extensions\n"
" --format Sample format %s (req. for rec) "
"(default %s)\n"
" --volume Stream volume 0-1.0 (default %.3f)\n"
" -q --quality Resampler quality (0 - 15) (default "
"%d)\n"
@ -177,19 +149,15 @@ msgid ""
" -n, --sample-count COUNT Stop after COUNT samples\n"
"\n"
msgstr ""
" --rate 采样率 (默认 %u)\n"
" --channels 声道数 (默认 %u)\n"
" --channel-map 道映射\n"
" 声道布局:\"stereo\", "
"\"5.1\",... 或\n"
" 以英文逗号分隔的道名列表: 如 "
" --rate 采样率 (录制模式需要) (默认 %u)\n"
" --channels 通道数 (录制模式需要) (默认 %u)\n"
" --channel-map 道映射\n"
" \"stereo\", \"5.1\",... 中的其一"
"或\n"
" 以英文逗号分隔的道名列表: 如 "
"\"FL,FR\"\n"
" --list-layouts 列出支持的声道布局\n"
" --list-channel-names 列出支持的声道映射\n"
" --format 采样格式 (默认 %s)\n"
" --list-formats 列出支持的采样格式\n"
" --container 容器格式\n"
" --list-containers 列出支持的容器和扩展\n"
" --format 采样格式 %s (录制模式需要) (默认 "
"%s)\n"
" --volume 媒体流音量 0-1.0 (默认 %.3f)\n"
" -q --quality 重采样质量 (0 - 15) (默认 %d)\n"
" -a, --raw 原生模式\n"
@ -198,7 +166,7 @@ msgstr ""
" -n, --sample-count COUNT 计数采样后停止\n"
"\n"
#: src/tools/pw-cat.c:1232
#: src/tools/pw-cat.c:1133
msgid ""
" -p, --playback Playback mode\n"
" -r, --record Recording mode\n"
@ -218,11 +186,6 @@ msgstr ""
" -c, --midi-clip MIDI 剪辑模式\n"
"\n"
#: src/tools/pw-cat.c:1837
#, c-format
msgid "Supported containers and extensions:\n"
msgstr "支持的容器和扩展:\n"
#: src/tools/pw-cli.c:2386
#, c-format
msgid ""
@ -245,12 +208,12 @@ msgstr ""
msgid "Pro Audio"
msgstr "专业音频"
#: spa/plugins/alsa/acp/acp.c:535 spa/plugins/alsa/acp/alsa-mixer.c:4699
#: spa/plugins/bluez5/bluez5-device.c:2165
#: 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 "关"
#: spa/plugins/alsa/acp/acp.c:618
#: spa/plugins/alsa/acp/acp.c:620
#, c-format
msgid "%s [ALSA UCM error]"
msgstr "%s [ALSA UCM 错误]"
@ -278,7 +241,7 @@ msgstr "输入插孔"
#: spa/plugins/alsa/acp/alsa-mixer.c:2726
#: spa/plugins/alsa/acp/alsa-mixer.c:2810
#: spa/plugins/bluez5/bluez5-device.c:2598
#: spa/plugins/bluez5/bluez5-device.c:2374
msgid "Microphone"
msgstr "话筒"
@ -344,15 +307,15 @@ msgid "No Bass Boost"
msgstr "无重低音增强"
#: spa/plugins/alsa/acp/alsa-mixer.c:2741
#: spa/plugins/bluez5/bluez5-device.c:2604
#: spa/plugins/bluez5/bluez5-device.c:2380
msgid "Speaker"
msgstr "扬声器"
#. Don't call it "headset", the HF one has the mic
#: spa/plugins/alsa/acp/alsa-mixer.c:2742
#: spa/plugins/alsa/acp/alsa-mixer.c:2820
#: spa/plugins/bluez5/bluez5-device.c:2610
#: spa/plugins/bluez5/bluez5-device.c:2677
#: spa/plugins/bluez5/bluez5-device.c:2386
#: spa/plugins/bluez5/bluez5-device.c:2453
msgid "Headphones"
msgstr "模拟耳机"
@ -462,7 +425,7 @@ msgstr "立体声"
#: spa/plugins/alsa/acp/alsa-mixer.c:4535
#: spa/plugins/alsa/acp/alsa-mixer.c:4693
#: spa/plugins/bluez5/bluez5-device.c:2586
#: spa/plugins/bluez5/bluez5-device.c:2362
msgid "Headset"
msgstr "耳机"
@ -657,109 +620,101 @@ msgstr "内置音频"
msgid "Modem"
msgstr "调制解调器"
#: spa/plugins/bluez5/bluez5-device.c:2176
#: spa/plugins/bluez5/bluez5-device.c:1987
msgid "Audio Gateway (A2DP Source & HSP/HFP AG)"
msgstr "音频网关 (A2DP 信源 或 HSP/HFP 网关)"
#: spa/plugins/bluez5/bluez5-device.c:2205
#: spa/plugins/bluez5/bluez5-device.c:2016
msgid "Audio Streaming for Hearing Aids (ASHA Sink)"
msgstr "助听器音频流 (ASHA 信宿)"
#: spa/plugins/bluez5/bluez5-device.c:2248
#: spa/plugins/bluez5/bluez5-device.c:2059
#, c-format
msgid "High Fidelity Playback (A2DP Sink, codec %s)"
msgstr "高保真回放 (A2DP 信宿, 编码 %s)"
#: spa/plugins/bluez5/bluez5-device.c:2251
#: spa/plugins/bluez5/bluez5-device.c:2062
#, c-format
msgid "High Fidelity Duplex (A2DP Source/Sink, codec %s)"
msgstr "高保真双工 (A2DP 信源/信宿, 编码 %s)"
#: spa/plugins/bluez5/bluez5-device.c:2259
#: spa/plugins/bluez5/bluez5-device.c:2070
msgid "High Fidelity Playback (A2DP Sink)"
msgstr "高保真回放 (A2DP 信宿)"
#: spa/plugins/bluez5/bluez5-device.c:2261
#: spa/plugins/bluez5/bluez5-device.c:2072
msgid "High Fidelity Duplex (A2DP Source/Sink)"
msgstr "高保真双工 (A2DP 信源/信宿)"
#: spa/plugins/bluez5/bluez5-device.c:2283
msgid "Auto: Prefer Quality (A2DP)"
msgstr "自动:质量优先 (A2DP)"
#: spa/plugins/bluez5/bluez5-device.c:2287
msgid "Auto: Prefer Latency (A2DP)"
msgstr "自动:延迟优先 (A2DP)"
#: spa/plugins/bluez5/bluez5-device.c:2368
#: spa/plugins/bluez5/bluez5-device.c:2146
#, c-format
msgid "High Fidelity Playback (BAP Sink, codec %s)"
msgstr "高保真回放 (BAP 信宿, 编码 %s)"
#: spa/plugins/bluez5/bluez5-device.c:2373
#: spa/plugins/bluez5/bluez5-device.c:2151
#, c-format
msgid "High Fidelity Input (BAP Source, codec %s)"
msgstr "高保真输入 (BAP 信源, 编码 %s)"
#: spa/plugins/bluez5/bluez5-device.c:2377
#: spa/plugins/bluez5/bluez5-device.c:2155
#, c-format
msgid "High Fidelity Duplex (BAP Source/Sink, codec %s)"
msgstr "高保真双工 (BAP 信源/信宿, 编码 %s)"
#: spa/plugins/bluez5/bluez5-device.c:2386
#: spa/plugins/bluez5/bluez5-device.c:2164
msgid "High Fidelity Playback (BAP Sink)"
msgstr "高保真回放 (BAP 信宿)"
#: spa/plugins/bluez5/bluez5-device.c:2390
#: spa/plugins/bluez5/bluez5-device.c:2168
msgid "High Fidelity Input (BAP Source)"
msgstr "高保真输入 (BAP 信源)"
#: spa/plugins/bluez5/bluez5-device.c:2393
#: spa/plugins/bluez5/bluez5-device.c:2171
msgid "High Fidelity Duplex (BAP Source/Sink)"
msgstr "高保真双工 (BAP 信源/信宿)"
#: spa/plugins/bluez5/bluez5-device.c:2433
#: spa/plugins/bluez5/bluez5-device.c:2211
#, c-format
msgid "Headset Head Unit (HSP/HFP, codec %s)"
msgstr "头戴式耳机单元 (HSP/HFP, 编码 %s)"
#: spa/plugins/bluez5/bluez5-device.c:2587
#: spa/plugins/bluez5/bluez5-device.c:2592
#: spa/plugins/bluez5/bluez5-device.c:2599
#: spa/plugins/bluez5/bluez5-device.c:2605
#: spa/plugins/bluez5/bluez5-device.c:2611
#: spa/plugins/bluez5/bluez5-device.c:2617
#: spa/plugins/bluez5/bluez5-device.c:2623
#: spa/plugins/bluez5/bluez5-device.c:2629
#: spa/plugins/bluez5/bluez5-device.c:2635
#: 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 "免提"
#: spa/plugins/bluez5/bluez5-device.c:2593
#: spa/plugins/bluez5/bluez5-device.c:2369
msgid "Handsfree (HFP)"
msgstr "免提HFP"
#: spa/plugins/bluez5/bluez5-device.c:2616
#: spa/plugins/bluez5/bluez5-device.c:2392
msgid "Portable"
msgstr "便携式"
#: spa/plugins/bluez5/bluez5-device.c:2622
#: spa/plugins/bluez5/bluez5-device.c:2398
msgid "Car"
msgstr "车内"
#: spa/plugins/bluez5/bluez5-device.c:2628
#: spa/plugins/bluez5/bluez5-device.c:2404
msgid "HiFi"
msgstr "高保真"
#: spa/plugins/bluez5/bluez5-device.c:2634
#: spa/plugins/bluez5/bluez5-device.c:2410
msgid "Phone"
msgstr "电话"
#: spa/plugins/bluez5/bluez5-device.c:2641
#: spa/plugins/bluez5/bluez5-device.c:2417
msgid "Bluetooth"
msgstr "蓝牙"
#: spa/plugins/bluez5/bluez5-device.c:2642
#: spa/plugins/bluez5/bluez5-device.c:2418
msgid "Bluetooth Handsfree"
msgstr "蓝牙免提"

View file

@ -4,221 +4,110 @@
#
# Cheng-Chia Tseng <pswo10680@gmail.com>, 2010, 2012.
# pan93412 <pan93412@gmail.com>, 2020.
# SPDX-FileCopyrightText: 2026 Kisaragi Hiu <mail@kisaragi-hiu.com>
msgid ""
msgstr ""
"Project-Id-Version: PipeWire Volume Control\n"
"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/"
"issues/new\n"
"POT-Creation-Date: 2026-03-11 22:03+0900\n"
"PO-Revision-Date: 2026-03-11 21:24+0900\n"
"Last-Translator: Kisaragi Hiu <mail@kisaragi-hiu.com>\n"
"Language-Team: Chinese (Taiwan) <zh-l10n@lists.slat.org>\n"
"POT-Creation-Date: 2021-04-18 16:54+0800\n"
"PO-Revision-Date: 2020-01-11 13:49+0800\n"
"Last-Translator: pan93412 <pan93412@gmail.com>\n"
"Language-Team: Chinese <zh-l10n@lists.linux.org.tw>\n"
"Language: zh_TW\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Lokalize 26.03.70\n"
"X-Generator: Lokalize 19.12.0\n"
"Plural-Forms: nplurals=1; plural=0;\n"
#: src/daemon/pipewire.c:29
#: src/daemon/pipewire.c:43
#, c-format
msgid ""
"%s [options]\n"
" -h, --help Show this help\n"
" -v, --verbose Increase verbosity by one level\n"
" --version Show version\n"
" -c, --config Load config (Default %s)\n"
" -P --properties Set context properties\n"
msgstr ""
"%s [選項]\n"
" -h, --help 顯示此說明\n"
" -v, --verbose 提高訊息詳細程度一階\n"
" --version 顯示版本\n"
" -c, --config 載入設定檔案(預設 %s\n"
" -P --properties 設定前後文屬性\n"
#: src/daemon/pipewire.desktop.in:4
msgid "PipeWire Media System"
msgstr "PipeWire 媒體系統"
msgstr ""
#: src/daemon/pipewire.desktop.in:5
msgid "Start the PipeWire Media System"
msgstr "啟動 PipeWire 媒體系統"
msgstr ""
#: src/modules/module-protocol-pulse/modules/module-tunnel-sink.c:159
#: src/modules/module-protocol-pulse/modules/module-tunnel-source.c:159
#, c-format
msgid "Tunnel to %s%s%s"
msgstr "穿隧到 %s%s%s"
#: src/examples/media-session/alsa-monitor.c:526
#: spa/plugins/alsa/acp/compat.c:187
msgid "Built-in Audio"
msgstr "內部音效"
#: src/modules/module-fallback-sink.c:40
msgid "Dummy Output"
msgstr "虛擬輸出"
#: src/examples/media-session/alsa-monitor.c:530
#: spa/plugins/alsa/acp/compat.c:192
msgid "Modem"
msgstr "數據機"
#: src/modules/module-pulse-tunnel.c:761
#, c-format
msgid "Tunnel for %s@%s"
msgstr "%s@%s 的穿隧道"
#: src/modules/module-zeroconf-discover.c:290
#: src/examples/media-session/alsa-monitor.c:539
msgid "Unknown device"
msgstr "未知裝置"
msgstr ""
#: src/modules/module-zeroconf-discover.c:302
#, c-format
msgid "%s on %s@%s"
msgstr "%s 於 %s@%s"
#: src/modules/module-zeroconf-discover.c:306
#, c-format
msgid "%s on %s"
msgstr "%s 於 %s"
#: src/tools/pw-cat.c:269
#, c-format
msgid "Supported formats:\n"
msgstr "支援的格式:\n"
#: src/tools/pw-cat.c:754
#, c-format
msgid "Supported channel layouts:\n"
msgstr "支援的頻道配置:\n"
#: src/tools/pw-cat.c:764
#, c-format
msgid "Supported channel layout aliases:\n"
msgstr "支援的頻道配置別名:\n"
#: src/tools/pw-cat.c:766
#, c-format
msgid " %s -> %s\n"
msgstr " %s -> %s\n"
#: src/tools/pw-cat.c:771
#, c-format
msgid "Supported channel names:\n"
msgstr "支援的頻道名稱:\n"
#: src/tools/pw-cat.c:1182
#: src/tools/pw-cat.c:991
#, c-format
msgid ""
"%s [options] [<file>|-]\n"
"%s [options] <file>\n"
" -h, --help Show this help\n"
" --version Show version\n"
" -v, --verbose Enable verbose operations\n"
"\n"
msgstr ""
"%s [選項] [<檔案>|-]\n"
" -h, --help 顯示此說明\n"
" --version 顯示版本\n"
" -v, --verbose 操作進行時顯示詳細訊息\n"
"\n"
#: src/tools/pw-cat.c:1189
#: src/tools/pw-cat.c:998
#, c-format
msgid ""
" -R, --remote Remote daemon name\n"
" --media-type Set media type (default %s)\n"
" --media-category Set media category (default %s)\n"
" --media-role Set media role (default %s)\n"
" --target Set node target serial or name "
"(default %s)\n"
" --target Set node target (default %s)\n"
" 0 means don't link\n"
" --latency Set node latency (default %s)\n"
" Xunit (unit = s, ms, us, ns)\n"
" or direct samples (256)\n"
" the rate is the one of the source "
"file\n"
" -P --properties Set node properties\n"
" --list-targets List available targets for --target\n"
"\n"
msgstr ""
" -R, --remote 遠端守護程式名稱\n"
" --media-type 設定媒體型態(預設 %s\n"
" --media-category 設定媒體分類(預設 %s\n"
" --media-role 設定媒體角色(預設 %s\n"
" --target 設定節點目標序號或名稱(預設 %s\n"
" 0 代表不要連結\n"
" --latency 設定節點延遲(預設 %s\n"
" X單位單位為 s, ms, us 或 ns\n"
" 或直接指定樣本數 (256)\n"
" 取樣率取自來源檔案\n"
" -P --properties 設定節點屬性\n"
"\n"
#: src/tools/pw-cat.c:1207
#: src/tools/pw-cat.c:1016
#, c-format
msgid ""
" --rate Sample rate (default %u)\n"
" --channels Number of channels (default %u)\n"
" --rate Sample rate (req. for rec) (default "
"%u)\n"
" --channels Number of channels (req. for rec) "
"(default %u)\n"
" --channel-map Channel map\n"
" a channel layout: \"Stereo\", "
"\"5.1\",... or\n"
" one of: \"stereo\", "
"\"surround-51\",... or\n"
" comma separated list of channel "
"names: eg. \"FL,FR\"\n"
" --list-layouts List supported channel layouts\n"
" --list-channel-names List supported channel maps\n"
" --format Sample format (default %s)\n"
" --list-formats List supported sample formats\n"
" --container Container format\n"
" --list-containers List supported containers and "
"extensions\n"
" --format Sample format %s (req. for rec) "
"(default %s)\n"
" --volume Stream volume 0-1.0 (default %.3f)\n"
" -q --quality Resampler quality (0 - 15) (default "
"%d)\n"
" -a, --raw RAW mode\n"
" -M, --force-midi Force midi format, one of \"midi\" "
"or \"ump\", (default ump)\n"
" -n, --sample-count COUNT Stop after COUNT samples\n"
"\n"
msgstr ""
" --rate 取樣率(預設 %u\n"
" --channels 頻道數量(預設 %u\n"
" --channel-map 頻道映射\n"
" 可以是頻道配置名稱,像是 "
"\"Stereo\"、\"5.1\" 等等,或是\n"
" 以逗號分隔的頻道名稱清單,像是 "
"\"FL,FR\"\n"
" --list-layouts 列出支援的頻道配置\n"
" --list-channel-names 列出支援的頻道映射\n"
" --format 取樣格式(預設 %s\n"
" --list-formats 列出支援的取樣格式\n"
" --container 容器格式\n"
" --list-containers 列出支援的容器與副檔名\n"
" --volume 串流音量 0-1.0(預設 %.3f\n"
" -q --quality 重新取樣器品質 0-15預設 %d\n"
" -a, --raw 原始模式\n"
" -M, --force-midi 強制使用 midi 格式,可選擇 \"midi\" "
"或 \"ump\"(預設 ump\n"
" -n, --sample-count 樣本數 在「樣本數」個樣本之後停止\n"
"\n"
#: src/tools/pw-cat.c:1232
#: src/tools/pw-cat.c:1033
msgid ""
" -p, --playback Playback mode\n"
" -r, --record Recording mode\n"
" -m, --midi Midi mode\n"
" -d, --dsd DSD mode\n"
" -o, --encoded Encoded mode\n"
" -s, --sysex SysEx mode\n"
" -c, --midi-clip MIDI clip mode\n"
"\n"
msgstr ""
" -p, --playback 播放模式\n"
" -r, --record 錄製模式\n"
" -m, --midi Midi 模式\n"
" -d, --dsd DSD 模式\n"
" -o, --encoded 已編碼模式\n"
" -s, --sysex SysEx 模式\n"
" -c, --midi-clip MIDI 素材模式\n"
"\n"
#: src/tools/pw-cat.c:1837
#, c-format
msgid "Supported containers and extensions:\n"
msgstr "支援的容器與副檔名:\n"
#: src/tools/pw-cli.c:2386
#: src/tools/pw-cli.c:2932
#, c-format
msgid ""
"%s [options] [command]\n"
@ -226,363 +115,357 @@ msgid ""
" --version Show version\n"
" -d, --daemon Start as daemon (Default false)\n"
" -r, --remote Remote daemon name\n"
" -m, --monitor Monitor activity\n"
"\n"
msgstr ""
"%s [選項] [指令]\n"
" -h, --help 顯示此說明\n"
" --version 顯示版本\n"
" -d, --daemon 作為守護程式啟動(預設為否)\n"
" -r, --remote 遠端守護程式名稱\n"
" -m, --monitor 監控活動\n"
"\n"
#: spa/plugins/alsa/acp/acp.c:361
#: spa/plugins/alsa/acp/acp.c:290
msgid "Pro Audio"
msgstr "Pro Audio"
msgstr ""
#: spa/plugins/alsa/acp/acp.c:535 spa/plugins/alsa/acp/alsa-mixer.c:4699
#: spa/plugins/bluez5/bluez5-device.c:2021
#: spa/plugins/alsa/acp/acp.c:411 spa/plugins/alsa/acp/alsa-mixer.c:4704
#: spa/plugins/bluez5/bluez5-device.c:1000
msgid "Off"
msgstr "關閉"
#: spa/plugins/alsa/acp/acp.c:618
#, c-format
msgid "%s [ALSA UCM error]"
msgstr "%s [ALSA UCM 錯誤]"
#: spa/plugins/alsa/acp/channelmap.h:466
msgid "(invalid)"
msgstr "(無效)"
#: spa/plugins/alsa/acp/alsa-mixer.c:2721
#: spa/plugins/alsa/acp/alsa-mixer.c:2709
msgid "Input"
msgstr "輸入"
#: spa/plugins/alsa/acp/alsa-mixer.c:2722
#: spa/plugins/alsa/acp/alsa-mixer.c:2710
msgid "Docking Station Input"
msgstr "Docking Station 輸入"
#: spa/plugins/alsa/acp/alsa-mixer.c:2723
#: spa/plugins/alsa/acp/alsa-mixer.c:2711
msgid "Docking Station Microphone"
msgstr "Docking Station 麥克風"
#: spa/plugins/alsa/acp/alsa-mixer.c:2724
#: spa/plugins/alsa/acp/alsa-mixer.c:2712
msgid "Docking Station Line In"
msgstr "Docking Station 線路輸入"
#: spa/plugins/alsa/acp/alsa-mixer.c:2725
#: spa/plugins/alsa/acp/alsa-mixer.c:2816
#: spa/plugins/alsa/acp/alsa-mixer.c:2713
#: spa/plugins/alsa/acp/alsa-mixer.c:2804
msgid "Line In"
msgstr "線路輸入"
#: spa/plugins/alsa/acp/alsa-mixer.c:2726
#: spa/plugins/alsa/acp/alsa-mixer.c:2810
#: spa/plugins/bluez5/bluez5-device.c:2422
#: spa/plugins/alsa/acp/alsa-mixer.c:2714
#: spa/plugins/alsa/acp/alsa-mixer.c:2798
#: spa/plugins/bluez5/bluez5-device.c:1145
msgid "Microphone"
msgstr "麥克風"
#: spa/plugins/alsa/acp/alsa-mixer.c:2727
#: spa/plugins/alsa/acp/alsa-mixer.c:2811
#: spa/plugins/alsa/acp/alsa-mixer.c:2715
#: spa/plugins/alsa/acp/alsa-mixer.c:2799
msgid "Front Microphone"
msgstr "前方麥克風"
#: spa/plugins/alsa/acp/alsa-mixer.c:2728
#: spa/plugins/alsa/acp/alsa-mixer.c:2812
#: spa/plugins/alsa/acp/alsa-mixer.c:2716
#: spa/plugins/alsa/acp/alsa-mixer.c:2800
msgid "Rear Microphone"
msgstr "後方麥克風"
#: spa/plugins/alsa/acp/alsa-mixer.c:2729
#: spa/plugins/alsa/acp/alsa-mixer.c:2717
msgid "External Microphone"
msgstr "外接麥克風"
#: spa/plugins/alsa/acp/alsa-mixer.c:2730
#: spa/plugins/alsa/acp/alsa-mixer.c:2814
#: spa/plugins/alsa/acp/alsa-mixer.c:2718
#: spa/plugins/alsa/acp/alsa-mixer.c:2802
msgid "Internal Microphone"
msgstr "內建麥克風"
#: spa/plugins/alsa/acp/alsa-mixer.c:2731
#: spa/plugins/alsa/acp/alsa-mixer.c:2817
#: spa/plugins/alsa/acp/alsa-mixer.c:2719
#: spa/plugins/alsa/acp/alsa-mixer.c:2805
msgid "Radio"
msgstr "無線電"
#: spa/plugins/alsa/acp/alsa-mixer.c:2732
#: spa/plugins/alsa/acp/alsa-mixer.c:2818
#: spa/plugins/alsa/acp/alsa-mixer.c:2720
#: spa/plugins/alsa/acp/alsa-mixer.c:2806
msgid "Video"
msgstr "視訊"
#: spa/plugins/alsa/acp/alsa-mixer.c:2733
#: spa/plugins/alsa/acp/alsa-mixer.c:2721
msgid "Automatic Gain Control"
msgstr "自動增益控制"
#: spa/plugins/alsa/acp/alsa-mixer.c:2734
#: spa/plugins/alsa/acp/alsa-mixer.c:2722
msgid "No Automatic Gain Control"
msgstr "無自動增益控制"
#: spa/plugins/alsa/acp/alsa-mixer.c:2735
#: spa/plugins/alsa/acp/alsa-mixer.c:2723
msgid "Boost"
msgstr "增強"
#: spa/plugins/alsa/acp/alsa-mixer.c:2736
#: spa/plugins/alsa/acp/alsa-mixer.c:2724
msgid "No Boost"
msgstr "無增強"
#: spa/plugins/alsa/acp/alsa-mixer.c:2737
#: spa/plugins/alsa/acp/alsa-mixer.c:2725
msgid "Amplifier"
msgstr "擴大器"
#: spa/plugins/alsa/acp/alsa-mixer.c:2738
#: spa/plugins/alsa/acp/alsa-mixer.c:2726
msgid "No Amplifier"
msgstr "無擴大器"
#: spa/plugins/alsa/acp/alsa-mixer.c:2739
#: spa/plugins/alsa/acp/alsa-mixer.c:2727
msgid "Bass Boost"
msgstr "低音增強"
#: spa/plugins/alsa/acp/alsa-mixer.c:2740
#: spa/plugins/alsa/acp/alsa-mixer.c:2728
msgid "No Bass Boost"
msgstr "無低音增強"
#: spa/plugins/alsa/acp/alsa-mixer.c:2741
#: spa/plugins/bluez5/bluez5-device.c:2428
#: spa/plugins/alsa/acp/alsa-mixer.c:2729
#: spa/plugins/bluez5/bluez5-device.c:1150
msgid "Speaker"
msgstr "喇叭"
#. Don't call it "headset", the HF one has the mic
#: spa/plugins/alsa/acp/alsa-mixer.c:2742
#: spa/plugins/alsa/acp/alsa-mixer.c:2820
#: spa/plugins/bluez5/bluez5-device.c:2434
#: spa/plugins/bluez5/bluez5-device.c:2501
#: spa/plugins/alsa/acp/alsa-mixer.c:2730
#: spa/plugins/alsa/acp/alsa-mixer.c:2808
msgid "Headphones"
msgstr "頭戴式耳機"
#: spa/plugins/alsa/acp/alsa-mixer.c:2809
#: spa/plugins/alsa/acp/alsa-mixer.c:2797
msgid "Analog Input"
msgstr "類比輸入"
#: spa/plugins/alsa/acp/alsa-mixer.c:2813
#: spa/plugins/alsa/acp/alsa-mixer.c:2801
msgid "Dock Microphone"
msgstr "臺座麥克風"
#: spa/plugins/alsa/acp/alsa-mixer.c:2815
#: spa/plugins/alsa/acp/alsa-mixer.c:2803
msgid "Headset Microphone"
msgstr "耳麥麥克風"
#: spa/plugins/alsa/acp/alsa-mixer.c:2819
#: spa/plugins/alsa/acp/alsa-mixer.c:2807
msgid "Analog Output"
msgstr "類比輸出"
#: spa/plugins/alsa/acp/alsa-mixer.c:2821
#: spa/plugins/alsa/acp/alsa-mixer.c:2809
#, fuzzy
msgid "Headphones 2"
msgstr "頭戴式耳機 2"
msgstr "頭戴式耳機"
#: spa/plugins/alsa/acp/alsa-mixer.c:2822
#: spa/plugins/alsa/acp/alsa-mixer.c:2810
msgid "Headphones Mono Output"
msgstr "頭戴式耳機單聲道輸出"
#: spa/plugins/alsa/acp/alsa-mixer.c:2823
#: spa/plugins/alsa/acp/alsa-mixer.c:2811
msgid "Line Out"
msgstr "線路輸出"
#: spa/plugins/alsa/acp/alsa-mixer.c:2824
#: spa/plugins/alsa/acp/alsa-mixer.c:2812
msgid "Analog Mono Output"
msgstr "類比單聲道輸出"
#: spa/plugins/alsa/acp/alsa-mixer.c:2825
#: spa/plugins/alsa/acp/alsa-mixer.c:2813
msgid "Speakers"
msgstr "喇叭"
#: spa/plugins/alsa/acp/alsa-mixer.c:2826
#: spa/plugins/alsa/acp/alsa-mixer.c:2814
msgid "HDMI / DisplayPort"
msgstr "HDMI / DisplayPort"
#: spa/plugins/alsa/acp/alsa-mixer.c:2827
#: spa/plugins/alsa/acp/alsa-mixer.c:2815
msgid "Digital Output (S/PDIF)"
msgstr "數位輸出 (S/PDIF)"
#: spa/plugins/alsa/acp/alsa-mixer.c:2828
#: spa/plugins/alsa/acp/alsa-mixer.c:2816
msgid "Digital Input (S/PDIF)"
msgstr "數位輸入 (S/PDIF)"
#: spa/plugins/alsa/acp/alsa-mixer.c:2829
#: spa/plugins/alsa/acp/alsa-mixer.c:2817
msgid "Multichannel Input"
msgstr "多聲道輸入"
#: spa/plugins/alsa/acp/alsa-mixer.c:2830
#: spa/plugins/alsa/acp/alsa-mixer.c:2818
msgid "Multichannel Output"
msgstr "多聲道輸出"
#: spa/plugins/alsa/acp/alsa-mixer.c:2831
#: spa/plugins/alsa/acp/alsa-mixer.c:2819
msgid "Game Output"
msgstr "遊戲輸出"
#: spa/plugins/alsa/acp/alsa-mixer.c:2832
#: spa/plugins/alsa/acp/alsa-mixer.c:2833
#: spa/plugins/alsa/acp/alsa-mixer.c:2820
#: spa/plugins/alsa/acp/alsa-mixer.c:2821
msgid "Chat Output"
msgstr "聊天輸出"
#: spa/plugins/alsa/acp/alsa-mixer.c:2834
#: spa/plugins/alsa/acp/alsa-mixer.c:2822
#, fuzzy
msgid "Chat Input"
msgstr "聊天輸"
msgstr "聊天輸"
#: spa/plugins/alsa/acp/alsa-mixer.c:2835
#: spa/plugins/alsa/acp/alsa-mixer.c:2823
#, fuzzy
msgid "Virtual Surround 7.1"
msgstr "虛擬環繞聲 7.1"
msgstr "虛擬環繞聲 sink"
#: spa/plugins/alsa/acp/alsa-mixer.c:4522
#: spa/plugins/alsa/acp/alsa-mixer.c:4527
msgid "Analog Mono"
msgstr "類比單聲道"
#: spa/plugins/alsa/acp/alsa-mixer.c:4523
#: spa/plugins/alsa/acp/alsa-mixer.c:4528
#, fuzzy
msgid "Analog Mono (Left)"
msgstr "類比單聲道(左)"
msgstr "類比單聲道"
#: spa/plugins/alsa/acp/alsa-mixer.c:4524
#: spa/plugins/alsa/acp/alsa-mixer.c:4529
#, fuzzy
msgid "Analog Mono (Right)"
msgstr "類比單聲道(右)"
msgstr "類比單聲道"
#. Note: Not translated to "Analog Stereo Input", because the source
#. * name gets "Input" appended to it automatically, so adding "Input"
#. * 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:4525
#: spa/plugins/alsa/acp/alsa-mixer.c:4533
#: spa/plugins/alsa/acp/alsa-mixer.c:4534
#: spa/plugins/alsa/acp/alsa-mixer.c:4530
#: spa/plugins/alsa/acp/alsa-mixer.c:4538
#: spa/plugins/alsa/acp/alsa-mixer.c:4539
msgid "Analog Stereo"
msgstr "類比立體聲"
#: spa/plugins/alsa/acp/alsa-mixer.c:4526
#: spa/plugins/alsa/acp/alsa-mixer.c:4531
msgid "Mono"
msgstr "單聲道"
#: spa/plugins/alsa/acp/alsa-mixer.c:4527
#: spa/plugins/alsa/acp/alsa-mixer.c:4532
msgid "Stereo"
msgstr "立體聲"
#: spa/plugins/alsa/acp/alsa-mixer.c:4535
#: spa/plugins/alsa/acp/alsa-mixer.c:4693
#: spa/plugins/bluez5/bluez5-device.c:2410
#: spa/plugins/alsa/acp/alsa-mixer.c:4540
#: spa/plugins/alsa/acp/alsa-mixer.c:4698
#: spa/plugins/bluez5/bluez5-device.c:1135
msgid "Headset"
msgstr "耳麥"
#: spa/plugins/alsa/acp/alsa-mixer.c:4536
#: spa/plugins/alsa/acp/alsa-mixer.c:4694
#: spa/plugins/alsa/acp/alsa-mixer.c:4541
#: spa/plugins/alsa/acp/alsa-mixer.c:4699
#, fuzzy
msgid "Speakerphone"
msgstr "會議揚聲器"
msgstr "喇叭"
#: spa/plugins/alsa/acp/alsa-mixer.c:4537
#: spa/plugins/alsa/acp/alsa-mixer.c:4538
#: spa/plugins/alsa/acp/alsa-mixer.c:4542
#: spa/plugins/alsa/acp/alsa-mixer.c:4543
msgid "Multichannel"
msgstr "多聲道"
#: spa/plugins/alsa/acp/alsa-mixer.c:4539
#: spa/plugins/alsa/acp/alsa-mixer.c:4544
msgid "Analog Surround 2.1"
msgstr "類比環繞聲 2.1"
#: spa/plugins/alsa/acp/alsa-mixer.c:4540
#: spa/plugins/alsa/acp/alsa-mixer.c:4545
msgid "Analog Surround 3.0"
msgstr "類比環繞聲 3.0"
#: spa/plugins/alsa/acp/alsa-mixer.c:4541
#: spa/plugins/alsa/acp/alsa-mixer.c:4546
msgid "Analog Surround 3.1"
msgstr "類比環繞聲 3.1"
#: spa/plugins/alsa/acp/alsa-mixer.c:4542
#: spa/plugins/alsa/acp/alsa-mixer.c:4547
msgid "Analog Surround 4.0"
msgstr "類比環繞聲 4.0"
#: spa/plugins/alsa/acp/alsa-mixer.c:4543
#: spa/plugins/alsa/acp/alsa-mixer.c:4548
msgid "Analog Surround 4.1"
msgstr "類比環繞聲 4.1"
#: spa/plugins/alsa/acp/alsa-mixer.c:4544
#: spa/plugins/alsa/acp/alsa-mixer.c:4549
msgid "Analog Surround 5.0"
msgstr "類比環繞聲 5.0"
#: spa/plugins/alsa/acp/alsa-mixer.c:4545
#: spa/plugins/alsa/acp/alsa-mixer.c:4550
msgid "Analog Surround 5.1"
msgstr "類比環繞聲 5.1"
#: spa/plugins/alsa/acp/alsa-mixer.c:4546
#: spa/plugins/alsa/acp/alsa-mixer.c:4551
msgid "Analog Surround 6.0"
msgstr "類比環繞聲 6.0"
#: spa/plugins/alsa/acp/alsa-mixer.c:4547
#: spa/plugins/alsa/acp/alsa-mixer.c:4552
msgid "Analog Surround 6.1"
msgstr "類比環繞聲 6.1"
#: spa/plugins/alsa/acp/alsa-mixer.c:4548
#: spa/plugins/alsa/acp/alsa-mixer.c:4553
msgid "Analog Surround 7.0"
msgstr "類比環繞聲 7.0"
#: spa/plugins/alsa/acp/alsa-mixer.c:4549
#: spa/plugins/alsa/acp/alsa-mixer.c:4554
msgid "Analog Surround 7.1"
msgstr "類比環繞聲 7.1"
#: spa/plugins/alsa/acp/alsa-mixer.c:4550
#: spa/plugins/alsa/acp/alsa-mixer.c:4555
msgid "Digital Stereo (IEC958)"
msgstr "數位立體聲 (IEC958)"
#: spa/plugins/alsa/acp/alsa-mixer.c:4551
#: spa/plugins/alsa/acp/alsa-mixer.c:4556
msgid "Digital Surround 4.0 (IEC958/AC3)"
msgstr "數位環繞聲 4.0 (IEC958/AC3)"
#: spa/plugins/alsa/acp/alsa-mixer.c:4552
#: spa/plugins/alsa/acp/alsa-mixer.c:4557
msgid "Digital Surround 5.1 (IEC958/AC3)"
msgstr "數位環繞聲 5.1 (IEC958/AC3)"
#: spa/plugins/alsa/acp/alsa-mixer.c:4553
#: spa/plugins/alsa/acp/alsa-mixer.c:4558
msgid "Digital Surround 5.1 (IEC958/DTS)"
msgstr "數位環繞聲 5.1 (IEC958/DTS)"
#: spa/plugins/alsa/acp/alsa-mixer.c:4554
#: spa/plugins/alsa/acp/alsa-mixer.c:4559
msgid "Digital Stereo (HDMI)"
msgstr "數位立體聲 (HDMI)"
#: spa/plugins/alsa/acp/alsa-mixer.c:4555
#: spa/plugins/alsa/acp/alsa-mixer.c:4560
msgid "Digital Surround 5.1 (HDMI)"
msgstr "數位環繞聲 5.1 (HDMI)"
#: spa/plugins/alsa/acp/alsa-mixer.c:4556
#: spa/plugins/alsa/acp/alsa-mixer.c:4561
msgid "Chat"
msgstr "聊天"
msgstr ""
#: spa/plugins/alsa/acp/alsa-mixer.c:4557
#: spa/plugins/alsa/acp/alsa-mixer.c:4562
msgid "Game"
msgstr "遊戲"
msgstr ""
#: spa/plugins/alsa/acp/alsa-mixer.c:4691
#: spa/plugins/alsa/acp/alsa-mixer.c:4696
msgid "Analog Mono Duplex"
msgstr "類比單聲道雙工"
#: spa/plugins/alsa/acp/alsa-mixer.c:4692
#: spa/plugins/alsa/acp/alsa-mixer.c:4697
msgid "Analog Stereo Duplex"
msgstr "類比立體聲雙工"
#: spa/plugins/alsa/acp/alsa-mixer.c:4695
#: spa/plugins/alsa/acp/alsa-mixer.c:4700
msgid "Digital Stereo Duplex (IEC958)"
msgstr "數位立體聲雙工 (IEC958)"
#: spa/plugins/alsa/acp/alsa-mixer.c:4696
#: spa/plugins/alsa/acp/alsa-mixer.c:4701
msgid "Multichannel Duplex"
msgstr "多聲道雙工"
#: spa/plugins/alsa/acp/alsa-mixer.c:4697
#: spa/plugins/alsa/acp/alsa-mixer.c:4702
msgid "Stereo Duplex"
msgstr "立體聲雙工"
#: spa/plugins/alsa/acp/alsa-mixer.c:4698
#: spa/plugins/alsa/acp/alsa-mixer.c:4703
msgid "Mono Chat + 7.1 Surround"
msgstr "單聲道聊天 + 7.1 立體聲"
msgstr ""
#: spa/plugins/alsa/acp/alsa-mixer.c:4799
#: spa/plugins/alsa/acp/alsa-mixer.c:4806
#, c-format
msgid "%s Output"
msgstr "%s 輸出"
#: spa/plugins/alsa/acp/alsa-mixer.c:4807
#: spa/plugins/alsa/acp/alsa-mixer.c:4813
#, c-format
msgid "%s Input"
msgstr "%s 輸入"
#: spa/plugins/alsa/acp/alsa-util.c:1233 spa/plugins/alsa/acp/alsa-util.c:1327
#: spa/plugins/alsa/acp/alsa-util.c:1175 spa/plugins/alsa/acp/alsa-util.c:1269
#, c-format
msgid ""
"snd_pcm_avail() returned a value that is exceptionally large: %lu byte (%lu "
@ -598,23 +481,23 @@ msgstr[0] ""
"snd_pcm_avail() 傳回超出預期的大值:%lu bytes (%lu ms)。\n"
"這很能是 ALSA 驅動程式「%s」的臭蟲。請回報這個問題給 ALSA 開發者。"
#: spa/plugins/alsa/acp/alsa-util.c:1299
#: spa/plugins/alsa/acp/alsa-util.c:1241
#, 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."
msgstr[0] ""
"snd_pcm_delay() 傳回超出預期的大值:%li bytes (%s%lu ms)。\n"
"這很能是 ALSA 驅動程式「%s」的臭蟲。請回報這個問題給 ALSA 開發者。"
#: spa/plugins/alsa/acp/alsa-util.c:1346
#: spa/plugins/alsa/acp/alsa-util.c:1288
#, c-format
msgid ""
"snd_pcm_avail_delay() returned strange values: delay %lu is less than avail "
@ -625,7 +508,7 @@ msgstr ""
"snd_pcm_avail_delay() 傳回超出預期的大值:延遲 %lu 少於可用的 %lu。\n"
"這很能是 ALSA 驅動程式「%s」的臭蟲。請回報這個問題給 ALSA 開發者。"
#: spa/plugins/alsa/acp/alsa-util.c:1389
#: spa/plugins/alsa/acp/alsa-util.c:1331
#, c-format
msgid ""
"snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu byte "
@ -641,115 +524,62 @@ msgstr[0] ""
"snd_pcm_mmap_begin() 傳回超出預期的大值:%lu bytes (%lu ms)。\n"
"這很能是 ALSA 驅動程式「%s」的臭蟲。請回報這個問題給 ALSA 開發者。"
#: spa/plugins/alsa/acp/channelmap.h:460
msgid "(invalid)"
msgstr "(無效)"
#: spa/plugins/alsa/acp/compat.c:194
msgid "Built-in Audio"
msgstr "內部音效"
#: spa/plugins/alsa/acp/compat.c:199
msgid "Modem"
msgstr "數據機"
#: spa/plugins/bluez5/bluez5-device.c:2032
#: spa/plugins/bluez5/bluez5-device.c:1010
msgid "Audio Gateway (A2DP Source & HSP/HFP AG)"
msgstr "音訊閘道 (A2DP Source & HSP/HFP AG)"
msgstr ""
#: spa/plugins/bluez5/bluez5-device.c:2061
msgid "Audio Streaming for Hearing Aids (ASHA Sink)"
msgstr "助聽器的音訊串流 (ASHA Sink)"
#: spa/plugins/bluez5/bluez5-device.c:2104
#: spa/plugins/bluez5/bluez5-device.c:1033
#, c-format
msgid "High Fidelity Playback (A2DP Sink, codec %s)"
msgstr "高傳真播放裝置 (A2DP Sink編碼器 %s)"
msgstr ""
#: spa/plugins/bluez5/bluez5-device.c:2107
#: spa/plugins/bluez5/bluez5-device.c:1035
#, c-format
msgid "High Fidelity Duplex (A2DP Source/Sink, codec %s)"
msgstr "高傳真雙工裝置 (A2DP Source/Sink編碼器 %s)"
msgstr ""
#: spa/plugins/bluez5/bluez5-device.c:2115
#: spa/plugins/bluez5/bluez5-device.c:1041
msgid "High Fidelity Playback (A2DP Sink)"
msgstr "高傳真播放裝置 (A2DP Sink)"
msgstr ""
#: spa/plugins/bluez5/bluez5-device.c:2117
#: spa/plugins/bluez5/bluez5-device.c:1043
msgid "High Fidelity Duplex (A2DP Source/Sink)"
msgstr "高傳真雙工裝置 (A2DP Source/Sink)"
msgstr ""
#: spa/plugins/bluez5/bluez5-device.c:2194
#, c-format
msgid "High Fidelity Playback (BAP Sink, codec %s)"
msgstr "高傳真播放裝置 (BAP Sink編碼器 %s)"
#: spa/plugins/bluez5/bluez5-device.c:2199
#, c-format
msgid "High Fidelity Input (BAP Source, codec %s)"
msgstr "高傳真輸入裝置 (BAP Source編碼器 %s)"
#: spa/plugins/bluez5/bluez5-device.c:2203
#, c-format
msgid "High Fidelity Duplex (BAP Source/Sink, codec %s)"
msgstr "高傳真雙工裝置 (BAP Source/Sink編碼器 %s)"
#: spa/plugins/bluez5/bluez5-device.c:2212
msgid "High Fidelity Playback (BAP Sink)"
msgstr "高傳真播放裝置 (BAP Sink)"
#: spa/plugins/bluez5/bluez5-device.c:2216
msgid "High Fidelity Input (BAP Source)"
msgstr "高傳真輸入裝置 (BAP Source)"
#: spa/plugins/bluez5/bluez5-device.c:2219
msgid "High Fidelity Duplex (BAP Source/Sink)"
msgstr "高傳真雙工裝置 (BAP Source/Sink)"
#: spa/plugins/bluez5/bluez5-device.c:2259
#: spa/plugins/bluez5/bluez5-device.c:1070
#, c-format
msgid "Headset Head Unit (HSP/HFP, codec %s)"
msgstr "耳麥頭戴單元 (HSP/HFP編碼器 %s)"
msgstr ""
#: spa/plugins/bluez5/bluez5-device.c:2411
#: spa/plugins/bluez5/bluez5-device.c:2416
#: spa/plugins/bluez5/bluez5-device.c:2423
#: spa/plugins/bluez5/bluez5-device.c:2429
#: spa/plugins/bluez5/bluez5-device.c:2435
#: spa/plugins/bluez5/bluez5-device.c:2441
#: spa/plugins/bluez5/bluez5-device.c:2447
#: spa/plugins/bluez5/bluez5-device.c:2453
#: spa/plugins/bluez5/bluez5-device.c:2459
#: spa/plugins/bluez5/bluez5-device.c:1074
msgid "Headset Head Unit (HSP/HFP)"
msgstr ""
#: spa/plugins/bluez5/bluez5-device.c:1140
msgid "Handsfree"
msgstr "免持裝置"
#: spa/plugins/bluez5/bluez5-device.c:2417
msgid "Handsfree (HFP)"
msgstr "免持裝置 (HFP)"
#: spa/plugins/bluez5/bluez5-device.c:1155
msgid "Headphone"
msgstr "頭戴式耳機"
#: spa/plugins/bluez5/bluez5-device.c:2440
#: spa/plugins/bluez5/bluez5-device.c:1160
msgid "Portable"
msgstr "可攜裝置"
#: spa/plugins/bluez5/bluez5-device.c:2446
#: spa/plugins/bluez5/bluez5-device.c:1165
msgid "Car"
msgstr "汽車"
#: spa/plugins/bluez5/bluez5-device.c:2452
#: spa/plugins/bluez5/bluez5-device.c:1170
msgid "HiFi"
msgstr "HiFi"
#: spa/plugins/bluez5/bluez5-device.c:2458
#: spa/plugins/bluez5/bluez5-device.c:1175
msgid "Phone"
msgstr "手機"
#: spa/plugins/bluez5/bluez5-device.c:2465
#: spa/plugins/bluez5/bluez5-device.c:1181
#, fuzzy
msgid "Bluetooth"
msgstr "藍牙"
#: spa/plugins/bluez5/bluez5-device.c:2466
msgid "Bluetooth Handsfree"
msgstr "藍牙免持裝置"
#~ msgid "Headphone"
#~ msgstr "頭戴式耳機"
msgstr "藍牙輸入"

View file

@ -44,7 +44,7 @@ spa_format_audio_dsd_parse(const struct spa_pod *format, struct spa_audio_info_d
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 -EINVAL;
return -ECHRNG;
if (position == NULL ||
spa_pod_copy_array(position, SPA_TYPE_Id, info->position, max_position) != info->channels) {
SPA_FLAG_SET(info->flags, SPA_AUDIO_FLAG_UNPOSITIONED);

View file

@ -87,7 +87,7 @@ spa_audio_layout_info_parse_name(struct spa_audio_layout_info *layout, size_t si
uint32_t i, n_pos;
if (spa_atou32(name+3, &n_pos, 10)) {
if (n_pos > max_position)
return -EINVAL;
return -ECHRNG;
for (i = 0; i < 0x1000 && i < n_pos; i++)
layout->position[i] = SPA_AUDIO_CHANNEL_AUX0 + i;
for (; i < n_pos; i++)
@ -99,7 +99,7 @@ spa_audio_layout_info_parse_name(struct spa_audio_layout_info *layout, size_t si
SPA_FOR_EACH_ELEMENT_VAR(spa_type_audio_layout_info, i) {
if (spa_streq(name, i->name)) {
if (i->layout.n_channels > max_position)
return -EINVAL;
return -ECHRNG;
*layout = i->layout;
return i->layout.n_channels;
}

View file

@ -88,14 +88,14 @@ spa_audio_info_raw_ext_update(struct spa_audio_info_raw *info, size_t size,
} else if (spa_streq(key, SPA_KEY_AUDIO_CHANNELS)) {
if (spa_atou32(val, &v, 0) && (force || info->channels == 0)) {
if (v > max_position)
return -EINVAL;
return -ECHRNG;
info->channels = v;
}
} else if (spa_streq(key, SPA_KEY_AUDIO_LAYOUT)) {
if (force || info->channels == 0) {
if (spa_audio_parse_layout(val, info->position, max_position, &v) > 0) {
if (v > max_position)
return -EINVAL;
return -ECHRNG;
info->channels = v;
SPA_FLAG_CLEAR(info->flags, SPA_AUDIO_FLAG_UNPOSITIONED);
}
@ -105,7 +105,7 @@ spa_audio_info_raw_ext_update(struct spa_audio_info_raw *info, size_t size,
if (spa_audio_parse_position_n(val, strlen(val), info->position,
max_position, &v) > 0) {
if (v > max_position)
return -EINVAL;
return -ECHRNG;
info->channels = v;
SPA_FLAG_CLEAR(info->flags, SPA_AUDIO_FLAG_UNPOSITIONED);
}

View file

@ -46,7 +46,7 @@ spa_format_audio_raw_ext_parse(const struct spa_pod *format, struct spa_audio_in
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 -EINVAL;
return -ECHRNG;
if (position == NULL ||
spa_pod_copy_array(position, SPA_TYPE_Id, info->position, max_position) != info->channels) {
SPA_FLAG_SET(info->flags, SPA_AUDIO_FLAG_UNPOSITIONED);

View file

@ -111,15 +111,8 @@ SPA_API_POD_BODY int spa_pod_choice_n_values(uint32_t choice_type, uint32_t *min
SPA_API_POD_BODY int spa_pod_body_from_data(void *data, size_t maxsize, off_t offset, size_t size,
struct spa_pod *pod, const void **body)
{
if (offset < 0)
if (offset < 0 || offset > (int64_t)UINT32_MAX)
return -EINVAL;
/* On 32-bit platforms, off_t is a signed 32-bit type (since it tracks pointer
* width), and consequently can never exceed UINT32_MAX. Skip the upper-bound
* check on 32-bit platforms to avoid a compiler warning. */
#if __SIZEOF_POINTER__ > 4
if (offset > (int64_t)UINT32_MAX)
return -EINVAL;
#endif
if (size < sizeof(struct spa_pod) ||
size > maxsize ||
maxsize - size < (uint32_t)offset)

View file

@ -62,7 +62,6 @@ struct spa_cpu { struct spa_interface iface; };
#define SPA_CPU_FLAG_BMI2 (1<<18) /**< Bit Manipulation Instruction Set 2 */
#define SPA_CPU_FLAG_AVX512 (1<<19) /**< AVX-512 */
#define SPA_CPU_FLAG_SLOW_UNALIGNED (1<<20) /**< unaligned loads/stores are slow */
#define SPA_CPU_FLAG_SLOW_GATHER (1<<21) /**< gather functions are slow */
/* PPC specific */
#define SPA_CPU_FLAG_ALTIVEC (1<<0) /**< standard */

View file

@ -41,7 +41,7 @@ struct itimerspec;
#define SPA_TYPE_INTERFACE_System SPA_TYPE_INFO_INTERFACE_BASE "System"
#define SPA_TYPE_INTERFACE_DataSystem SPA_TYPE_INFO_INTERFACE_BASE "DataSystem"
#define SPA_VERSION_SYSTEM 1
#define SPA_VERSION_SYSTEM 0
struct spa_system { struct spa_interface iface; };
/* IO events */
@ -59,18 +59,11 @@ struct spa_system { struct spa_interface iface; };
struct spa_poll_event {
uint32_t events;
union {
void *data;
uint64_t data_u64;
};
#ifdef __x86_64__
} __attribute__((packed));
#else
};
#endif
struct spa_system_methods {
#define SPA_VERSION_SYSTEM_METHODS 1
#define SPA_VERSION_SYSTEM_METHODS 0
uint32_t version;
/* read/write/ioctl */
@ -158,7 +151,7 @@ SPA_API_SYSTEM int spa_system_pollfd_del(struct spa_system *object, int pfd, int
SPA_API_SYSTEM int spa_system_pollfd_wait(struct spa_system *object, int pfd,
struct spa_poll_event *ev, int n_ev, int timeout)
{
return spa_api_method_fast_r(int, -ENOTSUP, spa_system, &object->iface, pollfd_wait, 1, pfd, ev, n_ev, timeout);
return spa_api_method_fast_r(int, -ENOTSUP, spa_system, &object->iface, pollfd_wait, 0, pfd, ev, n_ev, timeout);
}
SPA_API_SYSTEM int spa_system_timerfd_create(struct spa_system *object, int clockid, int flags)

View file

@ -5,7 +5,7 @@
#ifndef SPA_ENDIAN_H
#define SPA_ENDIAN_H
#if defined(__MidnightBSD__)
#if defined(__FreeBSD__) || defined(__MidnightBSD__)
#include <sys/endian.h>
#define bswap_16 bswap16
#define bswap_32 bswap32

View file

@ -1,445 +0,0 @@
/* Simple Plugin API */
/* SPDX-FileCopyrightText: Copyright © 2026 Wim Taymans */
/* SPDX-License-Identifier: MIT */
#ifndef SPA_UTILS_JSON_BUILDER_H
#define SPA_UTILS_JSON_BUILDER_H
#include <stddef.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <float.h>
#include <inttypes.h>
#include <limits.h>
#include <spa/utils/defs.h>
#include <spa/utils/ansi.h>
#include <spa/utils/json.h>
#ifdef __cplusplus
extern "C" {
#else
#include <stdbool.h>
#endif
#ifndef SPA_API_JSON_BUILDER
#ifdef SPA_API_IMPL
#define SPA_API_JSON_BUILDER SPA_API_IMPL
#else
#define SPA_API_JSON_BUILDER static inline
#endif
#endif
/** \defgroup spa_json_builder JSON builder
* JSON builder functions
*/
/**
* \addtogroup spa_json_builder
* \{
*/
struct spa_json_builder {
FILE *f;
#define SPA_JSON_BUILDER_FLAG_CLOSE (1<<0)
#define SPA_JSON_BUILDER_FLAG_INDENT (1<<1)
#define SPA_JSON_BUILDER_FLAG_SPACE (1<<2)
#define SPA_JSON_BUILDER_FLAG_PRETTY (SPA_JSON_BUILDER_FLAG_INDENT|SPA_JSON_BUILDER_FLAG_SPACE)
#define SPA_JSON_BUILDER_FLAG_COLOR (1<<3)
#define SPA_JSON_BUILDER_FLAG_SIMPLE (1<<4)
#define SPA_JSON_BUILDER_FLAG_RAW (1<<5)
uint32_t flags;
uint32_t indent_off;
uint32_t level;
uint32_t indent;
uint32_t count;
const char *delim;
const char *comma;
const char *key_sep;
#define SPA_JSON_BUILDER_COLOR_NORMAL 0
#define SPA_JSON_BUILDER_COLOR_KEY 1
#define SPA_JSON_BUILDER_COLOR_LITERAL 2
#define SPA_JSON_BUILDER_COLOR_NUMBER 3
#define SPA_JSON_BUILDER_COLOR_STRING 4
#define SPA_JSON_BUILDER_COLOR_CONTAINER 5
const char *color[8];
};
SPA_API_JSON_BUILDER int spa_json_builder_file(struct spa_json_builder *b, FILE *f, uint32_t flags)
{
bool color = flags & SPA_JSON_BUILDER_FLAG_COLOR;
bool simple = flags & SPA_JSON_BUILDER_FLAG_SIMPLE;
bool space = flags & SPA_JSON_BUILDER_FLAG_SPACE;
spa_zero(*b);
b->f = f;
b->flags = flags;
b->indent = 2;
b->delim = "";
b->comma = simple ? space ? "" : " " : ",";
b->key_sep = simple ? space ? " =" : "=" : ":";
b->color[0] = (color ? SPA_ANSI_RESET : "");
b->color[1] = (color ? SPA_ANSI_BRIGHT_BLUE : "");
b->color[2] = (color ? SPA_ANSI_BRIGHT_MAGENTA : "");
b->color[3] = (color ? SPA_ANSI_BRIGHT_CYAN : "");
b->color[4] = (color ? SPA_ANSI_BRIGHT_GREEN : "");
b->color[5] = (color ? SPA_ANSI_BRIGHT_YELLOW : "");
return 0;
}
SPA_API_JSON_BUILDER int spa_json_builder_memstream(struct spa_json_builder *b,
char **mem, size_t *size, uint32_t flags)
{
FILE *f;
spa_zero(*b);
if ((f = open_memstream(mem, size)) == NULL)
return -errno;
return spa_json_builder_file(b, f, flags | SPA_JSON_BUILDER_FLAG_CLOSE);
}
SPA_API_JSON_BUILDER int spa_json_builder_membuf(struct spa_json_builder *b,
char *mem, size_t size, uint32_t flags)
{
FILE *f;
spa_zero(*b);
if ((f = fmemopen(mem, size, "w")) == NULL)
return -errno;
return spa_json_builder_file(b, f, flags | SPA_JSON_BUILDER_FLAG_CLOSE);
}
SPA_API_JSON_BUILDER void spa_json_builder_close(struct spa_json_builder *b)
{
if (b->flags & SPA_JSON_BUILDER_FLAG_CLOSE)
fclose(b->f);
}
SPA_API_JSON_BUILDER int spa_json_builder_encode_string(struct spa_json_builder *b,
bool raw, const char *before, const char *val, int size, const char *after)
{
FILE *f = b->f;
int i, len;
if (raw) {
len = fprintf(f, "%s%.*s%s", before, size, val, after) - 1;
} else {
len = fprintf(f, "%s\"", before);
for (i = 0; i < size && val[i]; i++) {
char v = val[i];
switch (v) {
case '\n': len += fprintf(f, "\\n"); break;
case '\r': len += fprintf(f, "\\r"); break;
case '\b': len += fprintf(f, "\\b"); break;
case '\t': len += fprintf(f, "\\t"); break;
case '\f': len += fprintf(f, "\\f"); break;
case '\\':
case '"': len += fprintf(f, "\\%c", v); break;
default:
if (v > 0 && v < 0x20)
len += fprintf(f, "\\u%04x", v);
else
len += fprintf(f, "%c", v);
break;
}
}
len += fprintf(f, "\"%s", after);
}
return len-1;
}
SPA_API_JSON_BUILDER
void spa_json_builder_add_simple(struct spa_json_builder *b, const char *key, int key_len,
char type, const char *val, int val_len)
{
bool indent = b->indent_off == 0 && (b->flags & SPA_JSON_BUILDER_FLAG_INDENT);
bool space = b->flags & SPA_JSON_BUILDER_FLAG_SPACE;
bool force_raw = b->flags & SPA_JSON_BUILDER_FLAG_RAW;
bool raw = true, simple = b->flags & SPA_JSON_BUILDER_FLAG_SIMPLE;
int color;
if (val == NULL || val_len == 0) {
val = "null";
val_len = 4;
type = 'l';
}
if (type == 0) {
if (spa_json_is_container(val, val_len))
type = simple ? 'C' : 'S';
else if (val_len > 0 && (*val == '}' || *val == ']'))
type = 'e';
else if (spa_json_is_null(val, val_len) ||
spa_json_is_bool(val, val_len))
type = 'l';
else if (spa_json_is_string(val, val_len))
type = 's';
else if (spa_json_is_json_number(val, val_len))
type = 'd';
else if (simple && (spa_json_is_float(val, val_len) ||
spa_json_is_int(val, val_len)))
type = 'd';
else
type = 'S';
}
switch (type) {
case 'e':
b->level -= b->indent;
b->delim = "";
break;
}
fprintf(b->f, "%s%s%*s", b->delim, b->count == 0 ? "" : indent ? "\n" : space ? " " : "",
indent ? b->level : 0, "");
if (key) {
bool key_raw = force_raw || (simple && spa_json_make_simple_string(&key, &key_len)) ||
spa_json_is_string(key, key_len);
spa_json_builder_encode_string(b, key_raw,
b->color[1], key, key_len, b->color[0]);
fprintf(b->f, "%s%s", b->key_sep, space ? " " : "");
}
b->delim = b->comma;
switch (type) {
case 'c':
color = SPA_JSON_BUILDER_COLOR_NORMAL;
val_len = 1;
b->delim = "";
b->level += b->indent;
if (val[1] == '-') b->indent_off++;
break;
case 'e':
color = SPA_JSON_BUILDER_COLOR_NORMAL;
val_len = 1;
if (val[1] == '-') b->indent_off--;
break;
case 'l':
color = SPA_JSON_BUILDER_COLOR_LITERAL;
break;
case 'd':
color = SPA_JSON_BUILDER_COLOR_NUMBER;
break;
case 's':
color = SPA_JSON_BUILDER_COLOR_STRING;
break;
case 'C':
color = SPA_JSON_BUILDER_COLOR_CONTAINER;
break;
default:
color = SPA_JSON_BUILDER_COLOR_STRING;
raw = force_raw || (simple && spa_json_make_simple_string(&val, &val_len));
break;
}
spa_json_builder_encode_string(b, raw, b->color[color], val, val_len, b->color[0]);
b->count++;
}
SPA_API_JSON_BUILDER void spa_json_builder_object_push(struct spa_json_builder *b,
const char *key, const char *val)
{
spa_json_builder_add_simple(b, key, INT_MAX, 'c', val, INT_MAX);
}
SPA_API_JSON_BUILDER void spa_json_builder_pop(struct spa_json_builder *b,
const char *val)
{
spa_json_builder_add_simple(b, NULL, 0, 'e', val, INT_MAX);
}
SPA_API_JSON_BUILDER void spa_json_builder_object_null(struct spa_json_builder *b,
const char *key)
{
spa_json_builder_add_simple(b, key, INT_MAX, 'l', "null", 4);
}
SPA_API_JSON_BUILDER void spa_json_builder_object_bool(struct spa_json_builder *b,
const char *key, bool val)
{
spa_json_builder_add_simple(b, key, INT_MAX, 'l', val ? "true" : "false", INT_MAX);
}
SPA_API_JSON_BUILDER void spa_json_builder_object_int(struct spa_json_builder *b,
const char *key, int64_t val)
{
char str[128];
snprintf(str, sizeof(str), "%" PRIi64, val);
spa_json_builder_add_simple(b, key, INT_MAX, 'd', str, INT_MAX);
}
SPA_API_JSON_BUILDER void spa_json_builder_object_uint(struct spa_json_builder *b,
const char *key, uint64_t val)
{
char str[128];
snprintf(str, sizeof(str), "%" PRIu64, val);
spa_json_builder_add_simple(b, key, INT_MAX, 'd', str, INT_MAX);
}
SPA_API_JSON_BUILDER void spa_json_builder_object_double(struct spa_json_builder *b,
const char *key, double val)
{
char str[64];
spa_json_format_float(str, sizeof(str), (float)val);
spa_json_builder_add_simple(b, key, INT_MAX, 'd', str, INT_MAX);
}
SPA_API_JSON_BUILDER void spa_json_builder_object_string(struct spa_json_builder *b,
const char *key, const char *val)
{
spa_json_builder_add_simple(b, key, INT_MAX, 'S', val, INT_MAX);
}
SPA_API_JSON_BUILDER SPA_PRINTF_FUNC(3,0)
void spa_json_builder_object_stringv(struct spa_json_builder *b,
const char *key, const char *fmt, va_list va)
{
char *val;
if (vasprintf(&val, fmt, va) > 0) {
spa_json_builder_object_string(b, key, val);
free(val);
}
}
SPA_API_JSON_BUILDER SPA_PRINTF_FUNC(3,4)
void spa_json_builder_object_stringf(struct spa_json_builder *b,
const char *key, const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
spa_json_builder_object_stringv(b, key, fmt, va);
va_end(va);
}
SPA_API_JSON_BUILDER void spa_json_builder_object_value_iter(struct spa_json_builder *b,
struct spa_json *it, const char *key, int key_len, const char *val, int len)
{
struct spa_json sub;
if (spa_json_is_array(val, len)) {
spa_json_builder_add_simple(b, key, key_len, 'c', "[", 1);
spa_json_enter(it, &sub);
while ((len = spa_json_next(&sub, &val)) > 0)
spa_json_builder_object_value_iter(b, &sub, NULL, 0, val, len);
spa_json_builder_pop(b, "]");
}
else if (spa_json_is_object(val, len)) {
const char *k;
int kl;
spa_json_builder_add_simple(b, key, key_len, 'c', "{", 1);
spa_json_enter(it, &sub);
while ((kl = spa_json_next(&sub, &k)) > 0) {
if ((len = spa_json_next(&sub, &val)) < 0)
break;
spa_json_builder_object_value_iter(b, &sub, k, kl, val, len);
}
spa_json_builder_pop(b, "}");
}
else {
spa_json_builder_add_simple(b, key, key_len, 0, val, len);
}
}
SPA_API_JSON_BUILDER void spa_json_builder_object_value_full(struct spa_json_builder *b,
bool recurse, const char *key, int key_len, const char *val, int val_len)
{
if (!recurse || val == NULL) {
spa_json_builder_add_simple(b, key, key_len, 0, val, val_len);
} else {
struct spa_json it[1];
const char *v;
if (spa_json_begin(&it[0], val, val_len, &v) >= 0)
spa_json_builder_object_value_iter(b, &it[0], key, key_len, val, val_len);
}
}
SPA_API_JSON_BUILDER void spa_json_builder_object_value(struct spa_json_builder *b,
bool recurse, const char *key, const char *val)
{
spa_json_builder_object_value_full(b, recurse, key, key ? strlen(key) : 0,
val, val ? strlen(val) : 0);
}
SPA_API_JSON_BUILDER SPA_PRINTF_FUNC(4,5)
void spa_json_builder_object_valuef(struct spa_json_builder *b,
bool recurse, const char *key, const char *fmt, ...)
{
va_list va;
char *val;
va_start(va, fmt);
if (vasprintf(&val, fmt, va) > 0) {
spa_json_builder_object_value(b, recurse, key, val);
free(val);
}
va_end(va);
}
/* array functions */
SPA_API_JSON_BUILDER void spa_json_builder_array_push(struct spa_json_builder *b,
const char *val)
{
spa_json_builder_object_push(b, NULL, val);
}
SPA_API_JSON_BUILDER void spa_json_builder_array_null(struct spa_json_builder *b)
{
spa_json_builder_object_null(b, NULL);
}
SPA_API_JSON_BUILDER void spa_json_builder_array_bool(struct spa_json_builder *b,
bool val)
{
spa_json_builder_object_bool(b, NULL, val);
}
SPA_API_JSON_BUILDER void spa_json_builder_array_int(struct spa_json_builder *b,
int64_t val)
{
spa_json_builder_object_int(b, NULL, val);
}
SPA_API_JSON_BUILDER void spa_json_builder_array_uint(struct spa_json_builder *b,
uint64_t val)
{
spa_json_builder_object_uint(b, NULL, val);
}
SPA_API_JSON_BUILDER void spa_json_builder_array_double(struct spa_json_builder *b,
double val)
{
spa_json_builder_object_double(b, NULL, val);
}
SPA_API_JSON_BUILDER void spa_json_builder_array_string(struct spa_json_builder *b,
const char *val)
{
spa_json_builder_object_string(b, NULL, val);
}
SPA_API_JSON_BUILDER SPA_PRINTF_FUNC(2,3)
void spa_json_builder_array_stringf(struct spa_json_builder *b,
const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
spa_json_builder_object_stringv(b, NULL, fmt, va);
va_end(va);
}
SPA_API_JSON_BUILDER void spa_json_builder_array_value(struct spa_json_builder *b,
bool recurse, const char *val)
{
spa_json_builder_object_value(b, recurse, NULL, val);
}
SPA_API_JSON_BUILDER SPA_PRINTF_FUNC(3,4)
void spa_json_builder_array_valuef(struct spa_json_builder *b, bool recurse, const char *fmt, ...)
{
va_list va;
char *val;
va_start(va, fmt);
if (vasprintf(&val, fmt, va) > 0) {
spa_json_builder_object_value(b, recurse, NULL, val);
free(val);
}
va_end(va);
}
SPA_API_JSON_BUILDER char *spa_json_builder_reformat(const char *json, uint32_t flags)
{
struct spa_json_builder b;
char *mem;
size_t size;
int res;
if ((res = spa_json_builder_memstream(&b, &mem, &size, flags)) < 0) {
errno = -res;
return NULL;
}
spa_json_builder_array_value(&b, true, json);
spa_json_builder_close(&b);
return mem;
}
/**
* \}
*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* SPA_UTILS_JSON_BUILDER_H */

View file

@ -232,7 +232,7 @@ SPA_API_JSON int spa_json_next(struct spa_json * iter, const char **value)
switch (cur) {
case '\0':
case '\t': case ' ': case '\r': case '\n':
case '"': case '#': case '{': case '[':
case '"': case '#':
case ':': case ',': case '=': case ']': case '}':
iter->state = __STRUCT | flag;
if (iter->depth > 0)
@ -399,10 +399,6 @@ SPA_API_JSON int spa_json_is_container(const char *val, int len)
{
return len > 0 && (*val == '{' || *val == '[');
}
SPA_API_JSON int spa_json_is_container_end(const char *val, int len)
{
return len > 0 && (*val == '}' || *val == ']');
}
/* object */
SPA_API_JSON int spa_json_is_object(const char *val, int len)
@ -425,11 +421,20 @@ SPA_API_JSON bool spa_json_is_null(const char *val, int len)
/* float */
SPA_API_JSON int spa_json_parse_float(const char *val, int len, float *result)
{
char buf[96], *end;
char buf[96];
char *end;
int pos;
if (len <= 0 || len >= (int)sizeof(buf))
return 0;
for (pos = 0; pos < len; ++pos) {
switch (val[pos]) {
case '+': case '-': case '0' ... '9': case '.': case 'e': case 'E': break;
default: return 0;
}
}
memcpy(buf, val, len);
buf[len] = '\0';
@ -457,7 +462,8 @@ SPA_API_JSON char *spa_json_format_float(char *str, int size, float val)
/* int */
SPA_API_JSON int spa_json_parse_int(const char *val, int len, int *result)
{
char buf[64], *end;
char buf[64];
char *end;
if (len <= 0 || len >= (int)sizeof(buf))
return 0;
@ -474,39 +480,6 @@ SPA_API_JSON bool spa_json_is_int(const char *val, int len)
return spa_json_parse_int(val, len, &dummy);
}
SPA_API_JSON bool spa_json_is_json_number(const char *val, int len)
{
static const int8_t trans[9][7] = {
/* '1-9' '0' '-' '+' '.' 'eE' other */
/* 0 */ {-1, -1, -1, -1, 6, 7, -1 }, /* after '0' */
/* 1 */ { 1, 1, -1, -1, 6, 7, -1 }, /* in integer */
/* 2 */ { 2, 2, -1, -1, -1, 7, -1 }, /* in fraction */
/* 3 */ { 3, 3, -1, -1, -1, -1, -1 }, /* in exponent */
/* 4 */ { 1, 0, 5, -1, -1, -1, -1 }, /* start */
/* 5 */ { 1, 0, -1, -1, -1, -1, -1 }, /* after '-' */
/* 6 */ { 2, 2, -1, -1, -1, -1, -1 }, /* after '.' */
/* 7 */ { 3, 3, 8, 8, -1, -1, -1 }, /* after 'e'/'E' */
/* 8 */ { 3, 3, -1, -1, -1, -1, -1 }, /* after exp sign */
};
static const int8_t char_class[128] = {
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, /* 0-15 */
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, /* 16-31 */
6,6,6,6,6,6,6,6,6,6,6,3,6,2,4,6, /* 32-47: + - . */
1,0,0,0,0,0,0,0,0,0,6,6,6,6,6,6, /* 48-63: 0-9 */
6,6,6,6,6,5,6,6,6,6,6,6,6,6,6,6, /* 64-79: E */
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, /* 80-95 */
6,6,6,6,6,5,6,6,6,6,6,6,6,6,6,6, /* 96-111: e */
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, /* 112-127 */
};
int i, state = 4;
for (i = 0; i < len; i++) {
if ((state = trans[state][char_class[val[i]&0x7f]]) < 0)
return false;
}
return state < 4;
}
/* bool */
SPA_API_JSON bool spa_json_is_true(const char *val, int len)
{
@ -537,46 +510,6 @@ SPA_API_JSON bool spa_json_is_string(const char *val, int len)
{
return len > 1 && *val == '"';
}
SPA_API_JSON bool spa_json_is_simple_string(const char *val, int size)
{
int i;
static const char *REJECT = "\"\\'=:,{}[]()#";
for (i = 0; i < size && val[i]; i++) {
if (val[i] <= 0x20 || strchr(REJECT, val[i]) != NULL)
return false;
}
return true;
}
SPA_API_JSON bool spa_json_make_simple_string(const char **val, int *len)
{
int i, l = *len;
const char *v = *val;
static const char *REJECT = "\"\\'=:,{}[]()#";
int trimmed = 0, bad = 0;
for (i = 0; i < l && v[i]; i++) {
if (i == 0 && v[0] == '\"')
trimmed++;
else if ((i+1 == l || !v[i+1]) && v[i] == '\"')
trimmed++;
else if (v[i] <= 0x20 || strchr(REJECT, v[i]) != NULL)
bad++;
}
if (trimmed == 0 && bad == 0 && i > 0)
return true;
else if (trimmed == 2) {
if (bad == 0 && i > 2 &&
!spa_json_is_null(&v[1], i-2) &&
!spa_json_is_bool(&v[1], i-2) &&
!spa_json_is_float(&v[1], i-2) &&
!spa_json_is_container(&v[1], i-2) &&
!spa_json_is_container_end(&v[1], i-2)) {
(*len) = i-2;
(*val)++;
}
return true;
}
return false;
}
SPA_API_JSON int spa_json_parse_hex(const char *p, int num, uint32_t *res)
{

View file

@ -380,26 +380,17 @@ SPA_API_STRING void spa_strbuf_init(struct spa_strbuf *buf, char *buffer, size_t
buf->buffer[0] = '\0';
}
SPA_PRINTF_FUNC(2, 0)
SPA_API_STRING int spa_strbuf_appendv(struct spa_strbuf *buf, const char *fmt, va_list args)
{
size_t remain = buf->maxsize - buf->pos;
int written = vsnprintf(&buf->buffer[buf->pos], remain, fmt, args);
if (written > 0)
buf->pos += SPA_MIN(remain, (size_t)written);
return written;
}
SPA_PRINTF_FUNC(2, 3)
SPA_API_STRING int spa_strbuf_append(struct spa_strbuf *buf, const char *fmt, ...)
{
size_t remain = buf->maxsize - buf->pos;
ssize_t written;
va_list args;
int written;
va_start(args, fmt);
written = spa_strbuf_appendv(buf, fmt, args);
written = vsnprintf(&buf->buffer[buf->pos], remain, fmt, args);
va_end(args);
if (written > 0)
buf->pos += SPA_MIN(remain, (size_t)written);
return written;
}

View file

@ -2,6 +2,7 @@
#undef SPA_AUDIO_MAX_CHANNELS
#define SPA_API_IMPL SPA_EXPORT
#include <spa/utils/defs.h>
#include <spa/buffer/alloc.h>
#include <spa/buffer/buffer.h>
#include <spa/buffer/type-info.h>
@ -125,17 +126,16 @@
#include <spa/param/video/raw-types.h>
#include <spa/param/video/raw-utils.h>
#include <spa/param/video/type-info.h>
#include <spa/pod/body.h>
#include <spa/pod/builder.h>
#include <spa/pod/command.h>
#include <spa/pod/compare.h>
#include <spa/pod/dynamic.h>
#include <spa/pod/event.h>
#include <spa/pod/filter.h>
#include <spa/pod/body.h>
#include <spa/pod/iter.h>
#include <spa/pod/parser.h>
#include <spa/pod/pod.h>
#include <spa/pod/simplify.h>
#include <spa/pod/vararg.h>
#include <spa/support/cpu.h>
#include <spa/support/dbus.h>
@ -158,7 +158,6 @@
#include <spa/utils/hook.h>
#include <spa/utils/json-core.h>
#include <spa/utils/json.h>
#include <spa/utils/json-builder.h>
#include <spa/utils/json-pod.h>
#include <spa/utils/keys.h>
#include <spa/utils/list.h>

View file

@ -39,7 +39,7 @@ struct impl_data {
std::unique_ptr<float *[]> play_buffer, rec_buffer, out_buffer;
};
SPA_LOG_TOPIC_DEFINE_STATIC(log_topic, "spa.aec.webrtc");
SPA_LOG_TOPIC_DEFINE_STATIC(log_topic, "spa.eac.webrtc");
#undef SPA_LOG_TOPIC_DEFAULT
#define SPA_LOG_TOPIC_DEFAULT &log_topic
@ -221,11 +221,6 @@ static int webrtc_init2(void *object, const struct spa_dict *args,
}};
#endif
if (out_info->channels != 1 && rec_info->channels != out_info->channels) {
spa_log_error(impl->log, "Source channels must be equal to capture channels or 1");
return -EINVAL;
}
#if defined(HAVE_WEBRTC)
auto apm = std::unique_ptr<webrtc::AudioProcessing>(webrtc::AudioProcessing::Create(config));
#elif defined(HAVE_WEBRTC1)

View file

@ -187,11 +187,6 @@ ATTRS{idVendor}=="1395", ATTRS{idProduct}=="0300", ENV{ACP_PROFILE_SET}="usb-gam
# Sennheiser GSP 670 USB headset
ATTRS{idVendor}=="1395", ATTRS{idProduct}=="008a", ENV{ACP_PROFILE_SET}="usb-gaming-headset.conf"
# JBL Quantum One
ATTRS{idVendor}=="0ecb", ATTRS{idProduct}=="203a", ENV{ACP_PROFILE_SET}="usb-gaming-headset-gamefirst.conf"
# JBL Quantum 810 Wireless
ATTRS{idVendor}=="0ecb", ATTRS{idProduct}=="2069", ENV{ACP_PROFILE_SET}="usb-gaming-headset-gamefirst.conf"
# Audioengine HD3 powered speakers support IEC958 but don't actually
# have any digital outputs.
ATTRS{idVendor}=="0a12", ATTRS{idProduct}=="4007", ENV{ACP_PROFILE_SET}="analog-only.conf"

View file

@ -10,9 +10,7 @@
#include <time.h>
#include <stdbool.h>
#include <getopt.h>
#ifdef __linux__
#include <alloca.h>
#endif
#include <spa/debug/context.h>
#include <spa/utils/string.h>

View file

@ -485,11 +485,13 @@ static int add_pro_profile(pa_card *impl, uint32_t index)
if ((n_capture == 1 && n_playback == 1) || is_firewire) {
PA_IDXSET_FOREACH(m, ap->output_mappings, idx) {
pa_proplist_setf(m->output_proplist, "node.group", "pro-audio-%u", index);
pa_proplist_setf(m->output_proplist, "node.link-group", "pro-audio-%u", index);
pa_proplist_setf(m->output_proplist, "api.alsa.auto-link", "true");
pa_proplist_setf(m->output_proplist, "api.alsa.disable-tsched", "true");
}
PA_IDXSET_FOREACH(m, ap->input_mappings, idx) {
pa_proplist_setf(m->input_proplist, "node.group", "pro-audio-%u", index);
pa_proplist_setf(m->input_proplist, "node.link-group", "pro-audio-%u", index);
pa_proplist_setf(m->input_proplist, "api.alsa.auto-link", "true");
pa_proplist_setf(m->input_proplist, "api.alsa.disable-tsched", "true");
}

View file

@ -429,14 +429,14 @@ static PA_PRINTF_FUNC(1,0) inline char *pa_vsprintf_malloc(const char *fmt, va_l
#define pa_fopen_cloexec(f,m) fopen(f,m"e")
static inline const char *pa_path_get_filename(const char *p)
static inline char *pa_path_get_filename(const char *p)
{
const char *fn;
char *fn;
if (!p)
return NULL;
if ((fn = strrchr(p, PA_PATH_SEP_CHAR)))
return fn+1;
return p;
return (char*) p;
}
static inline bool pa_is_path_absolute(const char *fn)

View file

@ -3040,17 +3040,10 @@ static int update_time(struct state *state, uint64_t current_time, snd_pcm_sfram
}
if (state->rate_match) {
/* Only set rate_match rate when matching is active. When not matching,
* set it to 1.0 to indicate no rate adjustment needed, even though DLL
* may still be running for buffer level management. */
if (state->matching) {
if (state->stream == SND_PCM_STREAM_PLAYBACK)
state->rate_match->rate = corr;
else
state->rate_match->rate = 1.0/corr;
} else {
state->rate_match->rate = 1.0;
}
if (state->pitch_elem && state->matching)
spa_alsa_update_rate_match(state);

View file

@ -227,7 +227,7 @@ static void emit_port_info(struct seq_state *this, struct seq_port *port, bool f
if (full)
port->info.change_mask = port->info_all;
if (port->info.change_mask) {
struct spa_dict_item items[7];
struct spa_dict_item items[6];
uint32_t n_items = 0;
int card_id;
snd_seq_port_info_t *info;
@ -284,9 +284,6 @@ static void emit_port_info(struct seq_state *this, struct seq_port *port, bool f
snprintf(card, sizeof(card), "%d", card_id);
items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_API_ALSA_CARD, card);
}
if (this->ump)
items[n_items++] = SPA_DICT_ITEM_INIT("control.ump", "true");
port->info.props = &SPA_DICT_INIT(items, n_items);
spa_node_emit_port_info(&this->hooks,
@ -504,7 +501,6 @@ impl_node_port_enum_params(void *object, int seq,
struct seq_state *this = object;
struct seq_port *port;
struct spa_pod *param;
struct spa_pod_frame f[1];
struct spa_pod_builder b = { 0 };
uint8_t buffer[1024];
struct spa_result_node_params result;
@ -528,18 +524,10 @@ impl_node_port_enum_params(void *object, int seq,
case SPA_PARAM_EnumFormat:
if (result.index > 0)
return 0;
spa_pod_builder_push_object(&b, &f[0],
SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat);
spa_pod_builder_add(&b,
param = spa_pod_builder_add_object(&b,
SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_application),
SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_control),
0);
if (port->control_types != 0) {
spa_pod_builder_add(&b,
SPA_FORMAT_CONTROL_types, SPA_POD_Int(port->control_types),
0);
}
param = spa_pod_builder_pop(&b, &f[0]);
SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_control));
break;
case SPA_PARAM_Format:
@ -547,18 +535,10 @@ impl_node_port_enum_params(void *object, int seq,
return -EIO;
if (result.index > 0)
return 0;
spa_pod_builder_push_object(&b, &f[0],
SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat);
spa_pod_builder_add(&b,
param = spa_pod_builder_add_object(&b,
SPA_TYPE_OBJECT_Format, SPA_PARAM_Format,
SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_application),
SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_control),
0);
if (port->control_types != 0) {
spa_pod_builder_add(&b,
SPA_FORMAT_CONTROL_types, SPA_POD_Int(port->control_types),
0);
}
param = spa_pod_builder_pop(&b, &f[0]);
SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_control));
break;
case SPA_PARAM_Buffers:
@ -975,7 +955,7 @@ impl_init(const struct spa_handle_factory *factory,
this->quantum_limit = 8192;
this->min_pool_size = 500;
this->max_pool_size = 2000;
this->ump = false;
this->ump = true;
for (i = 0; info && i < info->n_items; i++) {
const char *k = info->items[i].key;

View file

@ -620,8 +620,9 @@ static int process_read(struct seq_state *state)
{
struct seq_stream *stream = &state->streams[SPA_DIRECTION_OUTPUT];
const bool ump = state->ump;
void *data;
uint32_t *data;
uint8_t midi1_data[MAX_EVENT_SIZE];
uint32_t ump_data[MAX_EVENT_SIZE];
long size;
int res = -1;
struct seq_port *port;
@ -632,6 +633,9 @@ static int process_read(struct seq_state *state)
uint64_t ev_time, diff;
uint32_t offset;
void *event;
uint8_t *midi1_ptr;
size_t midi1_size = 0;
uint64_t ump_state = 0;
snd_seq_event_type_t SPA_UNUSED type;
if (ump) {
@ -698,7 +702,7 @@ static int process_read(struct seq_state *state)
#ifdef HAVE_ALSA_UMP
snd_seq_ump_event_t *ev = event;
data = &ev->ump[0];
data = (uint32_t*)&ev->ump[0];
size = spa_ump_message_size(snd_ump_msg_hdr_type(ev->ump[0])) * 4;
#else
spa_assert_not_reached();
@ -711,13 +715,24 @@ static int process_read(struct seq_state *state)
spa_log_warn(state->log, "decode failed: %s", snd_strerror(size));
continue;
}
data = midi1_data;
midi1_ptr = midi1_data;
midi1_size = size;
}
do {
if (!ump) {
data = ump_data;
size = spa_ump_from_midi(&midi1_ptr, &midi1_size,
ump_data, sizeof(ump_data), 0, &ump_state);
if (size <= 0)
break;
}
spa_log_trace_fp(state->log, "event %d time:%"PRIu64" offset:%d size:%ld port:%d.%d",
type, ev_time, offset, size, addr->client, addr->port);
spa_pod_builder_control(&port->builder, offset, ump ? SPA_CONTROL_UMP : SPA_CONTROL_Midi );
spa_pod_builder_control(&port->builder, offset, SPA_CONTROL_UMP);
spa_pod_builder_bytes(&port->builder, data, size);
/* make sure we can fit at least one control event of max size otherwise
@ -726,6 +741,8 @@ static int process_read(struct seq_state *state)
sizeof(struct spa_pod_control) +
MAX_EVENT_SIZE > port->buffer->buf->datas[0].maxsize)
goto done;
} while (!ump);
}
done:
@ -802,6 +819,7 @@ static int process_write(struct seq_state *state)
const void *c_body;
uint64_t out_time;
snd_seq_real_time_t out_rt;
bool first = true;
if (io->status != SPA_STATUS_HAVE_DATA ||
io->buffer_id >= port->n_buffers)
@ -826,6 +844,9 @@ static int process_write(struct seq_state *state)
size_t body_size;
uint8_t *body;
if (c.type != SPA_CONTROL_UMP)
continue;
body = (uint8_t*)c_body;
body_size = c.value.size;
@ -840,9 +861,6 @@ static int process_write(struct seq_state *state)
#ifdef HAVE_ALSA_UMP
snd_seq_ump_event_t ev;
if (c.type != SPA_CONTROL_UMP)
continue;
snd_seq_ump_ev_clear(&ev);
snd_seq_ev_set_ump_data(&ev, body, SPA_MIN(sizeof(ev.ump), (size_t)body_size));
snd_seq_ev_set_source(&ev, state->event.addr.port);
@ -860,26 +878,26 @@ static int process_write(struct seq_state *state)
#endif
} else {
snd_seq_event_t ev;
int size = 0;
long s;
if (c.type != SPA_CONTROL_Midi)
continue;
uint8_t data[MAX_EVENT_SIZE];
int size;
uint64_t st = 0;
while (body_size > 0) {
if (size == 0)
if ((size = spa_ump_to_midi((const uint32_t **)&body, &body_size,
data, sizeof(data), &st)) <= 0)
break;
if (first)
snd_seq_ev_clear(&ev);
if ((s = snd_midi_event_encode(stream->codec, body, body_size, &ev)) < 0) {
if ((size = snd_midi_event_encode(stream->codec, data, size, &ev)) < 0) {
spa_log_warn(state->log, "failed to encode event: %s",
snd_strerror(size));
snd_midi_event_reset_encode(stream->codec);
size = 0;
first = true;
continue;
}
body += s;
body_size -= s;
size += s;
first = false;
if (ev.type == SND_SEQ_EVENT_NONE)
/* this can happen when the event is not complete yet, like
* a sysex message and we need to encode some more data. */
@ -895,7 +913,7 @@ static int process_write(struct seq_state *state)
spa_log_warn(state->log, "failed to output event: %s",
snd_strerror(err));
}
size = 0;
first = true;
}
}
}

View file

@ -82,8 +82,6 @@ struct seq_port {
struct spa_pod_builder builder;
struct spa_pod_frame frame;
uint32_t control_types;
struct spa_audio_info current_format;
unsigned int have_format:1;
unsigned int active:1;

View file

@ -48,7 +48,6 @@ struct card {
unsigned int accessible:1;
unsigned int ignored:1;
unsigned int emitted:1;
unsigned int wireless_disconnected:1;
/* Local SPA object IDs. (Global IDs are produced by PipeWire
* out of this using its registry.) Compress-Offload or PCM
@ -60,10 +59,6 @@ struct card {
* is used because 0 is a valid ALSA card number. */
uint32_t pcm_device_id;
uint32_t compress_offload_device_id;
/* Syspath of the USB interface that has wireless_status (e.g.
* /sys/devices/.../1-5:1.3). Empty string when not applicable. */
char wireless_status_syspath[256];
};
static uint32_t calc_pcm_device_id(struct card *card)
@ -97,8 +92,6 @@ struct impl {
struct spa_source source;
struct spa_source notify;
struct udev_monitor *usb_umonitor;
struct spa_source usb_source;
unsigned int use_acp:1;
unsigned int expose_busy:1;
int use_ucm;
@ -360,87 +353,6 @@ static int check_udev_environment(struct udev *udev, const char *devname)
return ret;
}
static void check_wireless_status(struct impl *this, struct card *card)
{
char path[PATH_MAX];
char buf[32];
size_t sz;
bool was_disconnected;
if (card->wireless_status_syspath[0] == '\0')
return;
was_disconnected = card->wireless_disconnected;
spa_scnprintf(path, sizeof(path), "%s/wireless_status", card->wireless_status_syspath);
spa_autoptr(FILE) f = fopen(path, "re");
if (f == NULL)
return;
sz = fread(buf, 1, sizeof(buf) - 1, f);
buf[sz] = '\0';
card->wireless_disconnected = spa_strstartswith(buf, "disconnected");
if (card->wireless_disconnected != was_disconnected)
spa_log_info(this->log, "card %u: wireless headset %s",
card->card_nr,
card->wireless_disconnected ? "disconnected" : "connected");
}
static void find_wireless_status(struct impl *this, struct card *card)
{
const char *bus, *parent_syspath, *parent_sysname;
struct udev_device *parent;
struct dirent *entry;
char path[PATH_MAX];
size_t sysname_len;
bus = udev_device_get_property_value(card->udev_device, "ID_BUS");
if (!spa_streq(bus, "usb"))
return;
/* udev_device_get_parent_* returns a borrowed reference owned by the child; do not unref it. */
parent = udev_device_get_parent_with_subsystem_devtype(card->udev_device, "usb", "usb_device");
if (parent == NULL)
return;
parent_syspath = udev_device_get_syspath(parent);
parent_sysname = udev_device_get_sysname(parent);
if (parent_syspath == NULL || parent_sysname == NULL)
return;
sysname_len = strlen(parent_sysname);
spa_autoptr(DIR) dir = opendir(parent_syspath);
if (dir == NULL)
return;
while ((entry = readdir(dir)) != NULL) {
/* USB interface directories are named "<sysname>:<config>.<intf>" */
if (strncmp(entry->d_name, parent_sysname, sysname_len) != 0 ||
entry->d_name[sysname_len] != ':')
continue;
spa_scnprintf(path, sizeof(path), "%s/%s/wireless_status",
parent_syspath, entry->d_name);
if (access(path, R_OK) < 0)
continue;
spa_scnprintf(card->wireless_status_syspath,
sizeof(card->wireless_status_syspath),
"%s/%s", parent_syspath, entry->d_name);
check_wireless_status(this, card);
spa_log_debug(this->log, "card %u: found wireless_status at %s (%s)",
card->card_nr, card->wireless_status_syspath,
card->wireless_disconnected ? "disconnected" : "connected");
return;
}
}
static int check_pcm_device_availability(struct impl *this, struct card *card,
int *num_pcm_devices)
{
@ -626,9 +538,6 @@ static int emit_added_object_info(struct impl *this, struct card *card)
if ((str = udev_device_get_property_value(udev_device, "ACP_PROFILE_SET")) && *str)
items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_PROFILE_SET, str);
if ((str = udev_device_get_property_value(udev_device, "ACP_IGNORE_DB")) && *str)
items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_API_ALSA_IGNORE_DB, str);
if ((str = udev_device_get_property_value(udev_device, "SOUND_CLASS")) && *str)
items[n_items++] = SPA_DICT_ITEM_INIT(SPA_KEY_DEVICE_CLASS, str);
@ -816,17 +725,13 @@ static bool check_access(struct impl *this, struct card *card)
static void process_card(struct impl *this, enum action action, struct card *card)
{
switch (action) {
case ACTION_CHANGE: {
if (card->ignored)
return;
switch (action) {
case ACTION_CHANGE: {
check_access(this, card);
check_wireless_status(this, card);
bool effective_accessible = card->accessible && !card->wireless_disconnected;
if (effective_accessible && !card->emitted) {
if (card->accessible && !card->emitted) {
int res = emit_added_object_info(this, card);
if (res < 0) {
if (card->ignored)
@ -845,7 +750,7 @@ static void process_card(struct impl *this, enum action action, struct card *car
card->card_nr);
card->unavailable = false;
}
} else if (!effective_accessible && card->emitted) {
} else if (!card->accessible && card->emitted) {
card->emitted = false;
if (card->pcm_device_id != ID_DEVICE_NOT_SUPPORTED)
@ -882,11 +787,8 @@ static void process_udev_device(struct impl *this, enum action action, struct ud
return;
card = find_card(this, card_nr);
if (action == ACTION_CHANGE && !card) {
if (action == ACTION_CHANGE && !card)
card = add_card(this, card_nr, udev_device);
if (card)
find_wireless_status(this, card);
}
if (!card)
return;
@ -1013,41 +915,6 @@ static void impl_on_fd_events(struct spa_source *source)
udev_device_unref(udev_device);
}
static void impl_on_usb_events(struct spa_source *source)
{
struct impl *this = source->data;
struct udev_device *udev_device;
const char *action, *syspath;
unsigned int i;
udev_device = udev_monitor_receive_device(this->usb_umonitor);
if (udev_device == NULL)
return;
if ((action = udev_device_get_action(udev_device)) == NULL)
action = "change";
if (!spa_streq(action, "change"))
goto done;
syspath = udev_device_get_syspath(udev_device);
if (syspath == NULL)
goto done;
for (i = 0; i < this->n_cards; i++) {
struct card *card = &this->cards[i];
if (card->wireless_status_syspath[0] == '\0')
continue;
if (!spa_streq(card->wireless_status_syspath, syspath))
continue;
spa_log_debug(this->log, "wireless_status change for card %u", card->card_nr);
process_card(this, ACTION_CHANGE, card);
}
done:
udev_device_unref(udev_device);
}
static int start_monitor(struct impl *this)
{
int res;
@ -1071,20 +938,6 @@ static int start_monitor(struct impl *this)
spa_log_debug(this->log, "monitor %p", this->umonitor);
spa_loop_add_source(this->main_loop, &this->source);
this->usb_umonitor = udev_monitor_new_from_netlink(this->udev, "udev");
if (this->usb_umonitor != NULL) {
udev_monitor_filter_add_match_subsystem_devtype(this->usb_umonitor,
"usb", "usb_interface");
udev_monitor_enable_receiving(this->usb_umonitor);
this->usb_source.func = impl_on_usb_events;
this->usb_source.data = this;
this->usb_source.fd = udev_monitor_get_fd(this->usb_umonitor);
this->usb_source.mask = SPA_IO_IN | SPA_IO_ERR;
spa_loop_add_source(this->main_loop, &this->usb_source);
}
if ((res = start_inotify(this)) < 0)
return res;
@ -1102,12 +955,6 @@ static int stop_monitor(struct impl *this)
udev_monitor_unref(this->umonitor);
this->umonitor = NULL;
if (this->usb_umonitor != NULL) {
spa_loop_remove_source(this->main_loop, &this->usb_source);
udev_monitor_unref(this->usb_umonitor);
this->usb_umonitor = NULL;
}
stop_inotify(this);
return 0;

View file

@ -1,70 +0,0 @@
# This file is part of PulseAudio.
#
# PulseAudio is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# PulseAudio is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
; USB gaming headset.
; These headsets usually have two output devices. The first one is meant
; for general audio, and the second one is meant for chat. There is also
; a single input device for chat.
; The purpose of this unusual design is to provide separate volume
; controls for voice and other audio, which can be useful in gaming.
;
; Works with:
; JBL Quantum 810 Wireless
; JBL Quantum One
;
; Based on usb-gaming-headset.conf.
;
; See default.conf for an explanation on the directives used here.
[General]
auto-profiles = yes
[Mapping mono-chat-output]
description-key = gaming-headset-chat
device-strings = hw:%f,1,0
channel-map = mono
paths-output = usb-gaming-headset-output-mono
intended-roles = phone
[Mapping stereo-chat-output]
description-key = gaming-headset-chat
device-strings = hw:%f,1,0
channel-map = left,right
paths-output = usb-gaming-headset-output-stereo
intended-roles = phone
[Mapping mono-chat-input]
description-key = gaming-headset-chat
device-strings = hw:%f,0,0
channel-map = mono
paths-input = usb-gaming-headset-input
intended-roles = phone
[Mapping stereo-game-output]
description-key = gaming-headset-game
device-strings = hw:%f,0,0
channel-map = left,right
paths-output = usb-gaming-headset-output-stereo
direction = output
[Profile output:mono-chat+output:stereo-game+input:mono-chat]
output-mappings = mono-chat-output stereo-game-output
input-mappings = mono-chat-input
priority = 5100
[Profile output:stereo-game+output:stereo-chat+input:mono-chat]
output-mappings = stereo-game-output stereo-chat-output
input-mappings = mono-chat-input
priority = 5100

View file

@ -16,7 +16,6 @@
#include <spa/utils/result.h>
#include <spa/utils/list.h>
#include <spa/utils/json.h>
#include <spa/utils/json-builder.h>
#include <spa/utils/names.h>
#include <spa/utils/string.h>
#include <spa/utils/ratelimit.h>
@ -269,7 +268,6 @@ struct impl {
struct spa_list active_graphs;
struct filter_graph graphs[MAX_GRAPH];
struct spa_process_latency_info latency;
char *graph_descs[MAX_GRAPH];
int in_filter_props;
int filter_props_count;
@ -724,34 +722,6 @@ static int node_param_prop_info(struct impl *this, uint32_t id, uint32_t index,
SPA_PROP_INFO_params, SPA_POD_Bool(true));
break;
case 19:
*param = spa_pod_builder_add_object(b,
SPA_TYPE_OBJECT_PropInfo, id,
SPA_PROP_INFO_name, SPA_POD_String("channelmix.center-level"),
SPA_PROP_INFO_description, SPA_POD_String("Center up/downmix level"),
SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(
this->mix.center_level, 0.0, 10.0),
SPA_PROP_INFO_params, SPA_POD_Bool(true));
break;
case 20:
*param = spa_pod_builder_add_object(b,
SPA_TYPE_OBJECT_PropInfo, id,
SPA_PROP_INFO_name, SPA_POD_String("channelmix.surround-level"),
SPA_PROP_INFO_description, SPA_POD_String("Surround up/downmix level"),
SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(
this->mix.surround_level, 0.0, 10.0),
SPA_PROP_INFO_params, SPA_POD_Bool(true));
break;
case 21:
*param = spa_pod_builder_add_object(b,
SPA_TYPE_OBJECT_PropInfo, id,
SPA_PROP_INFO_name, SPA_POD_String("channelmix.lfe-level"),
SPA_PROP_INFO_description, SPA_POD_String("LFE up/downmix level"),
SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(
this->mix.lfe_level, 0.0, 10.0),
SPA_PROP_INFO_params, SPA_POD_Bool(true));
break;
case 22:
*param = spa_pod_builder_add_object(b,
SPA_TYPE_OBJECT_PropInfo, id,
SPA_PROP_INFO_name, SPA_POD_String("channelmix.hilbert-taps"),
@ -760,7 +730,7 @@ static int node_param_prop_info(struct impl *this, uint32_t id, uint32_t index,
this->mix.hilbert_taps, 0, MAX_TAPS),
SPA_PROP_INFO_params, SPA_POD_Bool(true));
break;
case 23:
case 20:
spa_pod_builder_push_object(b, &f[0], SPA_TYPE_OBJECT_PropInfo, id);
spa_pod_builder_add(b,
SPA_PROP_INFO_name, SPA_POD_String("channelmix.upmix-method"),
@ -779,14 +749,14 @@ static int node_param_prop_info(struct impl *this, uint32_t id, uint32_t index,
spa_pod_builder_pop(b, &f[1]);
*param = spa_pod_builder_pop(b, &f[0]);
break;
case 24:
case 21:
*param = spa_pod_builder_add_object(b,
SPA_TYPE_OBJECT_PropInfo, id,
SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_rate),
SPA_PROP_INFO_description, SPA_POD_String("Rate scaler"),
SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Double(p->rate, 0.0, 10.0));
break;
case 25:
case 22:
*param = spa_pod_builder_add_object(b,
SPA_TYPE_OBJECT_PropInfo, id,
SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_quality),
@ -795,7 +765,7 @@ static int node_param_prop_info(struct impl *this, uint32_t id, uint32_t index,
SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int(p->resample_quality, 0, 14),
SPA_PROP_INFO_params, SPA_POD_Bool(true));
break;
case 26:
case 23:
*param = spa_pod_builder_add_object(b,
SPA_TYPE_OBJECT_PropInfo, id,
SPA_PROP_INFO_name, SPA_POD_String("resample.disable"),
@ -803,7 +773,7 @@ static int node_param_prop_info(struct impl *this, uint32_t id, uint32_t index,
SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(p->resample_disabled),
SPA_PROP_INFO_params, SPA_POD_Bool(true));
break;
case 27:
case 24:
*param = spa_pod_builder_add_object(b,
SPA_TYPE_OBJECT_PropInfo, id,
SPA_PROP_INFO_name, SPA_POD_String("dither.noise"),
@ -811,7 +781,7 @@ static int node_param_prop_info(struct impl *this, uint32_t id, uint32_t index,
SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Int(this->dir[1].conv.noise_bits, 0, 16),
SPA_PROP_INFO_params, SPA_POD_Bool(true));
break;
case 28:
case 25:
spa_pod_builder_push_object(b, &f[0], SPA_TYPE_OBJECT_PropInfo, id);
spa_pod_builder_add(b,
SPA_PROP_INFO_name, SPA_POD_String("dither.method"),
@ -829,7 +799,7 @@ static int node_param_prop_info(struct impl *this, uint32_t id, uint32_t index,
spa_pod_builder_pop(b, &f[1]);
*param = spa_pod_builder_pop(b, &f[0]);
break;
case 29:
case 26:
*param = spa_pod_builder_add_object(b,
SPA_TYPE_OBJECT_PropInfo, id,
SPA_PROP_INFO_name, SPA_POD_String("debug.wav-path"),
@ -837,7 +807,7 @@ static int node_param_prop_info(struct impl *this, uint32_t id, uint32_t index,
SPA_PROP_INFO_type, SPA_POD_String(p->wav_path),
SPA_PROP_INFO_params, SPA_POD_Bool(true));
break;
case 30:
case 27:
*param = spa_pod_builder_add_object(b,
SPA_TYPE_OBJECT_PropInfo, id,
SPA_PROP_INFO_name, SPA_POD_String("channelmix.lock-volumes"),
@ -845,7 +815,7 @@ static int node_param_prop_info(struct impl *this, uint32_t id, uint32_t index,
SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(p->lock_volumes),
SPA_PROP_INFO_params, SPA_POD_Bool(true));
break;
case 31:
case 28:
*param = spa_pod_builder_add_object(b,
SPA_TYPE_OBJECT_PropInfo, id,
SPA_PROP_INFO_name, SPA_POD_String("audioconvert.filter-graph.disable"),
@ -853,7 +823,7 @@ static int node_param_prop_info(struct impl *this, uint32_t id, uint32_t index,
SPA_PROP_INFO_type, SPA_POD_CHOICE_Bool(p->filter_graph_disabled),
SPA_PROP_INFO_params, SPA_POD_Bool(true));
break;
case 32:
case 29:
*param = spa_pod_builder_add_object(b,
SPA_TYPE_OBJECT_PropInfo, id,
SPA_PROP_INFO_name, SPA_POD_String("audioconvert.filter-graph.N"),
@ -864,7 +834,7 @@ static int node_param_prop_info(struct impl *this, uint32_t id, uint32_t index,
default:
if (this->filter_graph[0] && this->filter_graph[0]->graph) {
return spa_filter_graph_enum_prop_info(this->filter_graph[0]->graph,
index - 33, b, param);
index - 30, b, param);
}
return 0;
}
@ -876,7 +846,6 @@ static int node_param_props(struct impl *this, uint32_t id, uint32_t index,
{
struct props *p = &this->props;
struct spa_pod_frame f[2];
struct filter_graph *g;
switch (index) {
case 0:
@ -931,12 +900,6 @@ static int node_param_props(struct impl *this, uint32_t id, uint32_t index,
spa_pod_builder_float(b, this->mix.rear_delay);
spa_pod_builder_string(b, "channelmix.stereo-widen");
spa_pod_builder_float(b, this->mix.widen);
spa_pod_builder_string(b, "channelmix.center-level");
spa_pod_builder_float(b, this->mix.center_level);
spa_pod_builder_string(b, "channelmix.surround-level");
spa_pod_builder_float(b, this->mix.surround_level);
spa_pod_builder_string(b, "channelmix.lfe-level");
spa_pod_builder_float(b, this->mix.lfe_level);
spa_pod_builder_string(b, "channelmix.hilbert-taps");
spa_pod_builder_int(b, this->mix.hilbert_taps);
spa_pod_builder_string(b, "channelmix.upmix-method");
@ -955,12 +918,8 @@ static int node_param_props(struct impl *this, uint32_t id, uint32_t index,
spa_pod_builder_bool(b, p->lock_volumes);
spa_pod_builder_string(b, "audioconvert.filter-graph.disable");
spa_pod_builder_bool(b, p->filter_graph_disabled);
spa_list_for_each(g, &this->active_graphs, link) {
char key[64];
snprintf(key, sizeof(key), "audioconvert.filter-graph.%d", g->order);
spa_pod_builder_string(b, key);
spa_pod_builder_string(b, this->graph_descs[g->order]);
}
spa_pod_builder_string(b, "audioconvert.filter-graph");
spa_pod_builder_string(b, "");
spa_pod_builder_pop(b, &f[1]);
*param = spa_pod_builder_pop(b, &f[0]);
break;
@ -994,7 +953,7 @@ static int impl_node_enum_params(void *object, int seq,
struct impl *this = object;
struct spa_pod *param;
struct spa_pod_builder b = { 0 };
uint8_t buffer[16384];
uint8_t buffer[4096];
struct spa_result_node_params result;
uint32_t count = 0;
int res = 0;
@ -1450,7 +1409,6 @@ static int load_filter_graph(struct impl *impl, const char *graph, int order)
g->removing = true;
spa_log_info(impl->log, "removing filter-graph order:%d", order);
}
free(impl->graph_descs[order]);
}
if (graph != NULL && graph[0] != '\0') {
@ -1476,8 +1434,6 @@ static int load_filter_graph(struct impl *impl, const char *graph, int order)
spa_list_remove(&pending->link);
insert_graph(&impl->active_graphs, pending);
impl->graph_descs[order] = spa_json_builder_reformat(graph, 0);
spa_log_info(impl->log, "loading filter-graph order:%d", order);
}
if (impl->setup)
@ -1524,12 +1480,6 @@ static int audioconvert_set_param(struct impl *this, const char *k, const char *
spa_atof(s, &this->mix.rear_delay);
else if (spa_streq(k, "channelmix.stereo-widen"))
spa_atof(s, &this->mix.widen);
else if (spa_streq(k, "channelmix.center-level"))
spa_atof(s, &this->mix.center_level);
else if (spa_streq(k, "channelmix.surround-level"))
spa_atof(s, &this->mix.surround_level);
else if (spa_streq(k, "channelmix.lfe-level"))
spa_atof(s, &this->mix.lfe_level);
else if (spa_streq(k, "channelmix.hilbert-taps"))
spa_atou32(s, &this->mix.hilbert_taps, 0);
else if (spa_streq(k, "channelmix.upmix-method"))
@ -2165,7 +2115,7 @@ static int setup_in_convert(struct impl *this)
return res;
spa_log_debug(this->log, "%p: got converter features %08x:%08x passthrough:%d remap:%d %s", this,
this->cpu_flags, in->conv.func_cpu_flags, in->conv.is_passthrough,
this->cpu_flags, in->conv.cpu_flags, in->conv.is_passthrough,
remap, in->conv.func_name);
return 0;
@ -2322,7 +2272,7 @@ static int setup_channelmix(struct impl *this, uint32_t channels, uint32_t *posi
set_volume(this);
spa_log_debug(this->log, "%p: got channelmix features %08x:%08x flags:%08x %s",
this, this->cpu_flags, this->mix.func_cpu_flags,
this, this->cpu_flags, this->mix.cpu_flags,
this->mix.flags, this->mix.func_name);
return 0;
}
@ -2370,7 +2320,7 @@ static int setup_resample(struct impl *this)
res = resample_native_init(&this->resample);
spa_log_debug(this->log, "%p: got resample features %08x:%08x %s",
this, this->cpu_flags, this->resample.func_cpu_flags,
this, this->cpu_flags, this->resample.cpu_flags,
this->resample.func_name);
return res;
}
@ -2462,7 +2412,7 @@ static int setup_out_convert(struct impl *this)
spa_log_debug(this->log, "%p: got converter features %08x:%08x quant:%d:%d"
" passthrough:%d remap:%d %s", this,
this->cpu_flags, out->conv.func_cpu_flags, out->conv.method,
this->cpu_flags, out->conv.cpu_flags, out->conv.method,
out->conv.noise_bits, out->conv.is_passthrough, remap, out->conv.func_name);
return 0;
@ -4284,7 +4234,6 @@ static void free_dir(struct dir *dir)
static int impl_clear(struct spa_handle *handle)
{
struct impl *this;
int i;
spa_return_val_if_fail(handle != NULL, -EINVAL);
@ -4296,10 +4245,6 @@ static int impl_clear(struct spa_handle *handle)
free_tmp(this);
clean_filter_handles(this, true);
for (i = 0; i < MAX_GRAPH; i++) {
if (this->graph_descs[i])
free(this->graph_descs[i]);
}
if (this->resample.free)
resample_free(&this->resample);
@ -4354,13 +4299,18 @@ impl_init(const struct spa_handle_factory *factory,
struct filter_graph *g = &this->graphs[i];
g->impl = this;
spa_list_append(&this->free_graphs, &g->link);
this->graph_descs[i] = NULL;
}
this->rate_limit.interval = 2 * SPA_NSEC_PER_SEC;
this->rate_limit.burst = 1;
channelmix_reset(&this->mix);
this->mix.options = CHANNELMIX_OPTION_UPMIX | CHANNELMIX_OPTION_MIX_LFE;
this->mix.upmix = CHANNELMIX_UPMIX_NONE;
this->mix.log = this->log;
this->mix.lfe_cutoff = 0.0f;
this->mix.fc_cutoff = 0.0f;
this->mix.rear_delay = 0.0f;
this->mix.widen = 0.0f;
for (i = 0; info && i < info->n_items; i++) {
const char *k = info->items[i].key;

View file

@ -51,9 +51,9 @@ static void run_test1(const char *name, const char *impl, bool in_packed, bool o
void *op[n_channels];
struct timespec ts;
uint64_t count, t1, t2;
struct convert conv = {
.n_channels = n_channels,
};
struct convert conv;
conv.n_channels = n_channels;
for (j = 0; j < n_channels; j++) {
ip[j] = &samp_in[j * n_samples * 4];

View file

@ -1,63 +0,0 @@
/* Spa */
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
/* SPDX-License-Identifier: MIT */
#include "channelmix-ops.h"
#include <immintrin.h>
#include <float.h>
#include <math.h>
static inline void clear_avx(float *d, uint32_t n_samples)
{
memset(d, 0, n_samples * sizeof(float));
}
static inline void copy_avx(float *d, const float *s, uint32_t n_samples)
{
spa_memcpy(d, s, n_samples * sizeof(float));
}
static inline void vol_avx(float *d, const float *s, float vol, uint32_t n_samples)
{
uint32_t n, unrolled;
if (vol == 0.0f) {
clear_avx(d, n_samples);
} else if (vol == 1.0f) {
copy_avx(d, s, n_samples);
} else {
__m256 t[4];
const __m256 v = _mm256_set1_ps(vol);
if (SPA_IS_ALIGNED(d, 32) &&
SPA_IS_ALIGNED(s, 32))
unrolled = n_samples & ~31;
else
unrolled = 0;
for(n = 0; n < unrolled; n += 32) {
t[0] = _mm256_load_ps(&s[n]);
t[1] = _mm256_load_ps(&s[n+8]);
t[2] = _mm256_load_ps(&s[n+16]);
t[3] = _mm256_load_ps(&s[n+24]);
_mm256_store_ps(&d[n], _mm256_mul_ps(t[0], v));
_mm256_store_ps(&d[n+8], _mm256_mul_ps(t[1], v));
_mm256_store_ps(&d[n+16], _mm256_mul_ps(t[2], v));
_mm256_store_ps(&d[n+24], _mm256_mul_ps(t[3], v));
}
for(; n < n_samples; n++) {
__m128 v = _mm_set1_ps(vol);
_mm_store_ss(&d[n], _mm_mul_ss(_mm_load_ss(&s[n]), v));
}
}
}
void channelmix_copy_avx(struct channelmix *mix, void * SPA_RESTRICT dst[],
const void * SPA_RESTRICT src[], uint32_t n_samples)
{
uint32_t i, n_dst = mix->dst_chan;
float **d = (float **)dst;
const float **s = (const float **)src;
for (i = 0; i < n_dst; i++)
vol_avx(d[i], s[i], mix->matrix[i][i], n_samples);
}

View file

@ -36,11 +36,6 @@ static const struct channelmix_info {
uint32_t cpu_flags;
} channelmix_table[] =
{
#if defined (HAVE_AVX)
MAKE(2, MASK_MONO, 2, MASK_MONO, channelmix_copy_avx, SPA_CPU_FLAG_AVX),
MAKE(2, MASK_STEREO, 2, MASK_STEREO, channelmix_copy_avx, SPA_CPU_FLAG_AVX),
MAKE(EQ, 0, EQ, 0, channelmix_copy_avx, SPA_CPU_FLAG_AVX),
#endif
#if defined (HAVE_SSE)
MAKE(2, MASK_MONO, 2, MASK_MONO, channelmix_copy_sse, SPA_CPU_FLAG_SSE),
MAKE(2, MASK_STEREO, 2, MASK_STEREO, channelmix_copy_sse, SPA_CPU_FLAG_SSE),
@ -198,9 +193,9 @@ static int make_matrix(struct channelmix *mix)
uint32_t dst_chan = mix->dst_chan;
uint64_t unassigned, keep;
uint32_t i, j, ic, jc, matrix_encoding = MATRIX_NORMAL;
float clev = mix->center_level;
float slev = mix->surround_level;
float llev = mix->lfe_level;
float clev = SQRT1_2;
float slev = SQRT1_2;
float llev = 0.5f;
float maxsum = 0.0f;
bool filter_fc = false, filter_lfe = false, matched = false, normalize;
#define _MATRIX(s,d) matrix[_CH(s)][_CH(d)]
@ -725,7 +720,7 @@ done:
if (src_paired == 0)
src_paired = ~0LU;
for (jc = 0, ic = 0, i = 0; ic < dst_chan && i < MAX_CHANNELS; i++) {
for (jc = 0, ic = 0, i = 0; i < CHANNEL_BITS; i++) {
float sum = 0.0f;
char str1[1024], str2[1024];
struct spa_strbuf sb1, sb2;
@ -733,10 +728,12 @@ done:
spa_strbuf_init(&sb1, str1, sizeof(str1));
spa_strbuf_init(&sb2, str2, sizeof(str2));
if (i < CHANNEL_BITS && (dst_paired & (1UL << i)) == 0)
if ((dst_paired & (1UL << i)) == 0)
continue;
for (jc = 0, j = 0; jc < src_chan && j < MAX_CHANNELS; j++) {
if (j < CHANNEL_BITS && (src_paired & (1UL << j)) == 0)
for (jc = 0, j = 0; j < CHANNEL_BITS; j++) {
if ((src_paired & (1UL << j)) == 0)
continue;
if (ic >= dst_chan || jc >= src_chan)
continue;
if (ic == 0)
@ -755,7 +752,7 @@ done:
if (sb2.pos > 0)
spa_log_info(mix->log, " %s", str2);
if (sb1.pos > 0) {
spa_log_info(mix->log, "%03d %-4.4s %s %f", ic,
spa_log_info(mix->log, "%-4.4s %s %f",
dst_mask == 0 ? "UNK" :
spa_debug_type_find_short_name(spa_type_audio_channel, i + _SH),
str1, sum);
@ -828,6 +825,7 @@ static void impl_channelmix_set_volume(struct channelmix *mix, float volume, boo
for (i = 0; i < dst_chan; i++) {
for (j = 0; j < src_chan; j++) {
float v = mix->matrix[i][j];
spa_log_debug(mix->log, "%d %d: %f", i, j, v);
if (i == 0 && j == 0)
t = v;
else if (t != v)
@ -842,31 +840,7 @@ static void impl_channelmix_set_volume(struct channelmix *mix, float volume, boo
SPA_FLAG_UPDATE(mix->flags, CHANNELMIX_FLAG_IDENTITY,
dst_chan == src_chan && SPA_FLAG_IS_SET(mix->flags, CHANNELMIX_FLAG_COPY));
if (SPA_UNLIKELY(spa_log_level_topic_enabled(mix->log,
SPA_LOG_TOPIC_DEFAULT, SPA_LOG_LEVEL_DEBUG))) {
char str1[1024], str2[1024];
struct spa_strbuf sb1, sb2;
spa_strbuf_init(&sb2, str2, sizeof(str2));
for (i = 0; i < dst_chan; i++) {
spa_strbuf_init(&sb1, str1, sizeof(str1));
for (j = 0; j < src_chan; j++) {
float v = mix->matrix[i][j];
if (i == 0)
spa_strbuf_append(&sb2, " %03d ", j);
if (v == 0.0f)
spa_strbuf_append(&sb1, " ");
else
spa_strbuf_append(&sb1, "%1.3f ", v);
}
if (i == 0 && sb2.pos > 0)
spa_log_debug(mix->log, " %s", str2);
if (sb1.pos > 0)
spa_log_debug(mix->log, "%03d %s %03d", i, str1, i);
}
if (sb2.pos > 0)
spa_log_debug(mix->log, " %s", str2);
spa_log_debug(mix->log, "flags:%08x", mix->flags);
}
}
static void impl_channelmix_free(struct channelmix *mix)
@ -874,21 +848,6 @@ static void impl_channelmix_free(struct channelmix *mix)
mix->process = NULL;
}
void channelmix_reset(struct channelmix *mix)
{
spa_zero(*mix);
mix->options = CHANNELMIX_DEFAULT_OPTIONS;
mix->upmix = CHANNELMIX_DEFAULT_UPMIX;
mix->lfe_cutoff = CHANNELMIX_DEFAULT_LFE_CUTOFF;
mix->fc_cutoff = CHANNELMIX_DEFAULT_FC_CUTOFF;
mix->rear_delay = CHANNELMIX_DEFAULT_REAR_DELAY;
mix->center_level = CHANNELMIX_DEFAULT_CENTER_LEVEL;
mix->surround_level = CHANNELMIX_DEFAULT_SURROUND_LEVEL;
mix->lfe_level = CHANNELMIX_DEFAULT_LFE_LEVEL;
mix->widen = CHANNELMIX_DEFAULT_WIDEN;
mix->hilbert_taps = CHANNELMIX_DEFAULT_HILBERT_TAPS;
}
int channelmix_init(struct channelmix *mix)
{
const struct channelmix_info *info;
@ -905,8 +864,8 @@ int channelmix_init(struct channelmix *mix)
mix->free = impl_channelmix_free;
mix->process = info->process;
mix->set_volume = impl_channelmix_set_volume;
mix->cpu_flags = info->cpu_flags;
mix->delay = (uint32_t)(mix->rear_delay * mix->freq / 1000.0f);
mix->func_cpu_flags = info->cpu_flags;
mix->func_name = info->name;
spa_zero(mix->taps_mem);

View file

@ -28,17 +28,6 @@
#define CHANNELMIX_OPS_MAX_ALIGN 16
#define CHANNELMIX_DEFAULT_OPTIONS (CHANNELMIX_OPTION_UPMIX | CHANNELMIX_OPTION_MIX_LFE)
#define CHANNELMIX_DEFAULT_UPMIX CHANNELMIX_UPMIX_NONE
#define CHANNELMIX_DEFAULT_LFE_CUTOFF 0.0f
#define CHANNELMIX_DEFAULT_FC_CUTOFF 0.0f
#define CHANNELMIX_DEFAULT_REAR_DELAY 0.0f
#define CHANNELMIX_DEFAULT_CENTER_LEVEL 0.707106781f
#define CHANNELMIX_DEFAULT_SURROUND_LEVEL 0.707106781f
#define CHANNELMIX_DEFAULT_LFE_LEVEL 0.5f
#define CHANNELMIX_DEFAULT_WIDEN 0.0f
#define CHANNELMIX_DEFAULT_HILBERT_TAPS 0
struct channelmix {
uint32_t src_chan;
uint32_t dst_chan;
@ -55,7 +44,6 @@ struct channelmix {
uint32_t upmix;
struct spa_log *log;
uint32_t func_cpu_flags;
const char *func_name;
#define CHANNELMIX_FLAG_ZERO (1<<0) /**< all zero components */
@ -71,9 +59,6 @@ struct channelmix {
float fc_cutoff; /* in Hz, 0 is disabled */
float rear_delay; /* in ms, 0 is disabled */
float widen; /* stereo widen. 0 is disabled */
float center_level; /* center down/upmix level, sqrt(1/2) */
float lfe_level; /* lfe down/upmix level, 1/2 */
float surround_level; /* surround down/upmix level, sqrt(1/2) */
uint32_t hilbert_taps; /* to phase shift, 0 disabled */
struct lr4 lr4[MAX_CHANNELS];
@ -94,7 +79,6 @@ struct channelmix {
void *data;
};
void channelmix_reset(struct channelmix *mix);
int channelmix_init(struct channelmix *mix);
static const struct channelmix_upmix_info {
@ -155,8 +139,4 @@ DEFINE_FUNCTION(f32_5p1_4, sse);
DEFINE_FUNCTION(f32_7p1_4, sse);
#endif
#if defined (HAVE_AVX)
DEFINE_FUNCTION(copy, avx);
#endif
#undef DEFINE_FUNCTION

View file

@ -4,8 +4,6 @@
#include "fmt-ops.h"
#include <spa/support/cpu.h>
#include <immintrin.h>
// GCC: workaround for missing AVX intrinsic: "_mm256_setr_m128()"
// (see https://stackoverflow.com/questions/32630458/setting-m256i-to-the-value-of-two-m128i-values)
@ -32,38 +30,6 @@
_mm256_srli_epi16(x, 8)); \
})
#define _MM_TRANS_1x4_PS(v0,v1,v2,v3) \
({ \
v1 = _mm_shuffle_ps(v0, v0, _MM_SHUFFLE(0, 3, 2, 1)); \
v2 = _mm_shuffle_ps(v0, v0, _MM_SHUFFLE(1, 0, 3, 2)); \
v3 = _mm_shuffle_ps(v0, v0, _MM_SHUFFLE(2, 1, 0, 3)); \
})
#define _MM_TRANS_1x4_EPI32(v0,v1,v2,v3) \
({ \
v1 = _mm_shuffle_epi32(v0, _MM_SHUFFLE(0, 3, 2, 1)); \
v2 = _mm_shuffle_epi32(v0, _MM_SHUFFLE(1, 0, 3, 2)); \
v3 = _mm_shuffle_epi32(v0, _MM_SHUFFLE(2, 1, 0, 3)); \
})
#define _MM_STOREM_PS(d0,d1,d2,d3,v) \
({ \
__m128 o[3]; \
_MM_TRANS_1x4_PS(v, o[0], o[1], o[2]); \
_mm_store_ss(d0, v); \
_mm_store_ss(d1, o[0]); \
_mm_store_ss(d2, o[1]); \
_mm_store_ss(d3, o[2]); \
})
#define _MM_STOREM_EPI32(d0,d1,d2,d3,v) \
({ \
__m128i o[3]; \
_MM_TRANS_1x4_EPI32(v, o[0], o[1], o[2]); \
*d0 = _mm_cvtsi128_si32(v); \
*d1 = _mm_cvtsi128_si32(o[0]); \
*d2 = _mm_cvtsi128_si32(o[1]); \
*d3 = _mm_cvtsi128_si32(o[2]); \
})
static void
conv_s16_to_f32d_1s_avx2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
uint32_t n_channels, uint32_t n_samples)
@ -287,7 +253,7 @@ conv_s16s_to_f32d_2_avx2(struct convert *conv, void * SPA_RESTRICT dst[], const
}
static void
conv_s24_to_f32d_1s_gather_avx2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
conv_s24_to_f32d_1s_avx2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
uint32_t n_channels, uint32_t n_samples)
{
const int8_t *s = src;
@ -323,7 +289,7 @@ conv_s24_to_f32d_1s_gather_avx2(void *data, void * SPA_RESTRICT dst[], const voi
}
static void
conv_s24_to_f32d_2s_gather_avx2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
conv_s24_to_f32d_2s_avx2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
uint32_t n_channels, uint32_t n_samples)
{
const int8_t *s = src;
@ -375,7 +341,7 @@ conv_s24_to_f32d_2s_gather_avx2(void *data, void * SPA_RESTRICT dst[], const voi
}
}
static void
conv_s24_to_f32d_4s_gather_avx2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
conv_s24_to_f32d_4s_avx2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
uint32_t n_channels, uint32_t n_samples)
{
const int8_t *s = src;
@ -431,13 +397,18 @@ conv_s24_to_f32d_4s_gather_avx2(void *data, void * SPA_RESTRICT dst[], const voi
s += 12 * n_channels;
}
for(; n < n_samples; n++) {
in[0] = _mm_setr_epi32(s24_to_s32(*((int24_t*)s+0)),
s24_to_s32(*((int24_t*)s+1)),
s24_to_s32(*((int24_t*)s+2)),
s24_to_s32(*((int24_t*)s+3)));
out[0] = _mm_cvtepi32_ps(in[0]);
out[0] = _mm_mul_ps(out[0], factor);
_MM_STOREM_PS(&d0[n], &d1[n], &d2[n], &d3[n], out[0]);
out[0] = _mm_cvtsi32_ss(factor, s24_to_s32(*((int24_t*)s+0)));
out[1] = _mm_cvtsi32_ss(factor, s24_to_s32(*((int24_t*)s+1)));
out[2] = _mm_cvtsi32_ss(factor, s24_to_s32(*((int24_t*)s+2)));
out[3] = _mm_cvtsi32_ss(factor, s24_to_s32(*((int24_t*)s+3)));
out[0] = _mm_mul_ss(out[0], factor);
out[1] = _mm_mul_ss(out[1], factor);
out[2] = _mm_mul_ss(out[2], factor);
out[3] = _mm_mul_ss(out[3], factor);
_mm_store_ss(&d0[n], out[0]);
_mm_store_ss(&d1[n], out[1]);
_mm_store_ss(&d2[n], out[2]);
_mm_store_ss(&d3[n], out[3]);
s += 3 * n_channels;
}
}
@ -449,22 +420,16 @@ conv_s24_to_f32d_avx2(struct convert *conv, void * SPA_RESTRICT dst[], const voi
const int8_t *s = src[0];
uint32_t i = 0, n_channels = conv->n_channels;
if (conv->cpu_flags & SPA_CPU_FLAG_SLOW_GATHER) {
#if defined (HAVE_SSE2)
conv_s24_to_f32d_sse2(conv, dst, src, n_samples);
#endif
} else {
for(; i + 3 < n_channels; i += 4)
conv_s24_to_f32d_4s_gather_avx2(conv, &dst[i], &s[3*i], n_channels, n_samples);
conv_s24_to_f32d_4s_avx2(conv, &dst[i], &s[3*i], n_channels, n_samples);
for(; i + 1 < n_channels; i += 2)
conv_s24_to_f32d_2s_gather_avx2(conv, &dst[i], &s[3*i], n_channels, n_samples);
conv_s24_to_f32d_2s_avx2(conv, &dst[i], &s[3*i], n_channels, n_samples);
for(; i < n_channels; i++)
conv_s24_to_f32d_1s_gather_avx2(conv, &dst[i], &s[3*i], n_channels, n_samples);
}
conv_s24_to_f32d_1s_avx2(conv, &dst[i], &s[3*i], n_channels, n_samples);
}
static void
conv_s32_to_f32d_4s_gather_avx2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
conv_s32_to_f32d_4s_avx2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
uint32_t n_channels, uint32_t n_samples)
{
const int32_t *s = src;
@ -508,17 +473,24 @@ conv_s32_to_f32d_4s_gather_avx2(void *data, void * SPA_RESTRICT dst[], const voi
}
for(; n < n_samples; n++) {
__m128 out[4], factor = _mm_set1_ps(1.0f / S32_SCALE_I2F);
__m128i in[1];
in[0] = _mm_setr_epi32(s[0], s[1], s[2], s[3]);
out[0] = _mm_cvtepi32_ps(in[0]);
out[0] = _mm_mul_ps(out[0], factor);
_MM_STOREM_PS(&d0[n], &d1[n], &d2[n], &d3[n], out[0]);
out[0] = _mm_cvtsi32_ss(factor, s[0]);
out[1] = _mm_cvtsi32_ss(factor, s[1]);
out[2] = _mm_cvtsi32_ss(factor, s[2]);
out[3] = _mm_cvtsi32_ss(factor, s[3]);
out[0] = _mm_mul_ss(out[0], factor);
out[1] = _mm_mul_ss(out[1], factor);
out[2] = _mm_mul_ss(out[2], factor);
out[3] = _mm_mul_ss(out[3], factor);
_mm_store_ss(&d0[n], out[0]);
_mm_store_ss(&d1[n], out[1]);
_mm_store_ss(&d2[n], out[2]);
_mm_store_ss(&d3[n], out[3]);
s += n_channels;
}
}
static void
conv_s32_to_f32d_2s_gather_avx2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
conv_s32_to_f32d_2s_avx2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
uint32_t n_channels, uint32_t n_samples)
{
const int32_t *s = src;
@ -563,7 +535,7 @@ conv_s32_to_f32d_2s_gather_avx2(void *data, void * SPA_RESTRICT dst[], const voi
}
static void
conv_s32_to_f32d_1s_gather_avx2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
conv_s32_to_f32d_1s_avx2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
uint32_t n_channels, uint32_t n_samples)
{
const int32_t *s = src;
@ -603,169 +575,6 @@ conv_s32_to_f32d_1s_gather_avx2(void *data, void * SPA_RESTRICT dst[], const voi
}
}
static void
conv_s32_to_f32d_2s_avx2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
uint32_t n_channels, uint32_t n_samples)
{
const int32_t *s = src;
float *d0 = dst[0], *d1 = dst[1];
uint32_t n, unrolled;
__m256i in[4];
__m256 out[4], t[4], factor = _mm256_set1_ps(1.0f / S32_SCALE_I2F);
if (SPA_IS_ALIGNED(d0, 32) &&
SPA_IS_ALIGNED(d1, 32))
unrolled = n_samples & ~7;
else
unrolled = 0;
for(n = 0; n < unrolled; n += 8) {
in[0] = _mm256_setr_epi64x(
*((uint64_t*)&s[0*n_channels]),
*((uint64_t*)&s[1*n_channels]),
*((uint64_t*)&s[4*n_channels]),
*((uint64_t*)&s[5*n_channels]));
in[1] = _mm256_setr_epi64x(
*((uint64_t*)&s[2*n_channels]),
*((uint64_t*)&s[3*n_channels]),
*((uint64_t*)&s[6*n_channels]),
*((uint64_t*)&s[7*n_channels]));
out[0] = _mm256_cvtepi32_ps(in[0]);
out[1] = _mm256_cvtepi32_ps(in[1]);
out[0] = _mm256_mul_ps(out[0], factor); /* a0 b0 a1 b1 a4 b4 a5 b5 */
out[1] = _mm256_mul_ps(out[1], factor); /* a2 b2 a3 b3 a6 b6 a7 b7 */
t[0] = _mm256_unpacklo_ps(out[0], out[1]); /* a0 a2 b0 b2 a4 a6 b4 b6 */
t[1] = _mm256_unpackhi_ps(out[0], out[1]); /* a1 a3 b1 b3 a5 a7 b5 b7 */
out[0] = _mm256_unpacklo_ps(t[0], t[1]); /* a0 a1 a2 a3 a4 a5 a6 a7 */
out[1] = _mm256_unpackhi_ps(t[0], t[1]); /* b0 b1 b2 b3 b4 b5 b6 b7 */
_mm256_store_ps(&d0[n], out[0]);
_mm256_store_ps(&d1[n], out[1]);
s += 8*n_channels;
}
for(; n < n_samples; n++) {
__m128 out[2], factor = _mm_set1_ps(1.0f / S32_SCALE_I2F);
out[0] = _mm_cvtsi32_ss(factor, s[0]);
out[1] = _mm_cvtsi32_ss(factor, s[1]);
out[0] = _mm_mul_ss(out[0], factor);
out[1] = _mm_mul_ss(out[1], factor);
_mm_store_ss(&d0[n], out[0]);
_mm_store_ss(&d1[n], out[1]);
s += n_channels;
}
}
static void
conv_s32_to_f32d_1s_avx2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
uint32_t n_channels, uint32_t n_samples)
{
const int32_t *s = src;
float *d0 = dst[0];
uint32_t n, unrolled;
__m256i in[2];
__m256 out[2], factor = _mm256_set1_ps(1.0f / S32_SCALE_I2F);
if (SPA_IS_ALIGNED(d0, 32))
unrolled = n_samples & ~7;
else
unrolled = 0;
for(n = 0; n < unrolled; n += 8) {
in[0] = _mm256_setr_epi32(
s[0*n_channels], s[1*n_channels],
s[2*n_channels], s[3*n_channels],
s[4*n_channels], s[5*n_channels],
s[6*n_channels], s[7*n_channels]);
out[0] = _mm256_cvtepi32_ps(in[0]);
out[0] = _mm256_mul_ps(out[0], factor);
_mm256_store_ps(&d0[n+0], out[0]);
s += 8*n_channels;
}
for(; n < n_samples; n++) {
__m128 out, factor = _mm_set1_ps(1.0f / S32_SCALE_I2F);
out = _mm_cvtsi32_ss(factor, s[0]);
out = _mm_mul_ss(out, factor);
_mm_store_ss(&d0[n], out);
s += n_channels;
}
}
static void
conv_s32_to_f32d_4s_avx2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
uint32_t n_channels, uint32_t n_samples)
{
const int32_t *s = src;
float *d0 = dst[0], *d1 = dst[1], *d2 = dst[2], *d3 = dst[3];
uint32_t n, unrolled;
__m256i in[4];
__m256 out[4], t[4], factor = _mm256_set1_ps(1.0f / S32_SCALE_I2F);
if (SPA_IS_ALIGNED(d0, 32) &&
SPA_IS_ALIGNED(d1, 32) &&
SPA_IS_ALIGNED(d2, 32) &&
SPA_IS_ALIGNED(d3, 32))
unrolled = n_samples & ~7;
else
unrolled = 0;
for(n = 0; n < unrolled; n += 8) {
in[0] = _mm256_setr_m128i(
_mm_loadu_si128((__m128i*)&s[0*n_channels]),
_mm_loadu_si128((__m128i*)&s[4*n_channels]));
in[1] = _mm256_setr_m128i(
_mm_loadu_si128((__m128i*)&s[1*n_channels]),
_mm_loadu_si128((__m128i*)&s[5*n_channels]));
in[2] = _mm256_setr_m128i(
_mm_loadu_si128((__m128i*)&s[2*n_channels]),
_mm_loadu_si128((__m128i*)&s[6*n_channels]));
in[3] = _mm256_setr_m128i(
_mm_loadu_si128((__m128i*)&s[3*n_channels]),
_mm_loadu_si128((__m128i*)&s[7*n_channels]));
out[0] = _mm256_cvtepi32_ps(in[0]); /* a0 b0 c0 d0 a4 b4 c4 d4 */
out[1] = _mm256_cvtepi32_ps(in[1]); /* a1 b1 c1 d1 a5 b5 c5 d5 */
out[2] = _mm256_cvtepi32_ps(in[2]); /* a2 b2 c2 d2 a6 b6 c6 d6 */
out[3] = _mm256_cvtepi32_ps(in[3]); /* a3 b3 c3 d3 a7 b7 c7 d7 */
out[0] = _mm256_mul_ps(out[0], factor);
out[1] = _mm256_mul_ps(out[1], factor);
out[2] = _mm256_mul_ps(out[2], factor);
out[3] = _mm256_mul_ps(out[3], factor);
t[0] = _mm256_unpacklo_ps(out[0], out[2]); /* a0 a2 b0 b2 a4 a6 b4 b6 */
t[1] = _mm256_unpackhi_ps(out[0], out[2]); /* c0 c2 d0 d2 c4 c6 d4 d6 */
t[2] = _mm256_unpacklo_ps(out[1], out[3]); /* a1 a3 b1 b3 a5 a7 b5 b7 */
t[3] = _mm256_unpackhi_ps(out[1], out[3]); /* c1 c3 d1 d3 c5 c7 d5 d7 */
out[0] = _mm256_unpacklo_ps(t[0], t[2]); /* a0 a1 a2 a3 a4 a5 a6 a7 */
out[1] = _mm256_unpackhi_ps(t[0], t[2]); /* b0 b1 b2 b3 b4 b5 b6 b7 */
out[2] = _mm256_unpacklo_ps(t[1], t[3]); /* c0 c1 c2 c3 c4 c5 c6 c7 */
out[3] = _mm256_unpackhi_ps(t[1], t[3]); /* d0 d1 d2 d3 d4 d5 d6 d7 */
_mm256_store_ps(&d0[n], out[0]);
_mm256_store_ps(&d1[n], out[1]);
_mm256_store_ps(&d2[n], out[2]);
_mm256_store_ps(&d3[n], out[3]);
s += 8*n_channels;
}
for(; n < n_samples; n++) {
__m128 out[4], factor = _mm_set1_ps(1.0f / S32_SCALE_I2F);
__m128i in[1];
in[0] = _mm_setr_epi32(s[0], s[1], s[2], s[3]);
out[0] = _mm_cvtepi32_ps(in[0]);
out[0] = _mm_mul_ps(out[0], factor);
_MM_STOREM_PS(&d0[n], &d1[n], &d2[n], &d3[n], out[0]);
s += n_channels;
}
}
void
conv_s32_to_f32d_avx2(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
@ -773,21 +582,12 @@ conv_s32_to_f32d_avx2(struct convert *conv, void * SPA_RESTRICT dst[], const voi
const int32_t *s = src[0];
uint32_t i = 0, n_channels = conv->n_channels;
if (conv->cpu_flags & SPA_CPU_FLAG_SLOW_GATHER) {
for(; i + 3 < n_channels; i += 4)
conv_s32_to_f32d_4s_avx2(conv, &dst[i], &s[i], n_channels, n_samples);
for(; i + 1 < n_channels; i += 2)
conv_s32_to_f32d_2s_avx2(conv, &dst[i], &s[i], n_channels, n_samples);
for(; i < n_channels; i++)
conv_s32_to_f32d_1s_avx2(conv, &dst[i], &s[i], n_channels, n_samples);
} else {
for(; i + 3 < n_channels; i += 4)
conv_s32_to_f32d_4s_gather_avx2(conv, &dst[i], &s[i], n_channels, n_samples);
for(; i + 1 < n_channels; i += 2)
conv_s32_to_f32d_2s_gather_avx2(conv, &dst[i], &s[i], n_channels, n_samples);
for(; i < n_channels; i++)
conv_s32_to_f32d_1s_gather_avx2(conv, &dst[i], &s[i], n_channels, n_samples);
}
}
static void
@ -812,10 +612,14 @@ conv_f32d_to_s32_1s_avx2(void *data, void * SPA_RESTRICT dst, const void * SPA_R
in[0] = _mm_mul_ps(_mm_load_ps(&s0[n]), scale);
in[0] = _MM_CLAMP_PS(in[0], int_min, int_max);
out[0] = _mm_cvtps_epi32(in[0]);
_MM_STOREM_EPI32(&d[0*n_channels],
&d[1*n_channels],
&d[2*n_channels],
&d[3*n_channels], out[0]);
out[1] = _mm_shuffle_epi32(out[0], _MM_SHUFFLE(0, 3, 2, 1));
out[2] = _mm_shuffle_epi32(out[0], _MM_SHUFFLE(1, 0, 3, 2));
out[3] = _mm_shuffle_epi32(out[0], _MM_SHUFFLE(2, 1, 0, 3));
d[0*n_channels] = _mm_cvtsi128_si32(out[0]);
d[1*n_channels] = _mm_cvtsi128_si32(out[1]);
d[2*n_channels] = _mm_cvtsi128_si32(out[2]);
d[3*n_channels] = _mm_cvtsi128_si32(out[3]);
d += 4*n_channels;
}
for(; n < n_samples; n++) {
@ -970,7 +774,15 @@ conv_f32d_to_s32_4s_avx2(void *data, void * SPA_RESTRICT dst, const void * SPA_R
__m128 int_min = _mm_set1_ps(S32_MIN_F2I);
__m128 int_max = _mm_set1_ps(S32_MAX_F2I);
in[0] = _mm_setr_ps(s0[n], s1[n], s2[n], s3[n]);
in[0] = _mm_load_ss(&s0[n]);
in[1] = _mm_load_ss(&s1[n]);
in[2] = _mm_load_ss(&s2[n]);
in[3] = _mm_load_ss(&s3[n]);
in[0] = _mm_unpacklo_ps(in[0], in[2]);
in[1] = _mm_unpacklo_ps(in[1], in[3]);
in[0] = _mm_unpacklo_ps(in[0], in[1]);
in[0] = _mm_mul_ps(in[0], scale);
in[0] = _MM_CLAMP_PS(in[0], int_min, int_max);
out[0] = _mm_cvtps_epi32(in[0]);
@ -1160,16 +972,18 @@ conv_f32d_to_s16_4s_avx2(void *data, void * SPA_RESTRICT dst, const void * SPA_R
__m128 int_max = _mm_set1_ps(S16_MAX);
__m128 int_min = _mm_set1_ps(S16_MIN);
in[0] = _mm_setr_ps(s0[n], s1[n], s2[n], s3[n]);
in[0] = _mm_mul_ps(in[0], int_scale);
in[0] = _MM_CLAMP_PS(in[0], int_min, int_max);
_MM_TRANS_1x4_PS(in[0], in[1], in[2], in[3]);
in[0] = _mm_mul_ss(_mm_load_ss(&s0[n]), int_scale);
in[1] = _mm_mul_ss(_mm_load_ss(&s1[n]), int_scale);
in[2] = _mm_mul_ss(_mm_load_ss(&s2[n]), int_scale);
in[3] = _mm_mul_ss(_mm_load_ss(&s3[n]), int_scale);
in[0] = _MM_CLAMP_SS(in[0], int_min, int_max);
in[1] = _MM_CLAMP_SS(in[1], int_min, int_max);
in[2] = _MM_CLAMP_SS(in[2], int_min, int_max);
in[3] = _MM_CLAMP_SS(in[3], int_min, int_max);
d[0] = _mm_cvtss_si32(in[0]);
d[1] = _mm_cvtss_si32(in[1]);
d[2] = _mm_cvtss_si32(in[2]);
d[3] = _mm_cvtss_si32(in[3]);
d += n_channels;
}
}
@ -1241,10 +1055,14 @@ conv_f32d_to_s16_4_avx2(struct convert *conv, void * SPA_RESTRICT dst[], const v
__m128 int_max = _mm_set1_ps(S16_MAX);
__m128 int_min = _mm_set1_ps(S16_MIN);
in[0] = _mm_setr_ps(s0[n], s1[n], s2[n], s3[n]);
in[0] = _mm_mul_ps(in[0], int_scale);
in[0] = _MM_CLAMP_PS(in[0], int_min, int_max);
_MM_TRANS_1x4_PS(in[0], in[1], in[2], in[3]);
in[0] = _mm_mul_ss(_mm_load_ss(&s0[n]), int_scale);
in[1] = _mm_mul_ss(_mm_load_ss(&s1[n]), int_scale);
in[2] = _mm_mul_ss(_mm_load_ss(&s2[n]), int_scale);
in[3] = _mm_mul_ss(_mm_load_ss(&s3[n]), int_scale);
in[0] = _MM_CLAMP_SS(in[0], int_min, int_max);
in[1] = _MM_CLAMP_SS(in[1], int_min, int_max);
in[2] = _MM_CLAMP_SS(in[2], int_min, int_max);
in[3] = _MM_CLAMP_SS(in[3], int_min, int_max);
d[0] = _mm_cvtss_si32(in[0]);
d[1] = _mm_cvtss_si32(in[1]);
d[2] = _mm_cvtss_si32(in[2]);
@ -1367,4 +1185,3 @@ conv_f32d_to_s16s_2_avx2(struct convert *conv, void * SPA_RESTRICT dst[], const
d += 2;
}
}

View file

@ -26,72 +26,6 @@
a = _mm_shufflehi_epi16(a, _MM_SHUFFLE(2, 3, 0, 1)); \
})
#define spa_read_unaligned(ptr, type) \
__extension__ ({ \
__typeof__(type) _val; \
memcpy(&_val, (ptr), sizeof(_val)); \
_val; \
})
#define spa_write_unaligned(ptr, type, val) \
__extension__ ({ \
__typeof__(type) _val = (val); \
memcpy((ptr), &_val, sizeof(_val)); \
})
#define _MM_TRANS_1x4_PS(v0,v1,v2,v3) \
({ \
v1 = _mm_shuffle_ps(v0, v0, _MM_SHUFFLE(0, 3, 2, 1)); \
v2 = _mm_shuffle_ps(v0, v0, _MM_SHUFFLE(1, 0, 3, 2)); \
v3 = _mm_shuffle_ps(v0, v0, _MM_SHUFFLE(2, 1, 0, 3)); \
})
#define _MM_TRANS_1x4_EPI32(v0,v1,v2,v3) \
({ \
v1 = _mm_shuffle_epi32(v0, _MM_SHUFFLE(0, 3, 2, 1)); \
v2 = _mm_shuffle_epi32(v0, _MM_SHUFFLE(1, 0, 3, 2)); \
v3 = _mm_shuffle_epi32(v0, _MM_SHUFFLE(2, 1, 0, 3)); \
})
#if 0
#define _MM_STOREM_PS(d0,d1,d2,d3,v) \
({ \
*d0 = v[0]; \
*d1 = v[1]; \
*d2 = v[2]; \
*d3 = v[3]; \
})
#else
#define _MM_STOREM_PS(d0,d1,d2,d3,v) \
({ \
__m128 o[3]; \
_MM_TRANS_1x4_PS(v, o[0], o[1], o[2]); \
_mm_store_ss(d0, v); \
_mm_store_ss(d1, o[0]); \
_mm_store_ss(d2, o[1]); \
_mm_store_ss(d3, o[2]); \
})
#endif
#define _MM_STOREM_EPI32(d0,d1,d2,d3,v) \
({ \
__m128i o[3]; \
_MM_TRANS_1x4_EPI32(v, o[0], o[1], o[2]); \
*d0 = _mm_cvtsi128_si32(v); \
*d1 = _mm_cvtsi128_si32(o[0]); \
*d2 = _mm_cvtsi128_si32(o[1]); \
*d3 = _mm_cvtsi128_si32(o[2]); \
})
#define _MM_STOREUM_EPI32(d0,d1,d2,d3,v) \
({ \
__m128i o[3]; \
_MM_TRANS_1x4_EPI32(v, o[0], o[1], o[2]); \
spa_write_unaligned(d0, uint32_t, _mm_cvtsi128_si32(v)); \
spa_write_unaligned(d1, uint32_t, _mm_cvtsi128_si32(o[0])); \
spa_write_unaligned(d2, uint32_t, _mm_cvtsi128_si32(o[1])); \
spa_write_unaligned(d3, uint32_t, _mm_cvtsi128_si32(o[2])); \
})
static void
conv_s16_to_f32d_1s_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
uint32_t n_channels, uint32_t n_samples)
@ -299,6 +233,18 @@ conv_s16s_to_f32d_2_sse2(struct convert *conv, void * SPA_RESTRICT dst[], const
}
}
#define spa_read_unaligned(ptr, type) \
__extension__ ({ \
__typeof__(type) _val; \
memcpy(&_val, (ptr), sizeof(_val)); \
_val; \
})
#define spa_write_unaligned(ptr, type, val) \
__extension__ ({ \
__typeof__(type) _val = (val); \
memcpy((ptr), &_val, sizeof(_val)); \
})
void
conv_s24_to_f32d_1s_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
uint32_t n_channels, uint32_t n_samples)
@ -470,13 +416,18 @@ conv_s24_to_f32d_4s_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA
s += 4 * n_channels;
}
for(; n < n_samples; n++) {
in[0] = _mm_setr_epi32(s24_to_s32(*s),
s24_to_s32(*(s+1)),
s24_to_s32(*(s+2)),
s24_to_s32(*(s+3)));
out[0] = _mm_cvtepi32_ps(in[0]);
out[0] = _mm_mul_ps(out[0], factor);
_MM_STOREM_PS(&d0[n], &d1[n], &d2[n], &d3[n], out[0]);
out[0] = _mm_cvtsi32_ss(factor, s24_to_s32(*s));
out[1] = _mm_cvtsi32_ss(factor, s24_to_s32(*(s+1)));
out[2] = _mm_cvtsi32_ss(factor, s24_to_s32(*(s+2)));
out[3] = _mm_cvtsi32_ss(factor, s24_to_s32(*(s+3)));
out[0] = _mm_mul_ss(out[0], factor);
out[1] = _mm_mul_ss(out[1], factor);
out[2] = _mm_mul_ss(out[2], factor);
out[3] = _mm_mul_ss(out[3], factor);
_mm_store_ss(&d0[n], out[0]);
_mm_store_ss(&d1[n], out[1]);
_mm_store_ss(&d2[n], out[2]);
_mm_store_ss(&d3[n], out[3]);
s += n_channels;
}
}
@ -496,59 +447,6 @@ conv_s24_to_f32d_sse2(struct convert *conv, void * SPA_RESTRICT dst[], const voi
conv_s24_to_f32d_1s_sse2(conv, &dst[i], &s[3*i], n_channels, n_samples);
}
static void
conv_s32_to_f32d_4s_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
uint32_t n_channels, uint32_t n_samples)
{
const int32_t *s = src;
float *d0 = dst[0], *d1 = dst[1], *d2 = dst[2], *d3 = dst[3];
uint32_t n, unrolled;
__m128i in[4];
__m128 out[4], factor = _mm_set1_ps(1.0f / S32_SCALE_I2F);
if (SPA_IS_ALIGNED(d0, 16) &&
SPA_IS_ALIGNED(d1, 16) &&
SPA_IS_ALIGNED(d2, 16) &&
SPA_IS_ALIGNED(d3, 16) &&
SPA_IS_ALIGNED(s, 16) && (n_channels & 3) == 0)
unrolled = n_samples & ~3;
else
unrolled = 0;
for(n = 0; n < unrolled; n += 4) {
in[0] = _mm_load_si128((__m128i*)(s + 0*n_channels));
in[1] = _mm_load_si128((__m128i*)(s + 1*n_channels));
in[2] = _mm_load_si128((__m128i*)(s + 2*n_channels));
in[3] = _mm_load_si128((__m128i*)(s + 3*n_channels));
out[0] = _mm_cvtepi32_ps(in[0]);
out[1] = _mm_cvtepi32_ps(in[1]);
out[2] = _mm_cvtepi32_ps(in[2]);
out[3] = _mm_cvtepi32_ps(in[3]);
out[0] = _mm_mul_ps(out[0], factor);
out[1] = _mm_mul_ps(out[1], factor);
out[2] = _mm_mul_ps(out[2], factor);
out[3] = _mm_mul_ps(out[3], factor);
_MM_TRANSPOSE4_PS(out[0], out[1], out[2], out[3]);
_mm_store_ps(&d0[n], out[0]);
_mm_store_ps(&d1[n], out[1]);
_mm_store_ps(&d2[n], out[2]);
_mm_store_ps(&d3[n], out[3]);
s += 4*n_channels;
}
for(; n < n_samples; n++) {
in[0] = _mm_setr_epi32(s[0], s[1], s[2], s[3]);
out[0] = _mm_cvtepi32_ps(in[0]);
out[0] = _mm_mul_ps(out[0], factor);
_MM_STOREM_PS(&d0[n], &d1[n], &d2[n], &d3[n], out[0]);
s += n_channels;
}
}
static void
conv_s32_to_f32d_1s_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
uint32_t n_channels, uint32_t n_samples)
@ -589,8 +487,6 @@ conv_s32_to_f32d_sse2(struct convert *conv, void * SPA_RESTRICT dst[], const voi
const int32_t *s = src[0];
uint32_t i = 0, n_channels = conv->n_channels;
for(; i + 3 < n_channels; i += 4)
conv_s32_to_f32d_4s_sse2(conv, &dst[i], &s[i], n_channels, n_samples);
for(; i < n_channels; i++)
conv_s32_to_f32d_1s_sse2(conv, &dst[i], &s[i], n_channels, n_samples);
}
@ -617,10 +513,14 @@ conv_f32d_to_s32_1s_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_R
in[0] = _mm_mul_ps(_mm_load_ps(&s0[n]), scale);
in[0] = _MM_CLAMP_PS(in[0], int_min, int_max);
out[0] = _mm_cvtps_epi32(in[0]);
_MM_STOREM_EPI32(&d[0*n_channels],
&d[1*n_channels],
&d[2*n_channels],
&d[3*n_channels], out[0]);
out[1] = _mm_shuffle_epi32(out[0], _MM_SHUFFLE(0, 3, 2, 1));
out[2] = _mm_shuffle_epi32(out[0], _MM_SHUFFLE(1, 0, 3, 2));
out[3] = _mm_shuffle_epi32(out[0], _MM_SHUFFLE(2, 1, 0, 3));
d[0*n_channels] = _mm_cvtsi128_si32(out[0]);
d[1*n_channels] = _mm_cvtsi128_si32(out[1]);
d[2*n_channels] = _mm_cvtsi128_si32(out[2]);
d[3*n_channels] = _mm_cvtsi128_si32(out[3]);
d += 4*n_channels;
}
for(; n < n_samples; n++) {
@ -730,7 +630,15 @@ conv_f32d_to_s32_4s_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_R
d += 4*n_channels;
}
for(; n < n_samples; n++) {
in[0] = _mm_setr_ps(s0[n], s1[n], s2[n], s3[n]);
in[0] = _mm_load_ss(&s0[n]);
in[1] = _mm_load_ss(&s1[n]);
in[2] = _mm_load_ss(&s2[n]);
in[3] = _mm_load_ss(&s3[n]);
in[0] = _mm_unpacklo_ps(in[0], in[2]);
in[1] = _mm_unpacklo_ps(in[1], in[3]);
in[0] = _mm_unpacklo_ps(in[0], in[1]);
in[0] = _mm_mul_ps(in[0], scale);
in[0] = _MM_CLAMP_PS(in[0], int_min, int_max);
out[0] = _mm_cvtps_epi32(in[0]);
@ -846,10 +754,14 @@ conv_f32d_to_s32_1s_noise_sse2(struct convert *conv, void * SPA_RESTRICT dst, co
in[0] = _mm_add_ps(in[0], _mm_load_ps(&noise[n]));
in[0] = _MM_CLAMP_PS(in[0], int_min, int_max);
out[0] = _mm_cvtps_epi32(in[0]);
_MM_STOREM_EPI32(&d[0*n_channels],
&d[1*n_channels],
&d[2*n_channels],
&d[3*n_channels], out[0]);
out[1] = _mm_shuffle_epi32(out[0], _MM_SHUFFLE(0, 3, 2, 1));
out[2] = _mm_shuffle_epi32(out[0], _MM_SHUFFLE(1, 0, 3, 2));
out[3] = _mm_shuffle_epi32(out[0], _MM_SHUFFLE(2, 1, 0, 3));
d[0*n_channels] = _mm_cvtsi128_si32(out[0]);
d[1*n_channels] = _mm_cvtsi128_si32(out[1]);
d[2*n_channels] = _mm_cvtsi128_si32(out[2]);
d[3*n_channels] = _mm_cvtsi128_si32(out[3]);
d += 4*n_channels;
}
for(; n < n_samples; n++) {
@ -898,10 +810,14 @@ conv_interleave_32_1s_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA
for(n = 0; n < unrolled; n += 4) {
out[0] = _mm_load_si128((__m128i*)&s0[n]);
_MM_STOREM_EPI32(&d[0*n_channels],
&d[1*n_channels],
&d[2*n_channels],
&d[3*n_channels], out[0]);
out[1] = _mm_shuffle_epi32(out[0], _MM_SHUFFLE(0, 3, 2, 1));
out[2] = _mm_shuffle_epi32(out[0], _MM_SHUFFLE(1, 0, 3, 2));
out[3] = _mm_shuffle_epi32(out[0], _MM_SHUFFLE(2, 1, 0, 3));
d[0*n_channels] = _mm_cvtsi128_si32(out[0]);
d[1*n_channels] = _mm_cvtsi128_si32(out[1]);
d[2*n_channels] = _mm_cvtsi128_si32(out[2]);
d[3*n_channels] = _mm_cvtsi128_si32(out[3]);
d += 4*n_channels;
}
for(; n < n_samples; n++) {
@ -977,10 +893,14 @@ conv_interleave_32s_1s_sse2(void *data, void * SPA_RESTRICT dst, const void * SP
for(n = 0; n < unrolled; n += 4) {
out[0] = _mm_load_si128((__m128i*)&s0[n]);
out[0] = _MM_BSWAP_EPI32(out[0]);
_MM_STOREM_EPI32(&d[0*n_channels],
&d[1*n_channels],
&d[2*n_channels],
&d[3*n_channels], out[0]);
out[1] = _mm_shuffle_epi32(out[0], _MM_SHUFFLE(0, 3, 2, 1));
out[2] = _mm_shuffle_epi32(out[0], _MM_SHUFFLE(1, 0, 3, 2));
out[3] = _mm_shuffle_epi32(out[0], _MM_SHUFFLE(2, 1, 0, 3));
d[0*n_channels] = _mm_cvtsi128_si32(out[0]);
d[1*n_channels] = _mm_cvtsi128_si32(out[1]);
d[2*n_channels] = _mm_cvtsi128_si32(out[2]);
d[3*n_channels] = _mm_cvtsi128_si32(out[3]);
d += 4*n_channels;
}
for(; n < n_samples; n++) {
@ -1337,10 +1257,14 @@ conv_f32d_to_s16_2s_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_R
t[1] = _mm_packs_epi32(t[1], t[1]);
out[0] = _mm_unpacklo_epi16(t[0], t[1]);
_MM_STOREUM_EPI32(&d[0*n_channels],
&d[1*n_channels],
&d[2*n_channels],
&d[3*n_channels], out[0]);
out[1] = _mm_shuffle_epi32(out[0], _MM_SHUFFLE(0, 3, 2, 1));
out[2] = _mm_shuffle_epi32(out[0], _MM_SHUFFLE(1, 0, 3, 2));
out[3] = _mm_shuffle_epi32(out[0], _MM_SHUFFLE(2, 1, 0, 3));
spa_write_unaligned(d + 0*n_channels, uint32_t, _mm_cvtsi128_si32(out[0]));
spa_write_unaligned(d + 1*n_channels, uint32_t, _mm_cvtsi128_si32(out[1]));
spa_write_unaligned(d + 2*n_channels, uint32_t, _mm_cvtsi128_si32(out[2]));
spa_write_unaligned(d + 3*n_channels, uint32_t, _mm_cvtsi128_si32(out[3]));
d += 4*n_channels;
}
for(; n < n_samples; n++) {

View file

@ -631,7 +631,7 @@ int convert_init(struct convert *conv)
conv->random[i] = random();
conv->is_passthrough = conv->src_fmt == conv->dst_fmt;
conv->func_cpu_flags = info->cpu_flags;
conv->cpu_flags = info->cpu_flags;
conv->update_noise = ninfo->noise;
conv->process = info->process;
conv->clear = cinfo ? cinfo->clear : NULL;

View file

@ -219,7 +219,6 @@ struct convert {
uint32_t n_channels;
uint32_t rate;
uint32_t cpu_flags;
uint32_t func_cpu_flags;
const char *func_name;
unsigned int is_passthrough:1;

View file

@ -44,7 +44,7 @@ endif
if have_sse2
audioconvert_sse2 = static_library('audioconvert_sse2',
['fmt-ops-sse2.c' ],
c_args : [sse2_args, '-O3', '-DHAVE_SSE2', simd_cargs],
c_args : [sse2_args, '-O3', '-DHAVE_SSE2'],
dependencies : [ spa_dep ],
install : false
)
@ -55,7 +55,7 @@ if have_ssse3
audioconvert_ssse3 = static_library('audioconvert_ssse3',
['fmt-ops-ssse3.c',
'resample-native-ssse3.c' ],
c_args : [ssse3_args, '-O3', '-DHAVE_SSSE3', simd_cargs],
c_args : [ssse3_args, '-O3', '-DHAVE_SSSE3'],
dependencies : [ spa_dep ],
install : false
)
@ -65,27 +65,17 @@ endif
if have_sse41
audioconvert_sse41 = static_library('audioconvert_sse41',
['fmt-ops-sse41.c'],
c_args : [sse41_args, '-O3', '-DHAVE_SSE41', simd_cargs],
c_args : [sse41_args, '-O3', '-DHAVE_SSE41'],
dependencies : [ spa_dep ],
install : false
)
simd_cargs += ['-DHAVE_SSE41']
simd_dependencies += audioconvert_sse41
endif
if have_avx
audioconvert_avx = static_library('audioconvert_avx',
['channelmix-ops-avx.c'],
c_args : [avx_args, '-O3', '-DHAVE_AVX', simd_cargs],
dependencies : [ spa_dep ],
install : false
)
simd_cargs += ['-DHAVE_AVX']
simd_dependencies += audioconvert_avx
endif
if have_avx2 and have_fma
audioconvert_avx2_fma = static_library('audioconvert_avx2_fma',
['resample-native-avx2.c'],
c_args : [avx2_args, fma_args, '-O3', '-DHAVE_AVX2', '-DHAVE_FMA', simd_cargs],
c_args : [avx2_args, fma_args, '-O3', '-DHAVE_AVX2', '-DHAVE_FMA'],
dependencies : [ spa_dep ],
install : false
)
@ -95,7 +85,7 @@ endif
if have_avx2
audioconvert_avx2 = static_library('audioconvert_avx2',
['fmt-ops-avx2.c'],
c_args : [avx2_args, '-O3', '-DHAVE_AVX2', simd_cargs],
c_args : [avx2_args, '-O3', '-DHAVE_AVX2'],
dependencies : [ spa_dep ],
install : false
)

View file

@ -60,7 +60,7 @@ int peaks_init(struct peaks *peaks)
if (info == NULL)
return -ENOTSUP;
peaks->func_cpu_flags = info->cpu_flags;
peaks->cpu_flags = info->cpu_flags;
peaks->func_name = info->name;
peaks->free = impl_peaks_free;
peaks->min_max = info->min_max;

View file

@ -14,7 +14,6 @@ extern struct spa_log_topic resample_log_topic;
struct peaks {
uint32_t cpu_flags;
uint32_t func_cpu_flags;
const char *func_name;
struct spa_log *log;

View file

@ -576,7 +576,7 @@ int resample_native_init(struct resample *r)
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->func_cpu_flags = d->info->cpu_flags;
r->cpu_flags = d->info->cpu_flags;
impl_native_reset(r);
impl_native_update_rate(r, 1.0);

View file

@ -38,7 +38,6 @@ struct resample {
#define RESAMPLE_OPTION_PREFILL (1<<0)
uint32_t options;
uint32_t cpu_flags;
uint32_t func_cpu_flags;
const char *func_name;
uint32_t channels;

View file

@ -54,7 +54,7 @@ static int setup_context(struct context *ctx)
size_t size;
int res;
struct spa_support support[1];
struct spa_dict_item items[9];
struct spa_dict_item items[6];
const struct spa_handle_factory *factory;
void *iface;
@ -76,13 +76,10 @@ static int setup_context(struct context *ctx)
items[3] = SPA_DICT_ITEM_INIT("channelmix.lfe-cutoff", "150");
items[4] = SPA_DICT_ITEM_INIT("channelmix.fc-cutoff", "12000");
items[5] = SPA_DICT_ITEM_INIT("channelmix.rear-delay", "12.0");
items[6] = SPA_DICT_ITEM_INIT("channelmix.center-level", "0.707106781");
items[7] = SPA_DICT_ITEM_INIT("channelmix.surround-level", "0.707106781");
items[8] = SPA_DICT_ITEM_INIT("channelmix.lfe-level", "0.5");
res = spa_handle_factory_init(factory,
ctx->convert_handle,
&SPA_DICT_INIT(items, 9),
&SPA_DICT_INIT(items, 6),
support, 1);
spa_assert_se(res >= 0);

View file

@ -45,7 +45,7 @@ static void test_mix(uint32_t src_chan, uint32_t src_mask, uint32_t dst_chan, ui
spa_log_debug(&logger.log, "start %d->%d (%08x -> %08x)", src_chan, dst_chan, src_mask, dst_mask);
channelmix_reset(&mix);
spa_zero(mix);
mix.options = options;
mix.src_chan = src_chan;
mix.dst_chan = dst_chan;
@ -340,7 +340,7 @@ static void test_n_m_impl(void)
src[i] = src_data[i];
}
channelmix_reset(&mix);
spa_zero(mix);
mix.src_chan = 16;
mix.dst_chan = 12;
mix.log = &logger.log;

View file

@ -45,9 +45,9 @@ static void run_test(const char *name,
void *tp[N_CHANNELS];
int i, j;
const uint8_t *in8 = in, *out8 = out;
struct convert conv = {
.n_channels = N_CHANNELS,
};
struct convert conv;
conv.n_channels = N_CHANNELS;
for (j = 0; j < N_SAMPLES; j++) {
memcpy(&samp_in[j * in_size], &in8[(j % n_samples) * in_size], in_size);

View file

@ -56,7 +56,7 @@ int volume_init(struct volume *vol)
if (info == NULL)
return -ENOTSUP;
vol->func_cpu_flags = info->cpu_flags;
vol->cpu_flags = info->cpu_flags;
vol->func_name = info->name;
vol->free = impl_volume_free;
vol->process = info->process;

View file

@ -13,7 +13,6 @@
struct volume {
uint32_t cpu_flags;
uint32_t func_cpu_flags;
const char *func_name;
struct spa_log *log;

View file

@ -725,7 +725,7 @@ static int do_port_set_io(struct spa_loop *loop, bool async, uint32_t seq,
port->io[0] = info->data;
port->io[1] = info->data;
}
if (port->direction == SPA_DIRECTION_INPUT && !port->active) {
if (!port->active) {
spa_list_append(&info->impl->mix_list, &port->mix_link);
port->active = true;
}

View file

@ -718,7 +718,7 @@ static int do_port_set_io(struct spa_loop *loop, bool async, uint32_t seq,
port->io[0] = info->data;
port->io[1] = info->data;
}
if (port->direction == SPA_DIRECTION_INPUT && !port->active) {
if (!port->active) {
spa_list_append(&info->impl->mix_list, &port->mix_link);
port->active = true;
}

View file

@ -41,11 +41,13 @@ enum wave_type {
#define DEFAULT_RATE 48000
#define DEFAULT_CHANNELS 2
#define DEFAULT_LIVE true
#define DEFAULT_WAVE WAVE_SINE
#define DEFAULT_FREQ 440.0
#define DEFAULT_VOLUME 1.0
struct props {
bool live;
uint32_t wave;
float freq;
float volume;
@ -53,6 +55,7 @@ struct props {
static void reset_props(struct props *props)
{
props->live = DEFAULT_LIVE;
props->wave = DEFAULT_WAVE;
props->freq = DEFAULT_FREQ;
props->volume = DEFAULT_VOLUME;
@ -115,7 +118,9 @@ struct impl {
struct spa_hook_list hooks;
struct spa_callbacks callbacks;
bool async;
struct spa_source timer_source;
struct itimerspec timerspec;
bool started;
uint64_t start_time;
@ -157,6 +162,13 @@ static int impl_node_enum_params(void *object, int seq,
switch (result.index) {
case 0:
param = spa_pod_builder_add_object(&b,
SPA_TYPE_OBJECT_PropInfo, id,
SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_live),
SPA_PROP_INFO_description, SPA_POD_String("Configure live mode of the source"),
SPA_PROP_INFO_type, SPA_POD_Bool(p->live));
break;
case 1:
spa_pod_builder_push_object(&b, &f[0], SPA_TYPE_OBJECT_PropInfo, id);
spa_pod_builder_add(&b,
SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_waveType),
@ -172,14 +184,14 @@ static int impl_node_enum_params(void *object, int seq,
spa_pod_builder_pop(&b, &f[1]);
param = spa_pod_builder_pop(&b, &f[0]);
break;
case 1:
case 2:
param = spa_pod_builder_add_object(&b,
SPA_TYPE_OBJECT_PropInfo, id,
SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_frequency),
SPA_PROP_INFO_description, SPA_POD_String("Select the frequency"),
SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float(p->freq, 0.0, 50000000.0));
break;
case 2:
case 3:
param = spa_pod_builder_add_object(&b,
SPA_TYPE_OBJECT_PropInfo, id,
SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_volume),
@ -199,6 +211,7 @@ static int impl_node_enum_params(void *object, int seq,
case 0:
param = spa_pod_builder_add_object(&b,
SPA_TYPE_OBJECT_Props, id,
SPA_PROP_live, SPA_POD_Bool(p->live),
SPA_PROP_waveType, SPA_POD_Int(p->wave),
SPA_PROP_frequency, SPA_POD_Float(p->freq),
SPA_PROP_volume, SPA_POD_Float(p->volume));
@ -252,6 +265,7 @@ static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
if (id == SPA_PARAM_Props) {
struct props *p = &this->props;
struct port *port = &this->port;
if (param == NULL) {
reset_props(p);
@ -259,9 +273,15 @@ static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
}
spa_pod_parse_object(param,
SPA_TYPE_OBJECT_Props, NULL,
SPA_PROP_live, SPA_POD_OPT_Bool(&p->live),
SPA_PROP_waveType, SPA_POD_OPT_Int(&p->wave),
SPA_PROP_frequency, SPA_POD_OPT_Float(&p->freq),
SPA_PROP_volume, SPA_POD_OPT_Float(&p->volume));
if (p->live)
port->info.flags |= SPA_PORT_FLAG_LIVE;
else
port->info.flags &= ~SPA_PORT_FLAG_LIVE;
}
else
return -ENOENT;
@ -296,15 +316,23 @@ static int impl_node_set_io(void *object, uint32_t id, void *data, size_t size)
static void set_timer(struct impl *this, bool enabled)
{
struct itimerspec ts = {0};
if (this->async || this->props.live) {
if (enabled) {
if (this->props.live) {
uint64_t next_time = this->start_time + this->elapsed_time;
ts.it_value.tv_sec = next_time / SPA_NSEC_PER_SEC;
ts.it_value.tv_nsec = next_time % SPA_NSEC_PER_SEC;
this->timerspec.it_value.tv_sec = next_time / SPA_NSEC_PER_SEC;
this->timerspec.it_value.tv_nsec = next_time % SPA_NSEC_PER_SEC;
} else {
this->timerspec.it_value.tv_sec = 0;
this->timerspec.it_value.tv_nsec = 1;
}
} else {
this->timerspec.it_value.tv_sec = 0;
this->timerspec.it_value.tv_nsec = 0;
}
spa_system_timerfd_settime(this->data_system,
this->timer_source.fd, SPA_FD_TIMER_ABSTIME, &this->timerspec, NULL);
}
spa_system_timerfd_settime(this->data_system, this->timer_source.fd, SPA_FD_TIMER_ABSTIME, &ts, NULL);
}
static int read_timer(struct impl *this)
@ -312,12 +340,14 @@ static int read_timer(struct impl *this)
uint64_t expirations;
int res = 0;
if ((res = spa_system_timerfd_read(this->data_system, this->timer_source.fd, &expirations)) < 0) {
if (this->async || this->props.live) {
if ((res = spa_system_timerfd_read(this->data_system,
this->timer_source.fd, &expirations)) < 0) {
if (res != -EAGAIN)
spa_log_error(this->log, "%p: timerfd error: %s",
this, spa_strerror(res));
}
}
return 0;
}
@ -441,7 +471,10 @@ static int impl_node_send_command(void *object, const struct spa_command *comman
return 0;
clock_gettime(CLOCK_MONOTONIC, &now);
if (this->props.live)
this->start_time = SPA_TIMESPEC_TO_NSEC(&now);
else
this->start_time = 0;
this->sample_count = 0;
this->elapsed_time = 0;
@ -862,6 +895,9 @@ static inline void reuse_buffer(struct impl *this, struct port *port, uint32_t i
b->outstanding = false;
spa_list_append(&port->empty, &b->link);
if (!this->props.live && !this->following)
set_timer(this, true);
}
static int impl_node_port_reuse_buffer(void *object, uint32_t port_id, uint32_t buffer_id)
@ -935,7 +971,7 @@ static int impl_node_process(void *object)
io->buffer_id = SPA_ID_INVALID;
}
if (this->following)
if (!this->props.live || this->following)
return make_buffer(this);
else
return SPA_STATUS_OK;
@ -1069,6 +1105,10 @@ impl_init(const struct spa_handle_factory *factory,
CLOCK_MONOTONIC, SPA_FD_CLOEXEC | SPA_FD_NONBLOCK);
this->timer_source.mask = SPA_IO_IN;
this->timer_source.rmask = 0;
this->timerspec.it_value.tv_sec = 0;
this->timerspec.it_value.tv_nsec = 0;
this->timerspec.it_interval.tv_sec = 0;
this->timerspec.it_interval.tv_nsec = 0;
if (this->data_loop)
spa_loop_add_source(this->data_loop, &this->timer_source);
@ -1077,7 +1117,9 @@ impl_init(const struct spa_handle_factory *factory,
port->info_all = SPA_PORT_CHANGE_MASK_FLAGS |
SPA_PORT_CHANGE_MASK_PARAMS;
port->info = SPA_PORT_INFO_INIT();
port->info.flags = SPA_PORT_FLAG_NO_REF | SPA_PORT_FLAG_LIVE;
port->info.flags = SPA_PORT_FLAG_NO_REF;
if (this->props.live)
port->info.flags |= SPA_PORT_FLAG_LIVE;
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
port->params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);

View file

@ -106,8 +106,8 @@ static int codec_fill_caps(const struct media_codec *codec, uint32_t flags,
static const struct media_codec_config
aac_frequencies[] = {
{ AAC_SAMPLING_FREQ_44100, 44100, 10 },
{ AAC_SAMPLING_FREQ_48000, 48000, 11 },
{ AAC_SAMPLING_FREQ_44100, 44100, 10 },
{ AAC_SAMPLING_FREQ_96000, 96000, 9 },
{ AAC_SAMPLING_FREQ_88200, 88200, 8 },
{ AAC_SAMPLING_FREQ_64000, 64000, 7 },
@ -194,6 +194,75 @@ static int codec_select_config(const struct media_codec *codec, uint32_t flags,
return sizeof(conf);
}
static int codec_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 *b, struct spa_pod **param)
{
a2dp_aac_t conf;
struct spa_pod_frame f[2];
struct spa_pod_choice *choice;
uint32_t position[2];
uint32_t i = 0;
if (caps_size < sizeof(conf))
return -EINVAL;
memcpy(&conf, caps, sizeof(conf));
if (idx > 0)
return 0;
spa_pod_builder_push_object(b, &f[0], SPA_TYPE_OBJECT_Format, id);
spa_pod_builder_add(b,
SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio),
SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
SPA_FORMAT_AUDIO_format, SPA_POD_Id(SPA_AUDIO_FORMAT_S16),
0);
spa_pod_builder_prop(b, SPA_FORMAT_AUDIO_rate, 0);
spa_pod_builder_push_choice(b, &f[1], SPA_CHOICE_None, 0);
choice = (struct spa_pod_choice*)spa_pod_builder_frame(b, &f[1]);
i = 0;
SPA_FOR_EACH_ELEMENT_VAR(aac_frequencies, f) {
if (AAC_GET_FREQUENCY(conf) & f->config) {
if (i++ == 0)
spa_pod_builder_int(b, f->value);
spa_pod_builder_int(b, f->value);
}
}
if (i > 1)
choice->body.type = SPA_CHOICE_Enum;
spa_pod_builder_pop(b, &f[1]);
if (i == 0)
return -EINVAL;
if (SPA_FLAG_IS_SET(conf.channels, AAC_CHANNELS_1 | AAC_CHANNELS_2)) {
spa_pod_builder_add(b,
SPA_FORMAT_AUDIO_channels, SPA_POD_CHOICE_RANGE_Int(2, 1, 2),
0);
} else if (conf.channels & AAC_CHANNELS_1) {
position[0] = SPA_AUDIO_CHANNEL_MONO;
spa_pod_builder_add(b,
SPA_FORMAT_AUDIO_channels, SPA_POD_Int(1),
SPA_FORMAT_AUDIO_position, SPA_POD_Array(sizeof(uint32_t),
SPA_TYPE_Id, 1, position),
0);
} else if (conf.channels & AAC_CHANNELS_2) {
position[0] = SPA_AUDIO_CHANNEL_FL;
position[1] = SPA_AUDIO_CHANNEL_FR;
spa_pod_builder_add(b,
SPA_FORMAT_AUDIO_channels, SPA_POD_Int(2),
SPA_FORMAT_AUDIO_position, SPA_POD_Array(sizeof(uint32_t),
SPA_TYPE_Id, 2, position),
0);
} else
return -EINVAL;
*param = spa_pod_builder_pop(b, &f[0]);
return *param == NULL ? -EIO : 1;
}
static int codec_validate_config(const struct media_codec *codec, uint32_t flags,
const void *caps, size_t caps_size,
struct spa_audio_info *info)
@ -214,10 +283,8 @@ static int codec_validate_config(const struct media_codec *codec, uint32_t flags
/*
* A2DP v1.3.2, 4.5.2: only one bit shall be set in bitfields.
* However, there is a report (#1342) of device setting multiple
* bits for AAC object type. In addition AirPods set multiple bits.
*
* Some devices also set multiple bits in frequencies & channels.
* For these, pick a "preferred" choice.
* bits for AAC object type. It's not clear if this was due to
* a BlueZ bug, but we can be lax here and below in codec_init.
*/
if (!(conf.object_type & (AAC_OBJECT_TYPE_MPEG2_AAC_LC |
AAC_OBJECT_TYPE_MPEG4_AAC_LC |
@ -248,35 +315,6 @@ static int codec_validate_config(const struct media_codec *codec, uint32_t flags
return 0;
}
static int codec_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 *b, struct spa_pod **param)
{
struct spa_audio_info info;
struct spa_pod_frame f[1];
int res;
if ((res = codec_validate_config(codec, flags, caps, caps_size, &info)) < 0)
return res;
if (idx > 0)
return 0;
spa_pod_builder_push_object(b, &f[0], SPA_TYPE_OBJECT_Format, id);
spa_pod_builder_add(b,
SPA_FORMAT_mediaType, SPA_POD_Id(info.media_type),
SPA_FORMAT_mediaSubtype, SPA_POD_Id(info.media_subtype),
SPA_FORMAT_AUDIO_format, SPA_POD_Id(info.info.raw.format),
SPA_FORMAT_AUDIO_rate, SPA_POD_Int(info.info.raw.rate),
SPA_FORMAT_AUDIO_channels, SPA_POD_Int(info.info.raw.channels),
SPA_FORMAT_AUDIO_position, SPA_POD_Array(sizeof(uint32_t),
SPA_TYPE_Id, info.info.raw.channels, info.info.raw.position),
0);
*param = spa_pod_builder_pop(b, &f[0]);
return *param == NULL ? -EIO : 1;
}
static void *codec_init_props(const struct media_codec *codec, uint32_t flags, const struct spa_dict *settings)
{
struct props *p = calloc(1, sizeof(struct props));
@ -286,7 +324,7 @@ static void *codec_init_props(const struct media_codec *codec, uint32_t flags, c
return NULL;
if (settings == NULL || (str = spa_dict_lookup(settings, "bluez5.a2dp.aac.bitratemode")) == NULL)
str = "5";
str = "0";
p->bitratemode = SPA_CLAMP(atoi(str), 0, 5);
return p;
@ -331,14 +369,14 @@ static void *codec_init(const struct media_codec *codec, uint32_t flags,
goto error;
/* If object type has multiple bits set (invalid per spec, see above),
* assume the device usually means MPEG2 AAC LC which is mandatory.
* assume the device usually means AAC-LC.
*/
if (conf->object_type & AAC_OBJECT_TYPE_MPEG2_AAC_LC) {
res = aacEncoder_SetParam(this->aacenc, AACENC_AOT, AOT_MP2_AAC_LC);
if (conf->object_type & AAC_OBJECT_TYPE_MPEG4_AAC_LC) {
res = aacEncoder_SetParam(this->aacenc, AACENC_AOT, AOT_AAC_LC);
if (res != AACENC_OK)
goto error;
} else if (conf->object_type & AAC_OBJECT_TYPE_MPEG4_AAC_LC) {
res = aacEncoder_SetParam(this->aacenc, AACENC_AOT, AOT_AAC_LC);
} else if (conf->object_type & AAC_OBJECT_TYPE_MPEG2_AAC_LC) {
res = aacEncoder_SetParam(this->aacenc, AACENC_AOT, AOT_MP2_AAC_LC);
if (res != AACENC_OK)
goto error;
} else if (conf->object_type & AAC_OBJECT_TYPE_MPEG4_AAC_ELD) {
@ -380,12 +418,8 @@ static void *codec_init(const struct media_codec *codec, uint32_t flags,
// Fragmentation is not implemented yet,
// so make sure every encoded AAC frame fits in (mtu - header)
this->max_bitrate = ((this->mtu - sizeof(struct rtp_header)) * 8 * this->rate) / 1024;
this->cur_bitrate = SPA_MIN(this->max_bitrate, get_valid_aac_bitrate(conf));
spa_log_debug(log, "AAC: max (peak) bitrate: %d, cur bitrate: %d, mode: %d (vbr: %d)",
this->max_bitrate,
this->cur_bitrate,
bitratemode,
conf->vbr);
this->max_bitrate = SPA_MIN(this->max_bitrate, get_valid_aac_bitrate(conf));
this->cur_bitrate = this->max_bitrate;
res = aacEncoder_SetParam(this->aacenc, AACENC_BITRATE, this->cur_bitrate);
if (res != AACENC_OK)
@ -395,15 +429,6 @@ static void *codec_init(const struct media_codec *codec, uint32_t flags,
if (res != AACENC_OK)
goto error;
// Assume >110 kbit/s as a "high bitrate" CBR and increase the
// band pass cutout up to 19.3 kHz (as in mode 5 VBR).
if (!conf->vbr && this->cur_bitrate > 110000) {
res = aacEncoder_SetParam(this->aacenc, AACENC_BANDWIDTH,
19293);
if (res != AACENC_OK)
goto error;
}
res = aacEncoder_SetParam(this->aacenc, AACENC_TRANSMUX, TT_MP4_LATM_MCP1);
if (res != AACENC_OK)
goto error;

View file

@ -343,27 +343,77 @@ static int codec_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 *b, struct spa_pod **param)
{
struct spa_audio_info info;
struct spa_pod_frame f[1];
int res;
a2dp_sbc_t conf;
struct spa_pod_frame f[2];
struct spa_pod_choice *choice;
uint32_t i = 0;
uint32_t position[2];
if ((res = codec_validate_config(codec, flags, caps, caps_size, &info)) < 0)
return res;
if (caps_size < sizeof(conf))
return -EINVAL;
memcpy(&conf, caps, sizeof(conf));
if (idx > 0)
return 0;
spa_pod_builder_push_object(b, &f[0], SPA_TYPE_OBJECT_Format, id);
spa_pod_builder_add(b,
SPA_FORMAT_mediaType, SPA_POD_Id(info.media_type),
SPA_FORMAT_mediaSubtype, SPA_POD_Id(info.media_subtype),
SPA_FORMAT_AUDIO_format, SPA_POD_Id(info.info.raw.format),
SPA_FORMAT_AUDIO_rate, SPA_POD_Int(info.info.raw.rate),
SPA_FORMAT_AUDIO_channels, SPA_POD_Int(info.info.raw.channels),
SPA_FORMAT_AUDIO_position, SPA_POD_Array(sizeof(uint32_t),
SPA_TYPE_Id, info.info.raw.channels, info.info.raw.position),
SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_audio),
SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
SPA_FORMAT_AUDIO_format, SPA_POD_Id(SPA_AUDIO_FORMAT_S16),
0);
spa_pod_builder_prop(b, SPA_FORMAT_AUDIO_rate, 0);
spa_pod_builder_push_choice(b, &f[1], SPA_CHOICE_None, 0);
choice = (struct spa_pod_choice*)spa_pod_builder_frame(b, &f[1]);
i = 0;
if (conf.frequency & SBC_SAMPLING_FREQ_48000) {
if (i++ == 0)
spa_pod_builder_int(b, 48000);
spa_pod_builder_int(b, 48000);
}
if (conf.frequency & SBC_SAMPLING_FREQ_44100) {
if (i++ == 0)
spa_pod_builder_int(b, 44100);
spa_pod_builder_int(b, 44100);
}
if (conf.frequency & SBC_SAMPLING_FREQ_32000) {
if (i++ == 0)
spa_pod_builder_int(b, 32000);
spa_pod_builder_int(b, 32000);
}
if (conf.frequency & SBC_SAMPLING_FREQ_16000) {
if (i++ == 0)
spa_pod_builder_int(b, 16000);
spa_pod_builder_int(b, 16000);
}
if (i > 1)
choice->body.type = SPA_CHOICE_Enum;
spa_pod_builder_pop(b, &f[1]);
if (conf.channel_mode & SBC_CHANNEL_MODE_MONO &&
conf.channel_mode & (SBC_CHANNEL_MODE_JOINT_STEREO |
SBC_CHANNEL_MODE_STEREO | SBC_CHANNEL_MODE_DUAL_CHANNEL)) {
spa_pod_builder_add(b,
SPA_FORMAT_AUDIO_channels, SPA_POD_CHOICE_RANGE_Int(2, 1, 2),
0);
} else if (conf.channel_mode & SBC_CHANNEL_MODE_MONO) {
position[0] = SPA_AUDIO_CHANNEL_MONO;
spa_pod_builder_add(b,
SPA_FORMAT_AUDIO_channels, SPA_POD_Int(1),
SPA_FORMAT_AUDIO_position, SPA_POD_Array(sizeof(uint32_t),
SPA_TYPE_Id, 1, position),
0);
} else {
position[0] = SPA_AUDIO_CHANNEL_FL;
position[1] = SPA_AUDIO_CHANNEL_FR;
spa_pod_builder_add(b,
SPA_FORMAT_AUDIO_channels, SPA_POD_Int(2),
SPA_FORMAT_AUDIO_position, SPA_POD_Array(sizeof(uint32_t),
SPA_TYPE_Id, 2, position),
0);
}
*param = spa_pod_builder_pop(b, &f[0]);
return *param == NULL ? -EIO : 1;
}

View file

@ -63,9 +63,6 @@ SPA_LOG_TOPIC_DEFINE_STATIC(log_topic, "spa.bluez5.native");
#define RFCOMM_MESSAGE_MAX_LENGTH 256
#define BT_CODEC_CVSD 0x02
#define BT_CODEC_MSBC 0x05
enum {
HFP_AG_INITIAL_CODEC_SETUP_NONE = 0,
HFP_AG_INITIAL_CODEC_SETUP_SEND,
@ -115,7 +112,6 @@ struct impl {
int hfp_default_speaker_volume;
struct spa_source sco;
unsigned int hfphsp_sco_datapath;
const struct spa_bt_quirks *quirks;
@ -301,33 +297,6 @@ static const struct media_codec *codec_list_best(struct impl *backend, struct sp
return NULL;
}
static void sco_offload_btcodec(struct impl *backend, int sock, bool msbc)
{
int err;
char buffer[255];
struct bt_codecs *codecs;
if (backend->hfphsp_sco_datapath == HFP_SCO_DEFAULT_DATAPATH)
return;
spa_log_info(backend->log, "sock(%d) msbc(%d)", sock, msbc);
memset(buffer, 0, sizeof(buffer));
codecs = (void *)buffer;
if (msbc)
codecs->codecs[0].id = BT_CODEC_MSBC;
else
codecs->codecs[0].id = BT_CODEC_CVSD;
codecs->num_codecs = 1;
codecs->codecs[0].data_path_id = backend->hfphsp_sco_datapath;
err = setsockopt(sock, SOL_BLUETOOTH, BT_CODEC, codecs, sizeof(buffer));
if (err < 0)
spa_log_error(backend->log, "ERROR: %s (%d)", strerror(errno), errno);
else
spa_log_info(backend->log, "set offload codec succeeded");
}
static DBusHandlerResult profile_release(DBusConnection *conn, DBusMessage *m, void *userdata)
{
if (!reply_with_error(conn, m, BLUEZ_PROFILE_INTERFACE ".Error.NotImplemented", "Method not implemented"))
@ -1969,9 +1938,6 @@ static void hfp_hf_remove_disconnected_calls(struct rfcomm *rfcomm)
struct updated_call *updated_call;
bool found;
if (!rfcomm->telephony_ag)
return;
spa_list_for_each_safe(call, call_tmp, &rfcomm->telephony_ag->call_list, link) {
found = false;
spa_list_for_each(updated_call, &rfcomm->updated_call_list, link) {
@ -2100,8 +2066,6 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token)
if (spa_streq(rfcomm->hf_indicators[indicator], "battchg")) {
spa_bt_device_report_battery_level(rfcomm->device, value * 100 / 5);
} else if (!rfcomm->telephony_ag) {
/* noop */
} else if (spa_streq(rfcomm->hf_indicators[indicator], "callsetup")) {
if (rfcomm->hfp_hf_clcc) {
rfcomm_send_cmd(rfcomm, hfp_hf_clcc_update, NULL, "AT+CLCC");
@ -2250,8 +2214,7 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token)
rfcomm->hfp_hf_in_progress = false;
}
}
} else if (sscanf(token, "+CLIP: \"%16[^\"]\",%u", number, &type) == 2
&& rfcomm->telephony_ag) {
} else if (sscanf(token, "+CLIP: \"%16[^\"]\",%u", number, &type) == 2) {
struct spa_bt_telephony_call *call;
spa_list_for_each(call, &rfcomm->telephony_ag->call_list, link) {
if (call->state == CALL_STATE_INCOMING && !spa_streq(number, call->line_identification)) {
@ -2262,8 +2225,7 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token)
break;
}
}
} else if (sscanf(token, "+CCWA: \"%16[^\"]\",%u", number, &type) == 2
&& rfcomm->telephony_ag) {
} else if (sscanf(token, "+CCWA: \"%16[^\"]\",%u", number, &type) == 2) {
struct spa_bt_telephony_call *call;
bool found = false;
@ -2280,7 +2242,7 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token)
if (call == NULL)
spa_log_warn(backend->log, "failed to create waiting call");
}
} else if (spa_strstartswith(token, "+CLCC:") && rfcomm->telephony_ag) {
} else if (spa_strstartswith(token, "+CLCC:")) {
struct spa_bt_telephony_call *call;
size_t pos;
char *token_end;
@ -2428,7 +2390,6 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token)
}
}
if (backend->telephony) {
rfcomm->telephony_ag = telephony_ag_new(backend->telephony, 0);
rfcomm->telephony_ag->address = strdup(rfcomm->device->address);
rfcomm->telephony_ag->volume[SPA_BT_VOLUME_ID_RX] = rfcomm->volumes[SPA_BT_VOLUME_ID_RX].hw_volume = backend->hfp_default_speaker_volume;
@ -2440,7 +2401,6 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token)
rfcomm->telephony_ag->transport.state = rfcomm->transport->state;
}
telephony_ag_register(rfcomm->telephony_ag);
}
rfcomm_send_cmd(rfcomm, hfp_hf_clip, NULL, "AT+CLIP=1");
break;
@ -2487,7 +2447,7 @@ static bool rfcomm_hfp_hf(struct rfcomm *rfcomm, char* token)
break;
case hfp_hf_chld1_hangup:
/* For HFP/HF/TWC/BV-03-C - see 0e92ab9307e05758b3f70b4c0648e29c1d1e50be */
if (!rfcomm->hfp_hf_clcc && rfcomm->telephony_ag) {
if (!rfcomm->hfp_hf_clcc) {
struct spa_bt_telephony_call *call, *tcall;
spa_list_for_each_safe(call, tcall, &rfcomm->telephony_ag->call_list, link) {
if (call->state == CALL_STATE_ACTIVE) {
@ -2635,8 +2595,6 @@ static int sco_create_socket(struct impl *backend, struct spa_bt_adapter *adapte
}
}
sco_offload_btcodec(backend, sock, transparent);
return spa_steal_fd(sock);
}
@ -4143,14 +4101,6 @@ static void parse_hfp_default_volumes(struct impl *backend, const struct spa_dic
backend->hfp_default_speaker_volume = SPA_BT_VOLUME_HS_MAX;
}
static void parse_sco_datapath(struct impl *backend, const struct spa_dict *info)
{
backend->hfphsp_sco_datapath = HFP_SCO_DEFAULT_DATAPATH;
spa_atou32(spa_dict_lookup(info, "bluez5.hw-offload-datapath"),
&backend->hfphsp_sco_datapath, 10);
}
static const struct spa_bt_backend_implementation backend_impl = {
SPA_VERSION_BT_BACKEND_IMPLEMENTATION,
.free = backend_native_free,
@ -4213,7 +4163,6 @@ struct spa_bt_backend *backend_native_new(struct spa_bt_monitor *monitor,
parse_hfp_disable_nrec(backend, info);
parse_hfp_default_volumes(backend, info);
parse_hfp_pts(backend, info);
parse_sco_datapath(backend, info);
#ifdef HAVE_BLUEZ_5_BACKEND_HSP_NATIVE
if (!dbus_connection_register_object_path(backend->conn,

View file

@ -55,7 +55,6 @@ struct settings {
int latency;
int64_t delay;
int framing;
char *force_target_latency;
};
struct pac_data {
@ -77,7 +76,6 @@ struct bap_qos {
uint16_t latency;
uint32_t delay;
unsigned int priority;
char *tag;
};
typedef struct {
@ -98,50 +96,50 @@ struct config_data {
struct settings settings;
};
#define BAP_QOS(name_, rate_, duration_, framing_, framelen_, rtn_, latency_, delay_, priority_, tag_) \
#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_), \
.delay = (delay_), .priority = (priority_), .tag = (tag_) })
.delay = (delay_), .priority = (priority_) })
static const struct bap_qos bap_qos_configs[] = {
/* Priority: low-latency > high-reliability, 7.5ms > 10ms,
* bigger frequency and sdu better */
/* BAP v1.0.1 Table 5.2; low-latency */
BAP_QOS("8_1_1", LC3_CONFIG_FREQ_8KHZ, LC3_CONFIG_DURATION_7_5, false, 26, 2, 8, 40000, 30, "low-latency"), /* 8_1_1 */
BAP_QOS("8_2_1", LC3_CONFIG_FREQ_8KHZ, LC3_CONFIG_DURATION_10, false, 30, 2, 10, 40000, 20, "low-latency"), /* 8_2_1 */
BAP_QOS("16_1_1", LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_7_5, false, 30, 2, 8, 40000, 31, "low-latency"), /* 16_1_1 */
BAP_QOS("16_2_1", LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_10, false, 40, 2, 10, 40000, 21, "low-latency"), /* 16_2_1 (mandatory) */
BAP_QOS("24_1_1", LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_7_5, false, 45, 2, 8, 40000, 32, "low-latency"), /* 24_1_1 */
BAP_QOS("24_2_1", LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_10, false, 60, 2, 10, 40000, 22, "low-latency"), /* 24_2_1 */
BAP_QOS("32_1_1", LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_7_5, false, 60, 2, 8, 40000, 33, "low-latency"), /* 32_1_1 */
BAP_QOS("32_2_1", LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_10, false, 80, 2, 10, 40000, 23, "low-latency"), /* 32_2_1 */
BAP_QOS("441_1_1", LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_7_5, true, 97, 5, 24, 40000, 34, "low-latency"), /* 441_1_1 */
BAP_QOS("441_2_1", LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_10, true, 130, 5, 31, 40000, 24, "low-latency"), /* 441_2_1 */
BAP_QOS("48_1_1", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 75, 5, 15, 40000, 35, "low-latency"), /* 48_1_1 */
BAP_QOS("48_2_1", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 100, 5, 20, 40000, 25, "low-latency"), /* 48_2_1 */
BAP_QOS("48_3_1", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 90, 5, 15, 40000, 36, "low-latency"), /* 48_3_1 */
BAP_QOS("48_4_1", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 120, 5, 20, 40000, 26, "low-latency"), /* 48_4_1 */
BAP_QOS("48_5_1", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 117, 5, 15, 40000, 37, "low-latency"), /* 48_5_1 */
BAP_QOS("48_6_1", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 155, 5, 20, 40000, 27, "low-latency"), /* 48_6_1 */
BAP_QOS("8_1_1", LC3_CONFIG_FREQ_8KHZ, LC3_CONFIG_DURATION_7_5, false, 26, 2, 8, 40000, 30), /* 8_1_1 */
BAP_QOS("8_2_1", LC3_CONFIG_FREQ_8KHZ, LC3_CONFIG_DURATION_10, false, 30, 2, 10, 40000, 20), /* 8_2_1 */
BAP_QOS("16_1_1", LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_7_5, false, 30, 2, 8, 40000, 31), /* 16_1_1 */
BAP_QOS("16_2_1", LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_10, false, 40, 2, 10, 40000, 21), /* 16_2_1 (mandatory) */
BAP_QOS("24_1_1", LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_7_5, false, 45, 2, 8, 40000, 32), /* 24_1_1 */
BAP_QOS("24_2_1", LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_10, false, 60, 2, 10, 40000, 22), /* 24_2_1 */
BAP_QOS("32_1_1", LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_7_5, false, 60, 2, 8, 40000, 33), /* 32_1_1 */
BAP_QOS("32_2_1", LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_10, false, 80, 2, 10, 40000, 23), /* 32_2_1 */
BAP_QOS("441_1_1", LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_7_5, true, 97, 5, 24, 40000, 34), /* 441_1_1 */
BAP_QOS("441_2_1", LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_10, true, 130, 5, 31, 40000, 24), /* 441_2_1 */
BAP_QOS("48_1_1", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 75, 5, 15, 40000, 35), /* 48_1_1 */
BAP_QOS("48_2_1", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 100, 5, 20, 40000, 25), /* 48_2_1 */
BAP_QOS("48_3_1", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 90, 5, 15, 40000, 36), /* 48_3_1 */
BAP_QOS("48_4_1", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 120, 5, 20, 40000, 26), /* 48_4_1 */
BAP_QOS("48_5_1", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 117, 5, 15, 40000, 37), /* 48_5_1 */
BAP_QOS("48_6_1", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 155, 5, 20, 40000, 27), /* 48_6_1 */
/* BAP v1.0.1 Table 5.2; high-reliability */
BAP_QOS("8_1_2", LC3_CONFIG_FREQ_8KHZ, LC3_CONFIG_DURATION_7_5, false, 26, 13, 75, 40000, 10, "high-reliability"), /* 8_1_2 */
BAP_QOS("8_2_2", LC3_CONFIG_FREQ_8KHZ, LC3_CONFIG_DURATION_10, false, 30, 13, 95, 40000, 0, "high-reliability"), /* 8_2_2 */
BAP_QOS("16_1_2", LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_7_5, false, 30, 13, 75, 40000, 11, "high-reliability"), /* 16_1_2 */
BAP_QOS("16_2_2", LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_10, false, 40, 13, 95, 40000, 1, "high-reliability"), /* 16_2_2 */
BAP_QOS("24_1_2", LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_7_5, false, 45, 13, 75, 40000, 12, "high-reliability"), /* 24_1_2 */
BAP_QOS("24_2_2", LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_10, false, 60, 13, 95, 40000, 2, "high-reliability"), /* 24_2_2 */
BAP_QOS("32_1_2", LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_7_5, false, 60, 13, 75, 40000, 13, "high-reliability"), /* 32_1_2 */
BAP_QOS("32_2_2", LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_10, false, 80, 13, 95, 40000, 3, "high-reliability"), /* 32_2_2 */
BAP_QOS("441_1_2", LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_7_5, true, 97, 13, 80, 40000, 54, "high-reliability"), /* 441_1_2 */
BAP_QOS("441_2_2", LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_10, true, 130, 13, 85, 40000, 44, "high-reliability"), /* 441_2_2 */
BAP_QOS("48_1_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 75, 13, 75, 40000, 55, "high-reliability"), /* 48_1_2 */
BAP_QOS("48_2_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 100, 13, 95, 40000, 45, "high-reliability"), /* 48_2_2 */
BAP_QOS("48_3_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 90, 13, 75, 40000, 56, "high-reliability"), /* 48_3_2 */
BAP_QOS("48_4_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 120, 13, 100, 40000, 46, "high-reliability"), /* 48_4_2 */
BAP_QOS("48_5_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 117, 13, 75, 40000, 57, "high-reliability"), /* 48_5_2 */
BAP_QOS("48_6_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 155, 13, 100, 40000, 47, "high-reliability"), /* 48_6_2 */
BAP_QOS("8_1_2", LC3_CONFIG_FREQ_8KHZ, LC3_CONFIG_DURATION_7_5, false, 26, 13, 75, 40000, 10), /* 8_1_2 */
BAP_QOS("8_2_2", LC3_CONFIG_FREQ_8KHZ, LC3_CONFIG_DURATION_10, false, 30, 13, 95, 40000, 0), /* 8_2_2 */
BAP_QOS("16_1_2", LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_7_5, false, 30, 13, 75, 40000, 11), /* 16_1_2 */
BAP_QOS("16_2_2", LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_10, false, 40, 13, 95, 40000, 1), /* 16_2_2 */
BAP_QOS("24_1_2", LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_7_5, false, 45, 13, 75, 40000, 12), /* 24_1_2 */
BAP_QOS("24_2_2", LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_10, false, 60, 13, 95, 40000, 2), /* 24_2_2 */
BAP_QOS("32_1_2", LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_7_5, false, 60, 13, 75, 40000, 13), /* 32_1_2 */
BAP_QOS("32_2_2", LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_10, false, 80, 13, 95, 40000, 3), /* 32_2_2 */
BAP_QOS("441_1_2", LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_7_5, true, 97, 13, 80, 40000, 14), /* 441_1_2 */
BAP_QOS("441_2_2", LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_10, true, 130, 13, 85, 40000, 4), /* 441_2_2 */
BAP_QOS("48_1_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 75, 13, 75, 40000, 15), /* 48_1_2 */
BAP_QOS("48_2_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 100, 13, 95, 40000, 5), /* 48_2_2 */
BAP_QOS("48_3_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 90, 13, 75, 40000, 16), /* 48_3_2 */
BAP_QOS("48_4_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 120, 13, 100, 40000, 6), /* 48_4_2 */
BAP_QOS("48_5_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 117, 13, 75, 40000, 17), /* 48_5_2 */
BAP_QOS("48_6_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 155, 13, 100, 40000, 7), /* 48_6_2 */
};
static const struct bap_qos bap_bcast_qos_configs[] = {
@ -149,40 +147,40 @@ static const struct bap_qos bap_bcast_qos_configs[] = {
* bigger frequency and sdu better */
/* BAP v1.0.1 Table 6.4; low-latency */
BAP_QOS("8_1_1", LC3_CONFIG_FREQ_8KHZ, LC3_CONFIG_DURATION_7_5, false, 26, 2, 8, 40000, 30, "low-latency"), /* 8_1_1 */
BAP_QOS("8_2_1", LC3_CONFIG_FREQ_8KHZ, LC3_CONFIG_DURATION_10, false, 30, 2, 10, 40000, 20, "low-latency"), /* 8_2_1 */
BAP_QOS("16_1_1", LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_7_5, false, 30, 2, 8, 40000, 31, "low-latency"), /* 16_1_1 */
BAP_QOS("16_2_1", LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_10, false, 40, 2, 10, 40000, 21, "low-latency"), /* 16_2_1 (mandatory) */
BAP_QOS("24_1_1", LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_7_5, false, 45, 2, 8, 40000, 32, "low-latency"), /* 24_1_1 */
BAP_QOS("24_2_1", LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_10, false, 60, 2, 10, 40000, 22, "low-latency"), /* 24_2_1 */
BAP_QOS("32_1_1", LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_7_5, false, 60, 2, 8, 40000, 33, "low-latency"), /* 32_1_1 */
BAP_QOS("32_2_1", LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_10, false, 80, 2, 10, 40000, 23, "low-latency"), /* 32_2_1 */
BAP_QOS("441_1_1", LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_7_5, true, 97, 4, 24, 40000, 34, "low-latency"), /* 441_1_1 */
BAP_QOS("441_2_1", LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_10, true, 130, 4, 31, 40000, 24, "low-latency"), /* 441_2_1 */
BAP_QOS("48_1_1", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 75, 4, 15, 40000, 35, "low-latency"), /* 48_1_1 */
BAP_QOS("48_2_1", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 100, 4, 20, 40000, 25, "low-latency"), /* 48_2_1 */
BAP_QOS("48_3_1", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 90, 4, 15, 40000, 36, "low-latency"), /* 48_3_1 */
BAP_QOS("48_4_1", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 120, 4, 20, 40000, 26, "low-latency"), /* 48_4_1 */
BAP_QOS("48_5_1", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 117, 4, 15, 40000, 37, "low-latency"), /* 48_5_1 */
BAP_QOS("48_6_1", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 155, 4, 20, 40000, 27, "low-latency"), /* 48_6_1 */
BAP_QOS("8_1_1", LC3_CONFIG_FREQ_8KHZ, LC3_CONFIG_DURATION_7_5, false, 26, 2, 8, 40000, 30), /* 8_1_1 */
BAP_QOS("8_2_1", LC3_CONFIG_FREQ_8KHZ, LC3_CONFIG_DURATION_10, false, 30, 2, 10, 40000, 20), /* 8_2_1 */
BAP_QOS("16_1_1", LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_7_5, false, 30, 2, 8, 40000, 31), /* 16_1_1 */
BAP_QOS("16_2_1", LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_10, false, 40, 2, 10, 40000, 21), /* 16_2_1 (mandatory) */
BAP_QOS("24_1_1", LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_7_5, false, 45, 2, 8, 40000, 32), /* 24_1_1 */
BAP_QOS("24_2_1", LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_10, false, 60, 2, 10, 40000, 22), /* 24_2_1 */
BAP_QOS("32_1_1", LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_7_5, false, 60, 2, 8, 40000, 33), /* 32_1_1 */
BAP_QOS("32_2_1", LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_10, false, 80, 2, 10, 40000, 23), /* 32_2_1 */
BAP_QOS("441_1_1", LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_7_5, true, 97, 4, 24, 40000, 34), /* 441_1_1 */
BAP_QOS("441_2_1", LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_10, true, 130, 4, 31, 40000, 24), /* 441_2_1 */
BAP_QOS("48_1_1", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 75, 4, 15, 40000, 35), /* 48_1_1 */
BAP_QOS("48_2_1", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 100, 4, 20, 40000, 25), /* 48_2_1 */
BAP_QOS("48_3_1", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 90, 4, 15, 40000, 36), /* 48_3_1 */
BAP_QOS("48_4_1", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 120, 4, 20, 40000, 26), /* 48_4_1 */
BAP_QOS("48_5_1", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 117, 4, 15, 40000, 37), /* 48_5_1 */
BAP_QOS("48_6_1", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 155, 4, 20, 40000, 27), /* 48_6_1 */
/* BAP v1.0.1 Table 6.4; high-reliability */
BAP_QOS("8_1_2", LC3_CONFIG_FREQ_8KHZ, LC3_CONFIG_DURATION_7_5, false, 26, 4, 45, 40000, 10, "high-reliability"), /* 8_1_2 */
BAP_QOS("8_2_2", LC3_CONFIG_FREQ_8KHZ, LC3_CONFIG_DURATION_10, false, 30, 4, 60, 40000, 0, "high-reliability"), /* 8_2_2 */
BAP_QOS("16_1_2", LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_7_5, false, 30, 4, 45, 40000, 11, "high-reliability"), /* 16_1_2 */
BAP_QOS("16_2_2", LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_10, false, 40, 4, 60, 40000, 1, "high-reliability"), /* 16_2_2 */
BAP_QOS("24_1_2", LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_7_5, false, 45, 4, 45, 40000, 12, "high-reliability"), /* 24_1_2 */
BAP_QOS("24_2_2", LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_10, false, 60, 4, 60, 40000, 2, "high-reliability"), /* 24_2_2 */
BAP_QOS("32_1_2", LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_7_5, false, 60, 4, 45, 40000, 13, "high-reliability"), /* 32_1_2 */
BAP_QOS("32_2_2", LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_10, false, 80, 4, 60, 40000, 3, "high-reliability"), /* 32_2_2 */
BAP_QOS("441_1_2", LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_7_5, true, 97, 4, 54, 40000, 14, "high-reliability"), /* 441_1_2 */
BAP_QOS("441_2_2", LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_10, true, 130, 4, 60, 40000, 4, "high-reliability"), /* 441_2_2 */
BAP_QOS("48_1_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 75, 4, 50, 40000, 15, "high-reliability"), /* 48_1_2 */
BAP_QOS("48_2_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 100, 4, 65, 40000, 5, "high-reliability"), /* 48_2_2 */
BAP_QOS("48_3_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 90, 4, 50, 40000, 16, "high-reliability"), /* 48_3_2 */
BAP_QOS("48_4_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 120, 4, 65, 40000, 6, "high-reliability"), /* 48_4_2 */
BAP_QOS("48_5_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 117, 4, 50, 40000, 17, "high-reliability"), /* 48_5_2 */
BAP_QOS("48_6_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 155, 4, 65, 40000, 7, "high-reliability"), /* 48_6_2 */
BAP_QOS("8_1_2", LC3_CONFIG_FREQ_8KHZ, LC3_CONFIG_DURATION_7_5, false, 26, 4, 45, 40000, 10), /* 8_1_2 */
BAP_QOS("8_2_2", LC3_CONFIG_FREQ_8KHZ, LC3_CONFIG_DURATION_10, false, 30, 4, 60, 40000, 0), /* 8_2_2 */
BAP_QOS("16_1_2", LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_7_5, false, 30, 4, 45, 40000, 11), /* 16_1_2 */
BAP_QOS("16_2_2", LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_10, false, 40, 4, 60, 40000, 1), /* 16_2_2 */
BAP_QOS("24_1_2", LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_7_5, false, 45, 4, 45, 40000, 12), /* 24_1_2 */
BAP_QOS("24_2_2", LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_10, false, 60, 4, 60, 40000, 2), /* 24_2_2 */
BAP_QOS("32_1_2", LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_7_5, false, 60, 4, 45, 40000, 13), /* 32_1_2 */
BAP_QOS("32_2_2", LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_10, false, 80, 4, 60, 40000, 3), /* 32_2_2 */
BAP_QOS("441_1_2", LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_7_5, true, 97, 4, 54, 40000, 14), /* 441_1_2 */
BAP_QOS("441_2_2", LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_10, true, 130, 4, 60, 40000, 4), /* 441_2_2 */
BAP_QOS("48_1_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 75, 4, 50, 40000, 15), /* 48_1_2 */
BAP_QOS("48_2_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 100, 4, 65, 40000, 5), /* 48_2_2 */
BAP_QOS("48_3_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 90, 4, 50, 40000, 16), /* 48_3_2 */
BAP_QOS("48_4_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 120, 4, 65, 40000, 6), /* 48_4_2 */
BAP_QOS("48_5_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 117, 4, 50, 40000, 17), /* 48_5_2 */
BAP_QOS("48_6_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 155, 4, 65, 40000, 7), /* 48_6_2 */
};
static unsigned int get_rate_mask(uint8_t rate) {
@ -478,9 +476,6 @@ static bool select_bap_qos(struct bap_qos *conf,
else if (c.priority < conf->priority)
continue;
if (s->force_target_latency && !spa_streq(s->force_target_latency, c.tag))
continue;
if (s->retransmission >= 0)
c.retransmission = s->retransmission;
if (s->latency >= 0)
@ -849,9 +844,6 @@ static void parse_settings(struct settings *s, const struct spa_dict *settings,
if ((str = spa_dict_lookup(settings, "bluez5.bap.preset")))
s->qos_name = strdup(str);
if ((str = spa_dict_lookup(settings, "bluez5.bap.force-target-latency")))
s->force_target_latency = strdup(str);
if (spa_atou32(spa_dict_lookup(settings, "bluez5.bap.rtn"), &value, 0))
s->retransmission = value;
@ -889,11 +881,11 @@ static void parse_settings(struct settings *s, const struct spa_dict *settings,
spa_debugc(&debug_ctx->ctx,
"BAP LC3 settings: preset:%s rtn:%d latency:%d delay:%d framing:%d "
"locations:%x chnalloc:%x sink:%d duplex:%d force-target-latency:%s",
"locations:%x chnalloc:%x sink:%d duplex:%d",
s->qos_name ? s->qos_name : "auto",
s->retransmission, s->latency, (int)s->delay, s->framing,
(unsigned int)s->locations, (unsigned int)s->channel_allocation,
(int)s->sink, (int)s->duplex, s->force_target_latency);
(int)s->sink, (int)s->duplex);
}
static void free_config_data(struct config_data *d)
@ -901,7 +893,6 @@ static void free_config_data(struct config_data *d)
if (!d)
return;
free(d->settings.qos_name);
free(d->settings.force_target_latency);
free(d);
}
@ -1503,10 +1494,6 @@ static int codec_get_bis_config(const struct media_codec *codec, uint8_t *caps,
struct ltv_writer writer = LTV_WRITER(caps, *caps_size);
const struct bap_qos *preset = NULL;
uint32_t retransmissions = 0;
uint8_t rtn_manual_set = 0;
uint32_t max_transport_latency = 0;
uint32_t presentation_delay = 0;
*caps_size = 0;
if (settings) {
@ -1515,14 +1502,6 @@ static int codec_get_bis_config(const struct media_codec *codec, uint8_t *caps,
sscanf(settings->items[i].value, "%"PRIu32, &channel_allocation);
if (spa_streq(settings->items[i].key, "preset"))
preset_name = settings->items[i].value;
if (spa_streq(settings->items[i].key, "max_transport_latency"))
spa_atou32(settings->items[i].value, &max_transport_latency, 0);
if (spa_streq(settings->items[i].key, "presentation_delay"))
spa_atou32(settings->items[i].value, &presentation_delay, 0);
if (spa_streq(settings->items[i].key, "retransmissions")) {
spa_atou32(settings->items[i].value, &retransmissions, 0);
rtn_manual_set = 1;
}
}
}
@ -1549,9 +1528,9 @@ static int codec_get_bis_config(const struct media_codec *codec, uint8_t *caps,
else
qos->framing = 0;
qos->sdu = preset->framelen * get_channel_count(channel_allocation);
qos->retransmission = rtn_manual_set ? retransmissions : preset->retransmission;
qos->latency = max_transport_latency ? max_transport_latency : preset->latency;
qos->delay = presentation_delay ? presentation_delay : preset->delay;
qos->retransmission = preset->retransmission;
qos->latency = preset->latency;
qos->delay = preset->delay;
qos->phy = 2;
qos->interval = (preset->frame_duration == LC3_CONFIG_DURATION_7_5 ? 7500 : 10000);

View file

@ -148,7 +148,6 @@ struct spa_bt_monitor {
struct spa_bt_remote_endpoint {
struct spa_list link;
struct spa_list device_link;
struct spa_list adapter_link;
struct spa_bt_monitor *monitor;
char *path;
char *transport_path;
@ -156,7 +155,6 @@ struct spa_bt_remote_endpoint {
char *uuid;
unsigned int codec;
struct spa_bt_device *device;
struct spa_bt_adapter *adapter;
uint8_t *capabilities;
size_t capabilities_len;
uint8_t *metadata;
@ -188,22 +186,14 @@ struct spa_bt_metadata {
uint8_t value[METADATA_MAX_LEN - 1];
};
#define RTN_MAX 0x1E
#define MAX_TRANSPORT_LATENCY_MIN 0x5
#define MAX_TRANSPORT_LATENCY_MAX 0x0FA0
struct spa_bt_bis {
struct spa_list link;
char qos_preset[255];
int retransmissions;
int rtn_manual_set;
int max_transport_latency;
int channel_allocation;
struct spa_list metadata_list;
};
#define BROADCAST_CODE_LEN 16
#define BD_ADDR_STR_LEN 17
struct spa_bt_big {
struct spa_list link;
@ -212,7 +202,6 @@ struct spa_bt_big {
struct spa_list bis_list;
int big_id;
int sync_factor;
char adapter[BD_ADDR_STR_LEN + 3];
};
/*
@ -594,35 +583,18 @@ static enum spa_bt_profile get_codec_profile(const struct media_codec *codec,
{
switch (direction) {
case SPA_BT_MEDIA_SOURCE:
if (codec->kind == MEDIA_CODEC_A2DP)
return SPA_BT_PROFILE_A2DP_SOURCE;
else if (codec->kind == MEDIA_CODEC_BAP)
return SPA_BT_PROFILE_BAP_SOURCE;
else if (codec->kind == MEDIA_CODEC_HFP)
return SPA_BT_PROFILE_HEADSET_AUDIO;
else
return SPA_BT_PROFILE_NULL;
return codec->kind == MEDIA_CODEC_BAP ? SPA_BT_PROFILE_BAP_SOURCE : SPA_BT_PROFILE_A2DP_SOURCE;
case SPA_BT_MEDIA_SINK:
if (codec->kind == MEDIA_CODEC_A2DP)
return SPA_BT_PROFILE_A2DP_SINK;
else if (codec->kind == MEDIA_CODEC_ASHA)
if (codec->kind == MEDIA_CODEC_ASHA)
return SPA_BT_PROFILE_ASHA_SINK;
else if (codec->kind == MEDIA_CODEC_BAP)
return SPA_BT_PROFILE_BAP_SINK;
else if (codec->kind == MEDIA_CODEC_HFP)
return SPA_BT_PROFILE_HEADSET_AUDIO;
else
return SPA_BT_PROFILE_NULL;
return SPA_BT_PROFILE_A2DP_SINK;
case SPA_BT_MEDIA_SOURCE_BROADCAST:
if (codec->kind == MEDIA_CODEC_BAP)
return SPA_BT_PROFILE_BAP_BROADCAST_SOURCE;
else
return SPA_BT_PROFILE_NULL;
case SPA_BT_MEDIA_SINK_BROADCAST:
if (codec->kind == MEDIA_CODEC_BAP)
return SPA_BT_PROFILE_BAP_BROADCAST_SINK;
else
return SPA_BT_PROFILE_NULL;
default:
spa_assert_not_reached();
}
@ -744,12 +716,14 @@ static const char *bap_features_get_uuid(struct bap_features *feat, size_t i)
/** Get feature name at \a i, or NULL if uuid doesn't match */
static const char *bap_features_get_name(struct bap_features *feat, size_t i, const char *uuid)
{
char *pos;
if (i >= feat->dict.n_items)
return NULL;
if (!spa_streq(feat->dict.items[i].value, uuid))
return NULL;
const char *pos = strchr(feat->dict.items[i].key, ':');
pos = strchr(feat->dict.items[i].key, ':');
if (!pos)
return NULL;
return pos + 1;
@ -760,11 +734,6 @@ static void bap_features_clear(struct bap_features *feat)
spa_zero(*feat);
}
const struct spa_dict *get_device_codec_settings(struct spa_bt_device *device, bool bap)
{
return bap ? device->settings : &device->monitor->global_settings;
}
static DBusHandlerResult endpoint_select_configuration(DBusConnection *conn, DBusMessage *m, void *userdata)
{
struct spa_bt_monitor *monitor = userdata;
@ -1358,6 +1327,7 @@ static struct spa_bt_adapter *adapter_find(struct spa_bt_monitor *monitor, const
static int parse_modalias(const char *modalias, uint16_t *source, uint16_t *vendor,
uint16_t *product, uint16_t *version)
{
char *pos;
unsigned int src, i, j, k;
if (spa_strstartswith(modalias, "bluetooth:"))
@ -1367,7 +1337,7 @@ static int parse_modalias(const char *modalias, uint16_t *source, uint16_t *vend
else
return -EINVAL;
const char *pos = strchr(modalias, ':');
pos = strchr(modalias, ':');
if (pos == NULL)
return -EINVAL;
@ -1664,8 +1634,6 @@ static struct spa_bt_adapter *adapter_create(struct spa_bt_monitor *monitor, con
d->monitor = monitor;
d->path = strdup(path);
spa_list_init(&d->remote_endpoint_list);
spa_list_prepend(&monitor->adapter_list, &d->link);
adapter_init_bus_type(monitor, d);
@ -1680,7 +1648,6 @@ static void adapter_free(struct spa_bt_adapter *adapter)
{
struct spa_bt_monitor *monitor = adapter->monitor;
struct spa_bt_device *d, *td;
struct spa_bt_remote_endpoint *ep, *tep;
spa_log_debug(monitor->log, "%p", adapter);
@ -1689,13 +1656,6 @@ static void adapter_free(struct spa_bt_adapter *adapter)
if (d->adapter == adapter)
device_free(d);
spa_list_for_each_safe(ep, tep, &adapter->remote_endpoint_list, adapter_link) {
if (ep->adapter == adapter) {
spa_list_remove(&ep->adapter_link);
ep->adapter = NULL;
}
}
spa_bt_player_destroy(adapter->dummy_player);
spa_list_remove(&adapter->link);
@ -2798,21 +2758,18 @@ bool spa_bt_device_supports_media_codec(struct spa_bt_device *device, const stru
{ SPA_BLUETOOTH_AUDIO_CODEC_FASTSTREAM_DUPLEX, SPA_BT_FEATURE_A2DP_DUPLEX },
};
bool is_a2dp = codec->kind == MEDIA_CODEC_A2DP;
bool is_bap = codec->kind == MEDIA_CODEC_BAP;
size_t i;
if (codec->kind == MEDIA_CODEC_HFP) {
if (!(profile & SPA_BT_PROFILE_HEADSET_AUDIO))
return false;
if (!is_media_codec_enabled(monitor, codec))
return false;
return spa_bt_backend_supports_codec(monitor->backend, device, codec->codec_id) == 1;
}
codec_target_profile = get_codec_target_profile(monitor, codec);
if (!codec_target_profile)
return false;
if (codec->kind == MEDIA_CODEC_HFP) {
if (!(profile & SPA_BT_PROFILE_HEADSET_AUDIO))
return false;
return spa_bt_backend_supports_codec(monitor->backend, device, codec->codec_id) == 1;
}
if (!device->adapter->a2dp_application_registered && is_a2dp) {
/* Codec switching not supported: only plain SBC allowed */
return (codec->codec_id == A2DP_CODEC_SBC && spa_streq(codec->name, "sbc") &&
@ -2842,8 +2799,7 @@ bool spa_bt_device_supports_media_codec(struct spa_bt_device *device, const stru
continue;
if (media_codec_check_caps(codec, ep->codec, ep->capabilities, ep->capabilities_len,
&ep->monitor->default_audio_info,
get_device_codec_settings(device, is_bap)))
&ep->monitor->default_audio_info, &monitor->global_settings))
return true;
}
@ -3059,31 +3015,20 @@ static int remote_endpoint_update_props(struct spa_bt_remote_endpoint *remote_en
}
else if (spa_streq(key, "Device")) {
struct spa_bt_device *device;
struct spa_bt_adapter *adapter;
device = spa_bt_device_find(monitor, value);
adapter = adapter_find(monitor, value);
if (device == NULL)
goto next;
if (device != NULL) {
spa_log_debug(monitor->log, "remote_endpoint %p: device -> %p", remote_endpoint, device);
if (remote_endpoint->device != device) {
if (remote_endpoint->device != NULL)
spa_list_remove(&remote_endpoint->device_link);
remote_endpoint->device = device;
if (device != NULL)
spa_list_append(&device->remote_endpoint_list, &remote_endpoint->device_link);
}
}
if (adapter != NULL) {
spa_log_debug(monitor->log, "remote_endpoint %p: adapter -> %p", remote_endpoint, adapter);
if (remote_endpoint->adapter != adapter) {
if (remote_endpoint->adapter != NULL)
spa_list_remove(&remote_endpoint->adapter_link);
remote_endpoint->adapter = adapter;
spa_list_append(&adapter->remote_endpoint_list, &remote_endpoint->adapter_link);
}
}
} else if (spa_streq(key, "Transport")) {
/* For ASHA */
free(remote_endpoint->transport_path);
@ -3157,13 +3102,11 @@ static int remote_endpoint_update_props(struct spa_bt_remote_endpoint *remote_en
spa_log_debug(monitor->log, "remote_endpoint %p: %s=%"PRIu64, remote_endpoint, key, remote_endpoint->hisyncid);
} else if (spa_streq(key, "SupportedFeatures")) {
DBusMessageIter iter;
if (!check_iter_signature(&it[1], "a{sv}"))
goto next;
dbus_message_iter_recurse(&it[1], &iter);
parse_supported_features(monitor, &iter, &remote_endpoint->bap_features);
dbus_message_iter_recurse(&it[1], &it[2]);
parse_supported_features(monitor, &it[2], &remote_endpoint->bap_features);
} else {
unhandled:
spa_log_debug(monitor->log, "remote_endpoint %p: unhandled key %s", remote_endpoint, key);
@ -3219,9 +3162,6 @@ static void remote_endpoint_free(struct spa_bt_remote_endpoint *remote_endpoint)
if (remote_endpoint->device)
spa_list_remove(&remote_endpoint->device_link);
if (remote_endpoint->adapter)
spa_list_remove(&remote_endpoint->adapter_link);
bap_features_clear(&remote_endpoint->bap_features);
spa_list_remove(&remote_endpoint->link);
@ -3442,12 +3382,8 @@ int spa_bt_transport_acquire(struct spa_bt_transport *transport, bool optional)
if (!transport->acquired)
res = spa_bt_transport_impl(transport, acquire, 0, optional);
else {
/* keepalive */
transport->acquire_refcount = 1;
spa_bt_transport_emit_state_changed(transport, transport->state, transport->state);
return 0;
}
else
res = 0;
if (res >= 0) {
transport->acquire_refcount = 1;
@ -4715,7 +4651,7 @@ static bool codec_switch_check_endpoint(struct spa_bt_remote_endpoint *ep,
if (!media_codec_check_caps(codec, ep->codec, ep->capabilities, ep->capabilities_len,
&ep->device->monitor->default_audio_info,
get_device_codec_settings(ep->device, codec->kind == MEDIA_CODEC_BAP)))
&ep->device->monitor->global_settings))
return false;
if (ep_profile & (SPA_BT_PROFILE_A2DP_SINK | SPA_BT_PROFILE_BAP_SINK)) {
@ -6199,11 +6135,8 @@ static void configure_bis(struct spa_bt_monitor *monitor,
struct bap_codec_qos qos;
struct spa_bt_metadata *metadata_entry;
struct spa_dict settings;
struct spa_dict_item setting_items[4];
uint32_t n_items = 0;
struct spa_dict_item setting_items[2];
char channel_allocation[64] = {0};
char retransmissions[3] = {0};
char max_transport_latency[5] = {0};
int mse = 0;
int options = 0;
@ -6228,27 +6161,12 @@ static void configure_bis(struct spa_bt_monitor *monitor,
metadata_size += metadata_entry->length - 1;
}
spa_log_debug(monitor->log, "bis->channel_allocation %d", bis->channel_allocation);
if (bis->channel_allocation) {
if (bis->channel_allocation)
spa_scnprintf(channel_allocation, sizeof(channel_allocation), "%"PRIu32, bis->channel_allocation);
}
spa_log_debug(monitor->log, "bis->rtn_manual_set %d", bis->rtn_manual_set);
spa_log_debug(monitor->log, "bis->retransmissions %d", bis->retransmissions);
if (bis->rtn_manual_set) {
spa_scnprintf(retransmissions, sizeof(retransmissions), "%"PRIu8, bis->retransmissions);
setting_items[n_items++] = SPA_DICT_ITEM_INIT("retransmissions", retransmissions);
}
spa_log_debug(monitor->log, "bis->max_transport_latency %d", bis->max_transport_latency);
if (bis->max_transport_latency) {
spa_scnprintf(max_transport_latency, sizeof(max_transport_latency), "%"PRIu32, bis->max_transport_latency);
setting_items[n_items++] = SPA_DICT_ITEM_INIT("max_transport_latency", max_transport_latency);
}
setting_items[n_items++] = SPA_DICT_ITEM_INIT("preset", bis->qos_preset);
setting_items[n_items++] = SPA_DICT_ITEM_INIT("channel_allocation", channel_allocation);
settings = SPA_DICT_INIT(setting_items, n_items);
setting_items[0] = SPA_DICT_ITEM_INIT("channel_allocation", channel_allocation);
setting_items[1] = SPA_DICT_ITEM_INIT("preset", bis->qos_preset);
settings = SPA_DICT_INIT(setting_items, 2);
caps_size = sizeof(caps);
ret = codec->get_bis_config(codec, caps, &caps_size, &settings, &qos);
@ -6316,7 +6234,6 @@ static void configure_bis(struct spa_bt_monitor *monitor,
}
static void configure_bcast_source(struct spa_bt_monitor *monitor,
struct spa_bt_remote_endpoint *ep,
const struct media_codec *codec,
DBusConnection *conn,
const char *object_path,
@ -6325,24 +6242,8 @@ static void configure_bcast_source(struct spa_bt_monitor *monitor,
{
struct spa_bt_big *big;
struct spa_bt_bis *bis;
/* Configure each BIS from a BIG */
spa_list_for_each(big, &monitor->bcast_source_config_list, link) {
/* Apply per adapter configuration if BIG has an adapter value stated,
* otherwise apply the BIG config angnostically to each adapter
*/
if ((strlen(big->adapter) > 0) && (ep->adapter != NULL)) {
if (!ep->adapter->address) {
spa_log_warn(monitor->log, "this adapter is not associated with any BD address. BIG config will applied agnostically to any adapter!");
continue;
}
if (strcasecmp(ep->adapter->address, big->adapter))
continue;
spa_log_debug(monitor->log, "configuring BIG for adapter=%s", big->adapter);
}
spa_list_for_each(bis, &big->bis_list, link) {
configure_bis(monitor, codec, conn, object_path, interface_name,
big, bis, local_endpoint);
@ -6466,7 +6367,7 @@ static void interface_added(struct spa_bt_monitor *monitor,
}
if (local_endpoint != NULL)
configure_bcast_source(monitor, ep, monitor->media_codecs[i], conn, object_path, interface_name, local_endpoint);
configure_bcast_source(monitor, monitor->media_codecs[i], conn, object_path, interface_name, local_endpoint);
}
}
}
@ -7121,10 +7022,6 @@ static void parse_broadcast_source_config(struct spa_bt_monitor *monitor, const
goto parse_failed;
memcpy(big_entry->broadcast_code, bcode, strlen(bcode));
spa_log_debug(monitor->log, "big_entry->broadcast_code %s", big_entry->broadcast_code);
} else if (spa_streq(key, "adapter")) {
if (spa_json_get_string(&it[0], big_entry->adapter, sizeof(big_entry->adapter)) <= 0)
goto parse_failed;
spa_log_debug(monitor->log, "big_entry->adapter %s", big_entry->adapter);
} else if (spa_streq(key, "encryption")) {
if (spa_json_get_bool(&it[0], &big_entry->encryption) <= 0)
goto parse_failed;
@ -7151,20 +7048,6 @@ static void parse_broadcast_source_config(struct spa_bt_monitor *monitor, const
if (spa_json_get_string(&it[1], bis_entry->qos_preset, sizeof(bis_entry->qos_preset)) <= 0)
goto parse_failed;
spa_log_debug(monitor->log, "bis_entry->qos_preset %s", bis_entry->qos_preset);
} else if (spa_streq(bis_key, "retransmissions")) {
if (spa_json_get_int(&it[2], &bis_entry->retransmissions) <= 0)
goto parse_failed;
if (bis_entry->retransmissions > RTN_MAX)
goto parse_failed;
bis_entry->rtn_manual_set = 1;
spa_log_debug(monitor->log, "bis_entry->retransmissions %d", bis_entry->retransmissions);
} else if (spa_streq(bis_key, "max_transport_latency")) {
if (spa_json_get_int(&it[2], &bis_entry->max_transport_latency) <= 0)
goto parse_failed;
if (bis_entry->max_transport_latency < MAX_TRANSPORT_LATENCY_MIN &&
bis_entry->max_transport_latency > MAX_TRANSPORT_LATENCY_MAX)
goto parse_failed;
spa_log_debug(monitor->log, "bis_entry->max_transport_latency %d", bis_entry->max_transport_latency);
} else if (spa_streq(bis_key, "audio_channel_allocation")) {
if (spa_json_get_int(&it[1], &bis_entry->channel_allocation) <= 0)
goto parse_failed;

View file

@ -59,8 +59,6 @@ enum device_profile {
DEVICE_PROFILE_OFF = 0,
DEVICE_PROFILE_AG,
DEVICE_PROFILE_A2DP,
DEVICE_PROFILE_A2DP_AUTO_PREFER_QUALITY,
DEVICE_PROFILE_A2DP_AUTO_PREFER_LATENCY,
DEVICE_PROFILE_HSP_HFP,
DEVICE_PROFILE_BAP,
DEVICE_PROFILE_BAP_SINK,
@ -69,12 +67,6 @@ enum device_profile {
DEVICE_PROFILE_LAST,
};
enum codec_order {
CODEC_ORDER_NONE = 0,
CODEC_ORDER_QUALITY,
CODEC_ORDER_LATENCY,
};
enum {
ROUTE_INPUT = 0,
ROUTE_OUTPUT,
@ -212,89 +204,9 @@ static bool profile_is_bap(enum device_profile profile)
return false;
}
static bool profile_is_a2dp(enum device_profile profile)
{
switch (profile) {
case DEVICE_PROFILE_A2DP:
case DEVICE_PROFILE_A2DP_AUTO_PREFER_QUALITY:
case DEVICE_PROFILE_A2DP_AUTO_PREFER_LATENCY:
return true;
default:
break;
}
return false;
}
static size_t get_media_codec_quality_priority (const struct media_codec *mc)
{
/* From lowest quality to highest quality */
static const enum spa_bluetooth_audio_codec quality_priorities[] = {
SPA_BLUETOOTH_AUDIO_CODEC_START,
SPA_BLUETOOTH_AUDIO_CODEC_SBC,
SPA_BLUETOOTH_AUDIO_CODEC_APTX,
SPA_BLUETOOTH_AUDIO_CODEC_AAC,
SPA_BLUETOOTH_AUDIO_CODEC_OPUS_G,
SPA_BLUETOOTH_AUDIO_CODEC_LC3PLUS_HR,
SPA_BLUETOOTH_AUDIO_CODEC_APTX_HD,
SPA_BLUETOOTH_AUDIO_CODEC_LDAC,
};
size_t i;
for (i = 0; i < SPA_N_ELEMENTS(quality_priorities); ++i) {
if (quality_priorities[i] == mc->id)
return i;
}
return 0;
}
static size_t get_media_codec_latency_priority (const struct media_codec *mc)
{
/* From highest latency to lowest latency */
static const enum spa_bluetooth_audio_codec latency_priorities[] = {
SPA_BLUETOOTH_AUDIO_CODEC_START,
SPA_BLUETOOTH_AUDIO_CODEC_SBC,
SPA_BLUETOOTH_AUDIO_CODEC_APTX,
SPA_BLUETOOTH_AUDIO_CODEC_OPUS_G,
SPA_BLUETOOTH_AUDIO_CODEC_FASTSTREAM_DUPLEX,
SPA_BLUETOOTH_AUDIO_CODEC_FASTSTREAM,
SPA_BLUETOOTH_AUDIO_CODEC_APTX_LL_DUPLEX,
SPA_BLUETOOTH_AUDIO_CODEC_APTX_LL,
};
size_t i;
for (i = 0; i < SPA_N_ELEMENTS(latency_priorities); ++i) {
if (latency_priorities[i] == mc->id)
return i;
}
return 0;
}
static int media_codec_quality_cmp(const void *a, const void *b) {
const struct media_codec *ca = *(const struct media_codec **)a;
const struct media_codec *cb = *(const struct media_codec **)b;
size_t ca_prio = get_media_codec_quality_priority (ca);
size_t cb_prio = get_media_codec_quality_priority (cb);
if (ca_prio > cb_prio) return -1;
if (ca_prio < cb_prio) return 1;
return 0;
}
static int media_codec_latency_cmp(const void *a, const void *b) {
const struct media_codec *ca = *(const struct media_codec **)a;
const struct media_codec *cb = *(const struct media_codec **)b;
size_t ca_prio = get_media_codec_latency_priority (ca);
size_t cb_prio = get_media_codec_latency_priority (cb);
if (ca_prio > cb_prio) return -1;
if (ca_prio < cb_prio) return 1;
return 0;
}
static void get_media_codecs(struct impl *this, enum codec_order order, enum spa_bluetooth_audio_codec id, const struct media_codec **codecs, size_t size)
static void get_media_codecs(struct impl *this, enum spa_bluetooth_audio_codec id, const struct media_codec **codecs, size_t size)
{
const struct media_codec * const *c;
size_t n = 0;
spa_assert(size > 0);
spa_assert(this->supported_codecs);
@ -304,24 +216,12 @@ static void get_media_codecs(struct impl *this, enum codec_order order, enum spa
continue;
if ((*c)->id == id || id == 0) {
codecs[n++] = *c;
*codecs++ = *c;
--size;
}
}
codecs[n] = NULL;
switch (order) {
case CODEC_ORDER_QUALITY:
qsort(codecs, n, sizeof(struct media_codec *), media_codec_quality_cmp);
break;
case CODEC_ORDER_LATENCY:
qsort(codecs, n, sizeof(struct media_codec *), media_codec_latency_cmp);
break;
case CODEC_ORDER_NONE:
default:
break;
}
*codecs = NULL;
}
static const struct media_codec *get_supported_media_codec(struct impl *this, enum spa_bluetooth_audio_codec id,
@ -480,8 +380,6 @@ static bool node_update_volume_from_transport(struct node *node, bool reset)
/* PW is the controller for remote device. */
if (impl->profile != DEVICE_PROFILE_A2DP
&& impl->profile != DEVICE_PROFILE_A2DP_AUTO_PREFER_QUALITY
&& impl->profile != DEVICE_PROFILE_A2DP_AUTO_PREFER_LATENCY
&& impl->profile != DEVICE_PROFILE_BAP
&& impl->profile != DEVICE_PROFILE_BAP_SINK
&& impl->profile != DEVICE_PROFILE_BAP_SOURCE
@ -1364,8 +1262,6 @@ static int emit_nodes(struct impl *this)
}
break;
case DEVICE_PROFILE_A2DP:
case DEVICE_PROFILE_A2DP_AUTO_PREFER_QUALITY:
case DEVICE_PROFILE_A2DP_AUTO_PREFER_LATENCY:
if (this->bt_dev->connected_profiles & SPA_BT_PROFILE_A2DP_SOURCE) {
t = find_transport(this, SPA_BT_PROFILE_A2DP_SOURCE);
if (t) {
@ -1568,13 +1464,13 @@ static int set_profile(struct impl *this, uint32_t profile, enum spa_bluetooth_a
* XXX: source-only case, as it will only switch the sink, and we only
* XXX: list the sink codecs here. TODO: fix this
*/
if ((profile_is_a2dp (profile) || (profile_is_bap(profile) && is_bap_client(this)))
if ((profile == DEVICE_PROFILE_A2DP || (profile_is_bap(profile) && is_bap_client(this)))
&& !(this->bt_dev->connected_profiles & SPA_BT_PROFILE_A2DP_SOURCE)) {
int ret;
const struct media_codec *codecs[64];
uint32_t profiles;
get_media_codecs(this, CODEC_ORDER_NONE, codec, codecs, SPA_N_ELEMENTS(codecs));
get_media_codecs(this, codec, codecs, SPA_N_ELEMENTS(codecs));
this->switching_codec = true;
@ -1589,15 +1485,7 @@ static int set_profile(struct impl *this, uint32_t profile, enum spa_bluetooth_a
profiles = this->bt_dev->profiles & SPA_BT_PROFILE_BAP_DUPLEX;
break;
case DEVICE_PROFILE_A2DP:
profiles = this->bt_dev->connected_profiles & SPA_BT_PROFILE_A2DP_DUPLEX;
break;
case DEVICE_PROFILE_A2DP_AUTO_PREFER_QUALITY:
get_media_codecs(this, CODEC_ORDER_QUALITY, 0, codecs, SPA_N_ELEMENTS(codecs));
profiles = this->bt_dev->connected_profiles & SPA_BT_PROFILE_A2DP_DUPLEX;
break;
case DEVICE_PROFILE_A2DP_AUTO_PREFER_LATENCY:
get_media_codecs(this, CODEC_ORDER_LATENCY, 0, codecs, SPA_N_ELEMENTS(codecs));
profiles = this->bt_dev->connected_profiles & SPA_BT_PROFILE_A2DP_DUPLEX;
profiles = this->bt_dev->profiles & SPA_BT_PROFILE_A2DP_DUPLEX;
break;
default:
profiles = 0;
@ -1758,8 +1646,6 @@ static void profiles_changed(void *userdata, uint32_t connected_change)
nodes_changed);
break;
case DEVICE_PROFILE_A2DP:
case DEVICE_PROFILE_A2DP_AUTO_PREFER_QUALITY:
case DEVICE_PROFILE_A2DP_AUTO_PREFER_LATENCY:
nodes_changed = (connected_change & SPA_BT_PROFILE_A2DP_DUPLEX);
spa_log_debug(this->log, "profiles changed: A2DP nodes changed: %d",
nodes_changed);
@ -1915,8 +1801,6 @@ static uint32_t profile_direction_mask(struct impl *this, uint32_t index, enum s
switch (index) {
case DEVICE_PROFILE_A2DP:
case DEVICE_PROFILE_A2DP_AUTO_PREFER_QUALITY:
case DEVICE_PROFILE_A2DP_AUTO_PREFER_LATENCY:
if (device->connected_profiles & SPA_BT_PROFILE_A2DP_SINK)
have_output = true;
@ -1966,8 +1850,6 @@ static uint32_t get_profile_from_index(struct impl *this, uint32_t index, uint32
switch (profile) {
case DEVICE_PROFILE_OFF:
case DEVICE_PROFILE_AG:
case DEVICE_PROFILE_A2DP_AUTO_PREFER_QUALITY:
case DEVICE_PROFILE_A2DP_AUTO_PREFER_LATENCY:
*codec = 0;
*next = (profile + 1) << 16;
return profile;
@ -2002,8 +1884,6 @@ static uint32_t get_index_from_profile(struct impl *this, uint32_t profile, enum
switch (profile) {
case DEVICE_PROFILE_OFF:
case DEVICE_PROFILE_AG:
case DEVICE_PROFILE_A2DP_AUTO_PREFER_QUALITY:
case DEVICE_PROFILE_A2DP_AUTO_PREFER_LATENCY:
return (profile << 16);
case DEVICE_PROFILE_ASHA:
@ -2097,37 +1977,15 @@ static void set_initial_profile(struct impl *this)
t = find_transport(this, i);
if (t) {
if (i == SPA_BT_PROFILE_A2DP_SOURCE || i == SPA_BT_PROFILE_BAP_SOURCE) {
if (i == SPA_BT_PROFILE_A2DP_SOURCE || i == SPA_BT_PROFILE_BAP_SOURCE)
this->profile = DEVICE_PROFILE_AG;
this->props.codec = t->media_codec->id;
} else if (i == SPA_BT_PROFILE_BAP_SINK) {
else if (i == SPA_BT_PROFILE_BAP_SINK)
this->profile = DEVICE_PROFILE_BAP;
this->props.codec = t->media_codec->id;
} else if (i == SPA_BT_PROFILE_ASHA_SINK) {
else if (i == SPA_BT_PROFILE_ASHA_SINK)
this->profile = DEVICE_PROFILE_ASHA;
this->props.codec = t->media_codec->id;
} else {
const struct media_codec *codecs[64];
const struct media_codec *quality_codec = NULL;
int j;
get_media_codecs(this, CODEC_ORDER_QUALITY, 0, codecs, SPA_N_ELEMENTS(codecs));
for (j = 0; codecs[j] != NULL; ++j) {
if (codecs[j]->kind == MEDIA_CODEC_A2DP) {
quality_codec = codecs[j];
break;
}
}
if (quality_codec) {
this->profile = DEVICE_PROFILE_A2DP_AUTO_PREFER_QUALITY;
this->props.codec = quality_codec->id;
} else {
else
this->profile = DEVICE_PROFILE_A2DP;
this->props.codec = t->media_codec->id;
}
}
spa_log_debug(this->log, "initial profile media profile:%d codec:%d",
this->profile, this->props.codec);
return;
@ -2265,36 +2123,6 @@ static struct spa_pod *build_profile(struct impl *this, struct spa_pod_builder *
n_source++;
break;
}
case DEVICE_PROFILE_A2DP_AUTO_PREFER_QUALITY:
case DEVICE_PROFILE_A2DP_AUTO_PREFER_LATENCY:
{
uint32_t profile;
/* make this device profile visible only if there is an A2DP sink */
profile = device->connected_profiles & (SPA_BT_PROFILE_A2DP_SINK | SPA_BT_PROFILE_A2DP_SOURCE);
if (!(profile & SPA_BT_PROFILE_A2DP_SINK))
return NULL;
switch (profile_index) {
case DEVICE_PROFILE_A2DP_AUTO_PREFER_QUALITY:
name = "a2dp-auto-prefer-quality";
desc = _("Auto: Prefer Quality (A2DP)");
priority = 255;
break;
case DEVICE_PROFILE_A2DP_AUTO_PREFER_LATENCY:
name = "a2dp-auto-prefer-latency";
desc = _("Auto: Prefer Latency (A2DP)");
priority = 254;
break;
default:
return NULL;
}
n_sink++;
if (this->autoswitch_routes && (device->connected_profiles & SPA_BT_PROFILE_HEADSET_HEAD_UNIT))
n_source++;
break;
}
case DEVICE_PROFILE_BAP_SINK:
case DEVICE_PROFILE_BAP_SOURCE:
/* These are client-only */
@ -2496,8 +2324,6 @@ static bool profile_has_route(uint32_t profile, uint32_t route)
case DEVICE_PROFILE_AG:
break;
case DEVICE_PROFILE_A2DP:
case DEVICE_PROFILE_A2DP_AUTO_PREFER_QUALITY:
case DEVICE_PROFILE_A2DP_AUTO_PREFER_LATENCY:
switch (route) {
case ROUTE_INPUT:
case ROUTE_OUTPUT:
@ -2797,7 +2623,7 @@ static struct spa_pod *build_route(struct impl *this, struct spa_pod_builder *b,
spa_pod_builder_array(b, sizeof(uint32_t), SPA_TYPE_Id,
node->n_channels, node->channels);
if ((profile_is_a2dp (this->profile) || profile_is_bap(this->profile)) &&
if ((this->profile == DEVICE_PROFILE_A2DP || profile_is_bap(this->profile)) &&
(dev & SINK_ID_FLAG)) {
spa_pod_builder_prop(b, SPA_PROP_latencyOffsetNsec, 0);
spa_pod_builder_long(b, node->latency_offset);
@ -2833,7 +2659,7 @@ next:
c = this->supported_codecs[*j];
if (!(profile_is_a2dp (this->profile) && c->kind == MEDIA_CODEC_A2DP) &&
if (!(this->profile == DEVICE_PROFILE_A2DP && c->kind == MEDIA_CODEC_A2DP) &&
!(profile_is_bap(this->profile) && c->kind == MEDIA_CODEC_BAP) &&
!(this->profile == DEVICE_PROFILE_HSP_HFP && c->kind == MEDIA_CODEC_HFP) &&
!(this->profile == DEVICE_PROFILE_ASHA && c->kind == MEDIA_CODEC_ASHA))
@ -3414,7 +3240,7 @@ static int impl_set_param(void *object,
return 0;
}
if (profile_is_a2dp (this->profile) || profile_is_bap(this->profile) ||
if (this->profile == DEVICE_PROFILE_A2DP || profile_is_bap(this->profile) ||
this->profile == DEVICE_PROFILE_ASHA || this->profile == DEVICE_PROFILE_HSP_HFP) {
size_t j;
for (j = 0; j < this->supported_codec_count; ++j) {

View file

@ -136,7 +136,6 @@ extern "C" {
#define PROFILE_HFP_HF "/Profile/HFPHF"
#define HSP_HS_DEFAULT_CHANNEL 3
#define HFP_SCO_DEFAULT_DATAPATH 0
#define SOURCE_ID_BLUETOOTH 0x1 /* Bluetooth SIG */
#define SOURCE_ID_USB 0x2 /* USB Implementer's Forum */
@ -379,7 +378,6 @@ struct spa_bt_adapter {
unsigned int has_media1_interface:1;
unsigned int le_audio_bcast_supported:1;
unsigned int tx_timestamping_supported:1;
struct spa_list remote_endpoint_list;
};
enum spa_bt_form_factor {

View file

@ -1784,7 +1784,7 @@ static uint32_t get_samples(struct impl *this, int64_t *duration_ns)
static void update_target_latency(struct impl *this)
{
struct port *port = &this->port;
int32_t target = 0;
int32_t target;
int samples;
if (this->transport == NULL || !port->have_format)
@ -1803,7 +1803,7 @@ static void update_target_latency(struct impl *this)
*/
if (this->decode_buffer_target)
target = this->decode_buffer_target;
else if (this->transport->iso_io)
else
target = spa_bt_iso_io_get_source_target_latency(this->transport->iso_io);
spa_bt_decode_buffer_set_target_latency(&port->buffer, target);

View file

@ -23,6 +23,7 @@
#include <spa/utils/ringbuffer.h>
#include <spa/monitor/device.h>
#include <spa/control/control.h>
#include <spa/control/ump-utils.h>
#include <spa/node/node.h>
#include <spa/node/utils.h>
@ -449,7 +450,7 @@ static void midi_event_recv(void *user_data, uint16_t timestamp, uint8_t *data,
struct impl *this = user_data;
struct port *port = &this->ports[PORT_OUT];
struct time_sync *sync = &port->sync;
uint64_t time;
uint64_t time, state = 0;
int res;
spa_assert(size > 0);
@ -459,12 +460,20 @@ static void midi_event_recv(void *user_data, uint16_t timestamp, uint8_t *data,
spa_log_trace(this->log, "%p: event:0x%x size:%d timestamp:%d time:%"PRIu64"",
this, (int)data[0], (int)size, (int)timestamp, (uint64_t)time);
res = midi_event_ringbuffer_push(&this->event_rbuf, time, data, size);
while (size > 0) {
uint32_t ump[4];
int ump_size = spa_ump_from_midi(&data, &size,
ump, sizeof(ump), 0, &state);
if (ump_size <= 0)
break;
res = midi_event_ringbuffer_push(&this->event_rbuf, time, (uint8_t*)ump, ump_size);
if (res < 0) {
midi_event_ringbuffer_init(&this->event_rbuf);
spa_log_warn(this->log, "%p: MIDI receive buffer overflow: %s",
this, spa_strerror(res));
}
}
}
static int unacquire_port(struct port *port)
@ -704,7 +713,7 @@ static int process_output(struct impl *this)
offset = time * this->rate / SPA_NSEC_PER_SEC;
offset = SPA_CLAMP(offset, 0u, this->duration - 1);
spa_pod_builder_control(&port->builder, offset, SPA_CONTROL_Midi);
spa_pod_builder_control(&port->builder, offset, SPA_CONTROL_UMP);
buf = spa_pod_builder_reserve_bytes(&port->builder, size);
if (buf) {
midi_event_ringbuffer_pop(&this->event_rbuf, buf, size);
@ -777,14 +786,22 @@ static int write_data(struct impl *this, struct spa_data *d)
time = 0;
while (spa_pod_parser_get_control_body(&parser, &c, &c_body) >= 0) {
const uint8_t *event = c_body;
uint32_t size = c.value.size;
int size;
uint8_t event[32];
const uint32_t *ump = c_body;
size_t ump_size = c.value.size;
uint64_t state = 0;
if (c.type != SPA_CONTROL_Midi)
if (c.type != SPA_CONTROL_UMP)
continue;
time = SPA_MAX(time, this->current_time + c.offset * SPA_NSEC_PER_SEC / this->rate);
while (ump_size > 0) {
size = spa_ump_to_midi(&ump, &ump_size, event, sizeof(event), &state);
if (size <= 0)
break;
spa_log_trace(this->log, "%p: output event:0x%x time:%"PRIu64, this,
(size > 0) ? event[0] : 0, time);
@ -800,6 +817,7 @@ static int write_data(struct impl *this, struct spa_data *d)
}
} while (res);
}
}
if ((res = flush_packet(this)) < 0)
return res;

View file

@ -72,7 +72,6 @@ struct impl {
struct spa_node node;
uint32_t quantum_limit;
uint32_t control_types;
struct spa_log *log;
@ -474,9 +473,9 @@ static int port_set_format(void *object,
if (!port->have_format) {
this->n_formats++;
port->have_format = true;
port->types = types == 0 ? this->control_types : types;
spa_log_debug(this->log, "%p: set format on port %d:%d types:%08x %08x",
this, direction, port_id, port->types, this->control_types);
port->types = types;
spa_log_debug(this->log, "%p: set format on port %d:%d",
this, direction, port_id);
}
}
port->info.change_mask |= SPA_PORT_CHANGE_MASK_PARAMS;
@ -590,7 +589,7 @@ static int do_port_set_io(struct spa_loop *loop, bool async, uint32_t seq,
port->io[0] = info->data;
port->io[1] = info->data;
}
if (port->direction == SPA_DIRECTION_INPUT && !port->active) {
if (!port->active) {
spa_list_append(&info->impl->mix_list, &port->mix_link);
port->active = true;
}
@ -956,8 +955,6 @@ impl_init(const struct spa_handle_factory *factory,
}
this->quantum_limit = 8192;
/* by default we convert to midi1 */
this->control_types = 1u<<SPA_CONTROL_Midi;
for (i = 0; info && i < info->n_items; i++) {
const char *k = info->items[i].key;
@ -965,14 +962,6 @@ impl_init(const struct spa_handle_factory *factory,
if (spa_streq(k, "clock.quantum-limit")) {
spa_atou32(s, &this->quantum_limit, 0);
}
else if (spa_streq(k, "control.ump")) {
if (spa_atob(s))
/* we convert to UMP when forced */
this->control_types = 1u<<SPA_CONTROL_UMP;
else
/* when unforced we let both midi1 and UMP through */
this->control_types = 0;
}
}
spa_hook_list_init(&this->hooks);

View file

@ -69,7 +69,6 @@ struct spa_fga_descriptor {
void (*connect_port) (void *instance, unsigned long port, void *data);
void (*control_changed) (void *instance);
void (*control_sync) (void *instance);
void (*activate) (void *instance);
void (*deactivate) (void *instance);

View file

@ -19,7 +19,6 @@
#include <spa/utils/string.h>
#include <spa/utils/json.h>
#include <spa/support/cpu.h>
#include <spa/support/loop.h>
#include <spa/support/plugin-loader.h>
#include <spa/param/latency-utils.h>
#include <spa/param/tag-utils.h>
@ -81,6 +80,7 @@ struct descriptor {
unsigned long *output;
unsigned long *control;
unsigned long *notify;
float *default_control;
};
struct port {
@ -94,9 +94,6 @@ struct port {
uint32_t n_links;
uint32_t external;
bool control_initialized;
float control_current;
float control_data[MAX_HNDL];
float *audio_data[MAX_HNDL];
void *audio_mem[MAX_HNDL];
@ -196,9 +193,6 @@ struct graph {
struct volume volume[2];
uint32_t default_inputs;
uint32_t default_outputs;
uint32_t n_inputs;
uint32_t n_outputs;
uint32_t inputs_position[MAX_CHANNELS];
@ -222,7 +216,6 @@ struct impl {
struct spa_cpu *cpu;
struct spa_fga_dsp *dsp;
struct spa_plugin_loader *loader;
struct spa_loop *data_loop;
uint64_t info_all;
struct spa_filter_graph_info info;
@ -264,23 +257,16 @@ static void emit_filter_graph_info(struct impl *impl, bool full)
impl->info.change_mask = impl->info_all;
if (impl->info.change_mask || full) {
char n_inputs[64], n_outputs[64], latency[64];
char n_default_inputs[64], n_default_outputs[64];
struct spa_dict_item items[6];
struct spa_dict dict = SPA_DICT(items, 0);
char in_pos[MAX_CHANNELS * 8];
char out_pos[MAX_CHANNELS * 8];
/* these are the current graph inputs/outputs */
snprintf(n_inputs, sizeof(n_inputs), "%d", impl->graph.n_inputs);
snprintf(n_outputs, sizeof(n_outputs), "%d", impl->graph.n_outputs);
/* these are the default number of graph inputs/outputs */
snprintf(n_default_inputs, sizeof(n_default_inputs), "%d", impl->graph.default_inputs);
snprintf(n_default_outputs, sizeof(n_default_outputs), "%d", impl->graph.default_outputs);
items[dict.n_items++] = SPA_DICT_ITEM("n_inputs", n_inputs);
items[dict.n_items++] = SPA_DICT_ITEM("n_outputs", n_outputs);
items[dict.n_items++] = SPA_DICT_ITEM("n_default_inputs", n_default_inputs);
items[dict.n_items++] = SPA_DICT_ITEM("n_default_outputs", n_default_outputs);
if (graph->n_inputs_position) {
print_channels(in_pos, sizeof(in_pos),
graph->n_inputs_position, graph->inputs_position);
@ -353,6 +339,12 @@ static int impl_process(void *object,
return 0;
}
static float get_default(struct impl *impl, struct descriptor *desc, uint32_t p)
{
struct spa_fga_port *port = &desc->desc->ports[p];
return port->def;
}
static struct node *find_node(struct graph *graph, const char *name)
{
struct node *node;
@ -441,20 +433,6 @@ static struct port *find_port(struct node *node, const char *name, int descripto
return NULL;
}
static void get_ranges(struct impl *impl, struct spa_fga_port *p,
float *def, float *min, float *max)
{
uint32_t rate = impl->rate ? impl->rate : DEFAULT_RATE;
*def = p->def;
*min = p->min;
*max = p->max;
if (p->hint & SPA_FGA_HINT_SAMPLE_RATE) {
*def *= rate;
*min *= rate;
*max *= rate;
}
}
static int impl_enum_prop_info(void *object, uint32_t idx, struct spa_pod_builder *b,
struct spa_pod **param)
{
@ -469,6 +447,7 @@ static int impl_enum_prop_info(void *object, uint32_t idx, struct spa_pod_builde
struct spa_fga_port *p;
float def, min, max;
char name[512];
uint32_t rate = impl->rate ? impl->rate : DEFAULT_RATE;
if (idx >= graph->n_control)
return 0;
@ -479,7 +458,15 @@ static int impl_enum_prop_info(void *object, uint32_t idx, struct spa_pod_builde
d = desc->desc;
p = &d->ports[port->p];
get_ranges(impl, p, &def, &min, &max);
if (p->hint & SPA_FGA_HINT_SAMPLE_RATE) {
def = p->def * rate;
min = p->min * rate;
max = p->max * rate;
} else {
def = p->def;
min = p->min;
max = p->max;
}
if (node->name[0] != '\0')
snprintf(name, sizeof(name), "%s:%s", node->name, p->name);
@ -578,58 +565,41 @@ static int impl_get_props(void *object, struct spa_pod_builder *b, struct spa_po
return 1;
}
static int port_id_set_control_value(struct port *port, uint32_t id, float value)
static int port_set_control_value(struct port *port, float *value, uint32_t id)
{
struct node *node = port->node;
struct impl *impl = node->graph->impl;
struct descriptor *desc = node->desc;
struct spa_fga_port *p = &desc->desc->ports[port->p];
float old;
bool changed;
old = port->control_data[id];
port->control_data[id] = value;
port->control_data[id] = value ? *value : desc->default_control[port->idx];
spa_log_info(impl->log, "control %d %d ('%s') from %f to %f", port->idx, id,
p->name, old, value);
desc->desc->ports[port->p].name, old, port->control_data[id]);
changed = old != port->control_data[id];
node->control_changed |= changed;
return changed ? 1 : 0;
}
static int port_set_control_value(struct port *port, float *value)
{
struct node *node = port->node;
struct impl *impl = node->graph->impl;
struct spa_fga_port *p;
float v, def, min, max;
uint32_t i;
int count = 0;
p = &node->desc->desc->ports[port->p];
get_ranges(impl, p, &def, &min, &max);
v = SPA_CLAMP(value ? *value : def, min, max);
port->control_current = v;
port->control_initialized = true;
for (i = 0; i < node->n_hndl; i++)
count += port_id_set_control_value(port, i, v);
return count;
}
static int set_control_value(struct node *node, const char *name, float *value)
{
struct port *port;
int count = 0;
uint32_t i, n_hndl;
port = find_port(node, name, SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL);
if (port == NULL)
return -ENOENT;
return port_set_control_value(port, value);
/* if we don't have any instances yet, set the first control value, we will
* copy to other instances later */
n_hndl = SPA_MAX(1u, port->node->n_hndl);
for (i = 0; i < n_hndl; i++)
count += port_set_control_value(port, value, i);
return count;
}
static int parse_params(struct graph *graph, const struct spa_pod *pod)
@ -700,46 +670,21 @@ static int impl_reset(void *object)
return 0;
}
static int
do_emit_node_control_sync(struct spa_loop *loop, bool async, uint32_t seq, const void *data,
size_t size, void *user_data)
static void node_control_changed(struct node *node)
{
struct impl *impl = user_data;
struct graph *graph = &impl->graph;
struct node *node;
uint32_t i;
spa_list_for_each(node, &graph->node_list, link) {
const struct spa_fga_descriptor *d = node->desc->desc;
if (!node->control_changed || d->control_sync == NULL)
continue;
for (i = 0; i < node->n_hndl; i++) {
if (node->hndl[i] != NULL)
d->control_sync(node->hndl[i]);
}
}
return 0;
}
static void emit_node_control_changed(struct impl *impl)
{
struct graph *graph = &impl->graph;
struct node *node;
uint32_t i;
spa_loop_locked(impl->data_loop, do_emit_node_control_sync, 1, NULL, 0, impl);
spa_list_for_each(node, &graph->node_list, link) {
const struct spa_fga_descriptor *d = node->desc->desc;
if (!node->control_changed)
continue;
if (d->control_changed != NULL) {
return;
for (i = 0; i < node->n_hndl; i++) {
if (node->hndl[i] != NULL)
if (node->hndl[i] == NULL)
continue;
if (d->control_changed)
d->control_changed(node->hndl[i]);
}
}
node->control_changed = false;
}
}
static int sync_volume(struct graph *graph, struct volume *vol)
@ -761,7 +706,7 @@ static int sync_volume(struct graph *graph, struct volume *vol)
v = v * (vol->max[n_port] - vol->min[n_port]) + vol->min[n_port];
n_hndl = SPA_MAX(1u, p->node->n_hndl);
res += port_id_set_control_value(p, i % n_hndl, v);
res += port_set_control_value(p, &v, i % n_hndl);
}
return res;
}
@ -853,7 +798,11 @@ static int impl_set_props(void *object, enum spa_direction direction, const stru
spa_pod_dynamic_builder_clean(&b);
if (changed > 0) {
emit_node_control_changed(impl);
struct node *node;
spa_list_for_each(node, &graph->node_list, link)
node_control_changed(node);
spa_filter_graph_emit_props_changed(&impl->hooks, SPA_DIRECTION_INPUT);
}
return 0;
@ -976,6 +925,7 @@ static void descriptor_unref(struct descriptor *desc)
free(desc->input);
free(desc->output);
free(desc->control);
free(desc->default_control);
free(desc->notify);
free(desc);
}
@ -986,7 +936,7 @@ static struct descriptor *descriptor_load(struct impl *impl, const char *type,
struct plugin *pl;
struct descriptor *desc;
const struct spa_fga_descriptor *d;
uint32_t n_input, n_output, n_control, n_notify;
uint32_t i, n_input, n_output, n_control, n_notify;
unsigned long p;
int res;
@ -1040,6 +990,7 @@ static struct descriptor *descriptor_load(struct impl *impl, const char *type,
desc->input = calloc(n_input, sizeof(unsigned long));
desc->output = calloc(n_output, sizeof(unsigned long));
desc->control = calloc(n_control, sizeof(unsigned long));
desc->default_control = calloc(n_control, sizeof(float));
desc->notify = calloc(n_notify, sizeof(unsigned long));
for (p = 0; p < d->n_ports; p++) {
@ -1058,8 +1009,8 @@ static struct descriptor *descriptor_load(struct impl *impl, const char *type,
}
} else if (SPA_FGA_IS_PORT_CONTROL(fp->flags)) {
if (SPA_FGA_IS_PORT_INPUT(fp->flags)) {
spa_log_info(impl->log, "using port %lu ('%s') as control %d %f/%f/%f", p,
fp->name, desc->n_control, fp->def, fp->min, fp->max);
spa_log_info(impl->log, "using port %lu ('%s') as control %d", p,
fp->name, desc->n_control);
desc->control[desc->n_control++] = p;
}
else if (SPA_FGA_IS_PORT_OUTPUT(fp->flags)) {
@ -1069,6 +1020,17 @@ static struct descriptor *descriptor_load(struct impl *impl, const char *type,
}
}
}
if (desc->n_input == 0 && desc->n_output == 0 && desc->n_control == 0 && desc->n_notify == 0) {
spa_log_error(impl->log, "plugin has no input and no output ports");
res = -ENOTSUP;
goto exit;
}
for (i = 0; i < desc->n_control; i++) {
p = desc->control[i];
desc->default_control[i] = get_default(impl, desc, p);
spa_log_info(impl->log, "control %d ('%s') default to %f", i,
d->ports[p].name, desc->default_control[i]);
}
spa_list_append(&pl->descriptor_list, &desc->link);
return desc;
@ -1448,6 +1410,7 @@ static int load_node(struct graph *graph, struct spa_json *json)
port->external = SPA_ID_INVALID;
port->p = desc->control[i];
spa_list_init(&port->link_list);
port->control_data[0] = desc->default_control[i];
}
for (i = 0; i < desc->n_notify; i++) {
struct port *port = &node->notify_port[i];
@ -1645,7 +1608,6 @@ static int impl_activate(void *object, const struct spa_dict *props)
goto error;
}
}
node->control_changed = true;
}
/* then link ports */
@ -1719,10 +1681,10 @@ static int impl_activate(void *object, const struct spa_dict *props)
for (i = 0; i < node->n_hndl; i++) {
if (d->activate)
d->activate(node->hndl[i]);
if (node->control_changed && d->control_changed)
d->control_changed(node->hndl[i]);
}
}
emit_node_control_changed(impl);
/* calculate latency */
sort_reset(graph);
while ((node = sort_next_node(graph)) != NULL) {
@ -1822,7 +1784,7 @@ static int setup_graph(struct graph *graph)
struct port *port;
struct graph_port *gp;
struct graph_hndl *gh;
uint32_t i, j, n, n_input, n_output, n_hndl = 0, n_out_hndl;
uint32_t i, j, n, n_input, n_output, n_hndl = 0;
int res;
struct descriptor *desc;
const struct spa_fga_descriptor *d;
@ -1834,8 +1796,19 @@ static int setup_graph(struct graph *graph)
first = spa_list_first(&graph->node_list, struct node, link);
last = spa_list_last(&graph->node_list, struct node, link);
n_input = graph->default_inputs;
n_output = graph->default_outputs;
/* calculate the number of inputs and outputs into the graph.
* If we have a list of inputs/outputs, just use them. Otherwise
* we count all input ports of the first node and all output
* ports of the last node */
if (graph->n_input_names != 0)
n_input = graph->n_input_names;
else
n_input = first->desc->n_input;
if (graph->n_output_names != 0)
n_output = graph->n_output_names;
else
n_output = last->desc->n_output;
/* we allow unconnected ports when not explicitly given and the nodes support
* NULL data */
@ -1843,11 +1816,16 @@ static int setup_graph(struct graph *graph)
SPA_FLAG_IS_SET(first->desc->desc->flags, SPA_FGA_DESCRIPTOR_SUPPORTS_NULL_DATA) &&
SPA_FLAG_IS_SET(last->desc->desc->flags, SPA_FGA_DESCRIPTOR_SUPPORTS_NULL_DATA);
if (n_input == 0)
n_input = n_output;
if (n_output == 0)
n_output = n_input;
if (n_input == 0) {
spa_log_error(impl->log, "no inputs");
res = -EINVAL;
goto error;
}
if (n_output == 0) {
spa_log_error(impl->log, "no outputs");
res = -EINVAL;
goto error;
}
if (graph->n_inputs == 0)
graph->n_inputs = impl->info.n_inputs;
if (graph->n_inputs == 0)
@ -1858,14 +1836,12 @@ static int setup_graph(struct graph *graph)
/* compare to the requested number of inputs and duplicate the
* graph n_hndl times when needed. */
n_hndl = n_input ? graph->n_inputs / n_input : 1;
n_hndl = graph->n_inputs / n_input;
if (graph->n_outputs == 0)
graph->n_outputs = n_output * n_hndl;
n_out_hndl = n_output ? graph->n_outputs / n_output : 1;
if (n_hndl != n_out_hndl) {
if (n_hndl != graph->n_outputs / n_output) {
spa_log_error(impl->log, "invalid ports. The input stream has %1$d ports and "
"the filter has %2$d inputs. The output stream has %3$d ports "
"and the filter has %4$d outputs. input:%1$d / input:%2$d != "
@ -2053,9 +2029,11 @@ static int setup_graph(struct graph *graph)
}
}
for (i = 0; i < desc->n_control; i++) {
/* any default values for the controls are set in the first instance
* of the control data. Duplicate this to the other instances now. */
struct port *port = &node->control_port[i];
port_set_control_value(port,
port->control_initialized ? &port->control_current : NULL);
for (j = 1; j < n_hndl; j++)
port->control_data[j] = port->control_data[0];
}
}
res = 0;
@ -2105,7 +2083,6 @@ static int load_graph(struct graph *graph, const struct spa_dict *props)
struct spa_json inputs, outputs, *pinputs = NULL, *poutputs = NULL;
struct spa_json ivolumes, ovolumes, *pivolumes = NULL, *povolumes = NULL;
struct spa_json nodes, *pnodes = NULL, links, *plinks = NULL;
struct node *first, *last;
const char *json, *val;
char key[256];
int res, len;
@ -2255,25 +2232,6 @@ static int load_graph(struct graph *graph, const struct spa_dict *props)
}
if ((res = setup_graph_controls(graph)) < 0)
return res;
first = spa_list_first(&graph->node_list, struct node, link);
last = spa_list_last(&graph->node_list, struct node, link);
/* calculate the number of inputs and outputs into the graph.
* If we have a list of inputs/outputs, just use them. Otherwise
* we count all input ports of the first node and all output
* ports of the last node */
if (graph->n_input_names != 0)
graph->default_inputs = graph->n_input_names;
else
graph->default_inputs = first->desc->n_input;
if (graph->n_output_names != 0)
graph->default_outputs = graph->n_output_names;
else
graph->default_outputs = last->desc->n_output;
return 0;
}
@ -2370,7 +2328,6 @@ impl_init(const struct spa_handle_factory *factory,
spa_log_topic_init(impl->log, &log_topic);
impl->cpu = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_CPU);
impl->data_loop = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_DataLoop);
impl->max_align = spa_cpu_get_max_align(impl->cpu);
impl->dsp = spa_fga_dsp_new(impl->cpu ? spa_cpu_get_flags(impl->cpu) : 0);

View file

@ -14,14 +14,12 @@
#include <sys/wait.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <time.h>
#include <spa/utils/json.h>
#include <spa/utils/result.h>
#include <spa/utils/cleanup.h>
#include <spa/support/cpu.h>
#include <spa/support/log.h>
#include <spa/support/loop.h>
#include <spa/plugins/audioconvert/resample.h>
#include <spa/debug/log.h>
@ -543,12 +541,7 @@ static void bq_run(void *Instance, unsigned long samples)
struct biquad *bq = &impl->bq;
float *out = impl->port[0];
float *in = impl->port[1];
spa_fga_dsp_biquad_run(impl->dsp, bq, 1, 0, &out, (const float **)&in, 1, samples);
}
static void bq_control_sync(void * Instance)
{
struct builtin *impl = Instance;
if (impl->type == BQ_NONE) {
float b0, b1, b2, a0, a1, a2;
b0 = impl->port[5][0];
@ -568,6 +561,7 @@ static void bq_control_sync(void * Instance)
if (impl->freq != freq || impl->Q != Q || impl->gain != gain)
bq_freq_update(impl, impl->type, freq, Q, gain);
}
spa_fga_dsp_biquad_run(impl->dsp, bq, 1, 0, &out, (const float **)&in, 1, samples);
}
/** bq_lowpass */
@ -579,7 +573,6 @@ static const struct spa_fga_descriptor bq_lowpass_desc = {
.instantiate = bq_instantiate,
.connect_port = builtin_connect_port,
.control_sync = bq_control_sync,
.activate = bq_activate,
.run = bq_run,
.cleanup = builtin_cleanup,
@ -594,7 +587,6 @@ static const struct spa_fga_descriptor bq_highpass_desc = {
.instantiate = bq_instantiate,
.connect_port = builtin_connect_port,
.control_sync = bq_control_sync,
.activate = bq_activate,
.run = bq_run,
.cleanup = builtin_cleanup,
@ -609,7 +601,6 @@ static const struct spa_fga_descriptor bq_bandpass_desc = {
.instantiate = bq_instantiate,
.connect_port = builtin_connect_port,
.control_sync = bq_control_sync,
.activate = bq_activate,
.run = bq_run,
.cleanup = builtin_cleanup,
@ -624,7 +615,6 @@ static const struct spa_fga_descriptor bq_lowshelf_desc = {
.instantiate = bq_instantiate,
.connect_port = builtin_connect_port,
.control_sync = bq_control_sync,
.activate = bq_activate,
.run = bq_run,
.cleanup = builtin_cleanup,
@ -639,7 +629,6 @@ static const struct spa_fga_descriptor bq_highshelf_desc = {
.instantiate = bq_instantiate,
.connect_port = builtin_connect_port,
.control_sync = bq_control_sync,
.activate = bq_activate,
.run = bq_run,
.cleanup = builtin_cleanup,
@ -654,7 +643,6 @@ static const struct spa_fga_descriptor bq_peaking_desc = {
.instantiate = bq_instantiate,
.connect_port = builtin_connect_port,
.control_sync = bq_control_sync,
.activate = bq_activate,
.run = bq_run,
.cleanup = builtin_cleanup,
@ -669,7 +657,6 @@ static const struct spa_fga_descriptor bq_notch_desc = {
.instantiate = bq_instantiate,
.connect_port = builtin_connect_port,
.control_sync = bq_control_sync,
.activate = bq_activate,
.run = bq_run,
.cleanup = builtin_cleanup,
@ -685,7 +672,6 @@ static const struct spa_fga_descriptor bq_allpass_desc = {
.instantiate = bq_instantiate,
.connect_port = builtin_connect_port,
.control_sync = bq_control_sync,
.activate = bq_activate,
.run = bq_run,
.cleanup = builtin_cleanup,
@ -700,7 +686,6 @@ static const struct spa_fga_descriptor bq_raw_desc = {
.instantiate = bq_instantiate,
.connect_port = builtin_connect_port,
.control_sync = bq_control_sync,
.activate = bq_activate,
.run = bq_run,
.cleanup = builtin_cleanup,
@ -1467,7 +1452,6 @@ static struct spa_fga_port clamp_ports[] = {
{ .index = 3,
.name = "Control",
.flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL,
.def = 0.0f, .min = -FLT_MAX, .max = FLT_MAX
},
{ .index = 4,
.name = "Min",
@ -1525,7 +1509,6 @@ static struct spa_fga_port linear_ports[] = {
{ .index = 3,
.name = "Control",
.flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL,
.def = 0.0f, .min = -FLT_MAX, .max = FLT_MAX
},
{ .index = 4,
.name = "Mult",
@ -1593,7 +1576,6 @@ static struct spa_fga_port recip_ports[] = {
{ .index = 3,
.name = "Control",
.flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL,
.def = 0.0f, .min = -FLT_MAX, .max = FLT_MAX
},
};
@ -1643,7 +1625,6 @@ static struct spa_fga_port exp_ports[] = {
{ .index = 3,
.name = "Control",
.flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL,
.def = 0.0f, .min = -FLT_MAX, .max = FLT_MAX
},
{ .index = 4,
.name = "Base",
@ -1701,7 +1682,6 @@ static struct spa_fga_port log_ports[] = {
{ .index = 3,
.name = "Control",
.flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL,
.def = 0.0f, .min = -FLT_MAX, .max = FLT_MAX
},
{ .index = 4,
.name = "Base",
@ -2491,12 +2471,10 @@ static struct spa_fga_port ramp_ports[] = {
{ .index = 1,
.name = "Start",
.flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL,
.def = 0.0f, .min = -FLT_MAX, .max = FLT_MAX
},
{ .index = 2,
.name = "Stop",
.flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL,
.def = 1.0f, .min = -FLT_MAX, .max = FLT_MAX
},
{ .index = 3,
.name = "Current",
@ -2505,7 +2483,6 @@ static struct spa_fga_port ramp_ports[] = {
{ .index = 4,
.name = "Duration (s)",
.flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL,
.def = 1.0f, .min = 0.0f, .max = FLT_MAX
},
};
@ -2665,7 +2642,6 @@ static struct spa_fga_port debug_ports[] = {
{ .index = 2,
.name = "Control",
.flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL,
.def = 0.0f, .min = -FLT_MAX, .max = FLT_MAX
},
{ .index = 3,
.name = "Notify",
@ -3012,7 +2988,7 @@ static struct spa_fga_port noisegate_ports[] = {
{ .index = 2,
.name = "Level",
.flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL,
.def = NAN, .min = -FLT_MAX, .max = FLT_MAX
.def = NAN
},
{ .index = 3,
.name = "Open Threshold",
@ -3139,137 +3115,6 @@ static const struct spa_fga_descriptor noisegate_desc = {
.cleanup = builtin_cleanup,
};
/* busy */
struct busy_impl {
struct plugin *plugin;
struct spa_fga_dsp *dsp;
struct spa_log *log;
unsigned long rate;
float wait_scale;
float cpu_scale;
};
static void *busy_instantiate(const struct spa_fga_plugin *plugin, const struct spa_fga_descriptor * Descriptor,
unsigned long SampleRate, int index, const char *config)
{
struct plugin *pl = SPA_CONTAINER_OF(plugin, struct plugin, plugin);
struct busy_impl *impl;
struct spa_json it[1];
const char *val;
char key[256];
float wait_percent = 0.0f, cpu_percent = 0.0f;
int len;
if (config != NULL) {
if (spa_json_begin_object(&it[0], config, strlen(config)) <= 0) {
spa_log_error(pl->log, "busy:config must be an object");
return NULL;
}
while ((len = spa_json_object_next(&it[0], key, sizeof(key), &val)) > 0) {
if (spa_streq(key, "wait-percent")) {
if (spa_json_parse_float(val, len, &wait_percent) <= 0) {
spa_log_error(pl->log, "busy:wait-percent requires a number");
return NULL;
}
} else if (spa_streq(key, "cpu-percent")) {
if (spa_json_parse_float(val, len, &cpu_percent) <= 0) {
spa_log_error(pl->log, "busy:cpu-percent requires a number");
return NULL;
}
} else {
spa_log_warn(pl->log, "busy: ignoring config key: '%s'", key);
}
}
if (wait_percent <= 0.0f)
wait_percent = 0.0f;
if (cpu_percent <= 0.0f)
cpu_percent = 0.0f;
}
impl = calloc(1, sizeof(*impl));
if (impl == NULL)
return NULL;
impl->plugin = pl;
impl->dsp = pl->dsp;
impl->log = pl->log;
impl->rate = SampleRate;
impl->wait_scale = wait_percent * SPA_NSEC_PER_SEC / (100.0f * SampleRate);
impl->cpu_scale = cpu_percent * SPA_NSEC_PER_SEC / (100.0f * SampleRate);
spa_log_info(impl->log, "wait-percent:%f cpu-percent:%f", wait_percent, cpu_percent);
return impl;
}
static void busy_run(void * Instance, unsigned long SampleCount)
{
struct busy_impl *impl = Instance;
struct timespec ts;
uint64_t busy_nsec;
if (impl->wait_scale > 0.0f) {
busy_nsec = (uint64_t)(impl->wait_scale * SampleCount);
ts.tv_sec = busy_nsec / SPA_NSEC_PER_SEC;
ts.tv_nsec = busy_nsec % SPA_NSEC_PER_SEC;
clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);
}
if (impl->cpu_scale > 0.0f) {
clock_gettime(CLOCK_MONOTONIC, &ts);
busy_nsec = SPA_TIMESPEC_TO_NSEC(&ts);
busy_nsec += (uint64_t)(impl->cpu_scale * SampleCount);
do {
clock_gettime(CLOCK_MONOTONIC, &ts);
} while ((uint64_t)SPA_TIMESPEC_TO_NSEC(&ts) < busy_nsec);
}
}
static const struct spa_fga_descriptor busy_desc = {
.name = "busy",
.flags = SPA_FGA_DESCRIPTOR_SUPPORTS_NULL_DATA,
.n_ports = 0,
.ports = NULL,
.instantiate = busy_instantiate,
.connect_port = builtin_connect_port,
.run = busy_run,
.cleanup = builtin_cleanup,
};
/* null */
static void null_run(void * Instance, unsigned long SampleCount)
{
}
static struct spa_fga_port null_ports[] = {
{ .index = 0,
.name = "In",
.flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_AUDIO,
},
{ .index = 1,
.name = "Control",
.flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL,
.def = 0.0f, .min = -FLT_MAX, .max = FLT_MAX
},
};
static const struct spa_fga_descriptor null_desc = {
.name = "null",
.flags = SPA_FGA_DESCRIPTOR_SUPPORTS_NULL_DATA,
.n_ports = SPA_N_ELEMENTS(null_ports),
.ports = null_ports,
.instantiate = builtin_instantiate,
.connect_port = builtin_connect_port,
.run = null_run,
.cleanup = builtin_cleanup,
};
static const struct spa_fga_descriptor * builtin_descriptor(unsigned long Index)
{
switch(Index) {
@ -3335,10 +3180,6 @@ static const struct spa_fga_descriptor * builtin_descriptor(unsigned long Index)
return &zeroramp_desc;
case 30:
return &noisegate_desc;
case 31:
return &busy_desc;
case 32:
return &null_desc;
}
return NULL;
}

View file

@ -399,7 +399,6 @@ static struct spa_fga_port lufs2gain_ports[] = {
{ .index = 0,
.name = "LUFS",
.flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL,
.def = 0.0f, .min = 0.0f, .max = FLT_MAX
},
{ .index = 1,
.name = "Gain",

View file

@ -7,7 +7,6 @@
#include <dlfcn.h>
#include <math.h>
#include <limits.h>
#include <float.h>
#include <spa/utils/result.h>
#include <spa/utils/defs.h>
@ -114,14 +113,8 @@ static void ladspa_port_update_ranges(struct descriptor *dd, struct spa_fga_port
LADSPA_PortRangeHintDescriptor hint = d->PortRangeHints[p].HintDescriptor;
LADSPA_Data lower, upper;
if (hint & LADSPA_HINT_BOUNDED_BELOW)
lower = d->PortRangeHints[p].LowerBound;
else
lower = -FLT_MAX;
if (hint & LADSPA_HINT_BOUNDED_ABOVE)
upper = d->PortRangeHints[p].UpperBound;
else
upper = FLT_MAX;
port->hint = 0;
if (hint & LADSPA_HINT_TOGGLED)

View file

@ -560,17 +560,6 @@ static const struct spa_fga_descriptor *lv2_plugin_make_desc(void *plugin, const
fp->min = mins[i];
fp->max = maxes[i];
fp->def = controls[i];
if (isnan(fp->min))
fp->min = -FLT_MAX;
if (isnan(fp->max))
fp->max = FLT_MAX;
if (isnan(fp->def))
fp->def = 0.0f;
if (fp->max <= fp->min)
fp->max = FLT_MAX;
if (fp->def <= fp->min)
fp->min = -FLT_MAX;
}
return &desc->desc;
}

View file

@ -593,10 +593,6 @@ static const struct spa_fga_descriptor *onnx_plugin_make_desc(void *plugin, cons
fp->flags |= SPA_FGA_PORT_OUTPUT;
fp->name = ti->data_name;
fp->min = -FLT_MAX;
fp->max = FLT_MAX;
fp->def = 0.0f;
ti->data_index = desc->desc.n_ports;
desc->desc.n_ports++;

View file

@ -32,7 +32,6 @@ struct spatializer_impl {
unsigned long rate;
float *port[7];
int n_samples, blocksize, tailsize;
float gain;
float *tmp[2];
struct MYSOFA_EASY *sofa;
@ -72,7 +71,6 @@ static void * spatializer_instantiate(const struct spa_fga_plugin *plugin, const
impl->plugin = pl;
impl->dsp = pl->dsp;
impl->log = pl->log;
impl->gain = 1.0f;
while ((len = spa_json_object_next(&it[0], key, sizeof(key), &val)) > 0) {
if (spa_streq(key, "blocksize")) {
@ -96,13 +94,6 @@ static void * spatializer_instantiate(const struct spa_fga_plugin *plugin, const
goto error;
}
}
else if (spa_streq(key, "gain")) {
if (spa_json_parse_float(val, len, &impl->gain) <= 0) {
spa_log_error(impl->log, "spatializer:gain requires a number");
errno = EINVAL;
goto error;
}
}
}
if (!filename[0]) {
spa_log_error(impl->log, "spatializer:filename was not given");
@ -177,14 +168,11 @@ static void * spatializer_instantiate(const struct spa_fga_plugin *plugin, const
reason = "Only sources with MC supported";
errno = ENOTSUP;
break;
default:
case MYSOFA_INTERNAL_ERROR:
errno = EIO;
reason = "Internal error";
break;
default:
errno = ret;
reason = strerror(errno);
break;
}
spa_log_error(impl->log, "Unable to load HRTF from %s: %s (%d)", filename, reason, ret);
goto error;
@ -195,8 +183,8 @@ static void * spatializer_instantiate(const struct spa_fga_plugin *plugin, const
if (impl->tailsize <= 0)
impl->tailsize = SPA_CLAMP(4096, impl->blocksize, 32768);
spa_log_info(impl->log, "using n_samples:%u %d:%d blocksize gain:%f sofa:%s", impl->n_samples,
impl->blocksize, impl->tailsize, impl->gain, filename);
spa_log_info(impl->log, "using n_samples:%u %d:%d blocksize sofa:%s", impl->n_samples,
impl->blocksize, impl->tailsize, filename);
impl->tmp[0] = calloc(impl->plugin->quantum_limit, sizeof(float));
impl->tmp[1] = calloc(impl->plugin->quantum_limit, sizeof(float));
@ -262,13 +250,6 @@ static void spatializer_reload(void * Instance)
if (impl->r_conv[2])
convolver_free(impl->r_conv[2]);
if (impl->gain != 1.0f) {
for (int i = 0; i < impl->n_samples; i++) {
left_ir[i] *= impl->gain;
right_ir[i] *= impl->gain;
}
}
impl->l_conv[2] = convolver_new(impl->dsp, impl->blocksize, impl->tailsize,
left_ir, impl->n_samples);
impl->r_conv[2] = convolver_new(impl->dsp, impl->blocksize, impl->tailsize,

View file

@ -5,7 +5,6 @@
/* SPDX-License-Identifier: MIT */
#include <cstddef>
#include <span>
#include <sstream>
#include <spa/support/plugin.h>
@ -26,6 +25,7 @@
#include <libcamera/camera.h>
#include <libcamera/property_ids.h>
#include <libcamera/base/span.h>
using namespace libcamera;
@ -50,7 +50,7 @@ struct impl {
std::string device_id);
};
std::span<const int64_t> cameraDevice(const Camera& camera)
const libcamera::Span<const int64_t> cameraDevice(const Camera& camera)
{
if (auto devices = camera.properties().get(properties::SystemDevices))
return devices.value();

View file

@ -184,6 +184,9 @@ struct impl {
0, nullptr, 0, this
);
if (source.fd >= 0)
spa_system_close(system, std::exchange(source.fd, -1));
camera->requestCompleted.disconnect(this, &impl::requestComplete);
if (int res = camera->stop(); res < 0) {
@ -191,9 +194,6 @@ struct impl {
camera->id().c_str(), spa_strerror(res));
}
if (source.fd >= 0)
spa_system_close(system, std::exchange(source.fd, -1));
completed_requests_rb = SPA_RINGBUFFER_INIT();
active = false;
@ -2163,7 +2163,7 @@ impl::impl(spa_log *log, spa_loop *data_loop, spa_system *system,
&impl_node, this);
params[NODE_PropInfo] = SPA_PARAM_INFO(SPA_PARAM_PropInfo, SPA_PARAM_INFO_READ);
params[NODE_Props] = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_WRITE);
params[NODE_Props] = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_READWRITE);
params[NODE_EnumFormat] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
params[NODE_Format] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);

View file

@ -1,4 +1,4 @@
if alsa_dep.found()
if alsa_dep.found() and host_machine.system() == 'linux'
subdir('alsa')
endif
if get_option('avb').require(host_machine.system() == 'linux', error_message: 'AVB support is only available on Linux').allowed()

View file

@ -78,8 +78,6 @@ x86_init(struct impl *impl)
if ((ebx & AVX512_BITS) == AVX512_BITS)
flags |= SPA_CPU_FLAG_AVX512;
}
if (max_level < 0x16)
flags |= SPA_CPU_FLAG_SLOW_GATHER;
/* Check cpuid level of extended features. */
__cpuid (0x80000000, ext_level, ebx, ecx, edx);

View file

@ -2,16 +2,12 @@
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
/* SPDX-License-Identifier: MIT */
#include "config.h"
#include <stddef.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <time.h>
#include <threads.h>
#include <fnmatch.h>
#include <spa/support/log.h>
@ -71,10 +67,16 @@ impl_log_logtv(void *object,
const char *fmt,
va_list args)
{
#define RESERVED_LENGTH 24
struct impl *impl = object;
char location[1024];
char timestamp[18] = {0};
char topicstr[32] = {0};
char filename[64] = {0};
char location[1000 + RESERVED_LENGTH], *p, *s;
static const char * const levels[] = { "-", "E", "W", "I", "D", "T", "*T*" };
const char *prefix = "", *suffix = "";
int size, len;
bool do_trace;
if ((do_trace = (level == SPA_LOG_LEVEL_TRACE && impl->have_source)))
@ -91,18 +93,8 @@ impl_log_logtv(void *object,
suffix = SPA_ANSI_RESET;
}
struct spa_strbuf msg;
spa_strbuf_init(&msg, location, sizeof(location));
spa_strbuf_append(&msg, "%s[%s]", prefix, levels[level]);
#ifdef HAVE_GETTID
static thread_local pid_t tid;
if (SPA_UNLIKELY(tid == 0))
tid = gettid();
spa_strbuf_append(&msg, "[%jd]", (intmax_t) tid);
#endif
p = location;
len = sizeof(location) - RESERVED_LENGTH;
if (impl->local_timestamp) {
char buf[64];
@ -112,52 +104,67 @@ impl_log_logtv(void *object,
clock_gettime(impl->clock_id, &now);
localtime_r(&now.tv_sec, &now_tm);
strftime(buf, sizeof(buf), "%H:%M:%S", &now_tm);
spa_strbuf_append(&msg, "[%s.%06d]", buf,
spa_scnprintf(timestamp, sizeof(timestamp), "[%s.%06d]", buf,
(int)(now.tv_nsec / SPA_NSEC_PER_USEC));
} else if (impl->timestamp) {
struct timespec now;
clock_gettime(impl->clock_id, &now);
spa_strbuf_append(&msg, "[%05jd.%06jd]",
spa_scnprintf(timestamp, sizeof(timestamp), "[%05jd.%06jd]",
(intmax_t) (now.tv_sec & 0x1FFFFFFF) % 100000, (intmax_t) now.tv_nsec / 1000);
}
if (topic && topic->topic)
spa_strbuf_append(&msg, " %-12s | ", topic->topic);
spa_scnprintf(topicstr, sizeof(topicstr), " %-12s | ", topic->topic);
if (impl->line && line != 0) {
const char *s = strrchr(file, '/');
spa_strbuf_append(&msg, "[%16.16s:%5i %s()]",
s = strrchr(file, '/');
spa_scnprintf(filename, sizeof(filename), "[%16.16s:%5i %s()]",
s ? s + 1 : file, line, func);
}
spa_strbuf_append(&msg, " ");
spa_strbuf_appendv(&msg, fmt, args);
spa_strbuf_append(&msg, "%s\n", suffix);
size = spa_scnprintf(p, len, "%s[%s]%s%s%s ", prefix, levels[level],
timestamp, topicstr, filename);
/*
* it is assumed that at this point `size` <= `len`,
* which is reasonable as long as file names and function names
* don't become very long
*/
size += spa_vscnprintf(p + size, len - size, fmt, args);
if (SPA_UNLIKELY(msg.pos >= msg.maxsize)) {
static const char truncated_text[] = "... (truncated)";
size_t suffix_length = strlen(suffix) + strlen(truncated_text) + 1 + 1;
/*
* `RESERVED_LENGTH` bytes are reserved for printing the suffix
* (at the moment it's "... (truncated)\x1B[0m\n" at its longest - 21 bytes),
* its length must be less than `RESERVED_LENGTH` (including the null byte),
* otherwise a stack buffer overrun could ensue
*/
spa_assert(msg.maxsize >= suffix_length);
msg.pos = msg.maxsize - suffix_length;
spa_strbuf_append(&msg, "%s%s\n", truncated_text, suffix);
spa_assert(msg.pos < msg.maxsize);
/* if the message could not fit entirely... */
if (size >= len - 1) {
size = len - 1; /* index of the null byte */
len = sizeof(location);
size += spa_scnprintf(p + size, len - size, "... (truncated)");
}
else {
len = sizeof(location);
}
size += spa_scnprintf(p + size, len - size, "%s\n", suffix);
if (SPA_UNLIKELY(do_trace)) {
uint32_t index;
spa_ringbuffer_get_write_index(&impl->trace_rb, &index);
spa_ringbuffer_write_data(&impl->trace_rb, impl->trace_data, TRACE_BUFFER,
index & (TRACE_BUFFER - 1), msg.buffer, msg.pos);
spa_ringbuffer_write_update(&impl->trace_rb, index + msg.pos);
index & (TRACE_BUFFER - 1), location, size);
spa_ringbuffer_write_update(&impl->trace_rb, index + size);
if (spa_system_eventfd_write(impl->system, impl->source.fd, 1) < 0)
fprintf(impl->file, "error signaling eventfd: %s\n", strerror(errno));
} else
fputs(msg.buffer, impl->file);
fputs(location, impl->file);
#undef RESERVED_LENGTH
}
static SPA_PRINTF_FUNC(6,0) void

View file

@ -462,12 +462,12 @@ again:
* this invoking thread but we need to serialize the flushing here with
* a mutex */
if (loop_thread == 0)
spa_assert_se(pthread_mutex_lock(&impl->lock) == 0);
pthread_mutex_lock(&impl->lock);
flush_all_queues(impl);
if (loop_thread == 0)
spa_assert_se(pthread_mutex_unlock(&impl->lock) == 0);
pthread_mutex_unlock(&impl->lock);
res = item->res;
} else {
@ -482,9 +482,9 @@ again:
recurse = impl->recurse;
while (impl->recurse > 0) {
impl->recurse--;
spa_assert_se(pthread_mutex_unlock(&impl->lock) == 0);
pthread_mutex_unlock(&impl->lock);
}
spa_assert_se(pthread_mutex_unlock(&impl->lock) == 0);
pthread_mutex_unlock(&impl->lock);
}
if ((res = spa_system_eventfd_read(impl->system, queue->ack_fd, &count)) < 0)
@ -492,7 +492,7 @@ again:
queue, queue->ack_fd, spa_strerror(res));
for (i = 0; i < recurse; i++) {
spa_assert_se(pthread_mutex_lock(&impl->lock) == 0);
pthread_mutex_lock(&impl->lock);
impl->recurse++;
}
@ -569,14 +569,9 @@ static int loop_locked(void *object, spa_invoke_func_t func, uint32_t seq,
{
struct impl *impl = object;
int res;
res = pthread_mutex_lock(&impl->lock);
if (res)
return -res;
pthread_mutex_lock(&impl->lock);
res = func(&impl->loop, false, seq, data, size, user_data);
spa_assert_se(pthread_mutex_unlock(&impl->lock) == 0);
pthread_mutex_unlock(&impl->lock);
return res;
}
@ -603,7 +598,7 @@ static void loop_enter(void *object)
struct impl *impl = object;
pthread_t thread_id = pthread_self();
spa_assert_se(pthread_mutex_lock(&impl->lock) == 0);
pthread_mutex_lock(&impl->lock);
if (impl->enter_count == 0) {
spa_return_if_fail(impl->thread == 0);
impl->thread = thread_id;
@ -630,7 +625,7 @@ static void loop_leave(void *object)
impl->thread = 0;
flush_all_queues(impl);
}
spa_assert_se(pthread_mutex_unlock(&impl->lock) == 0);
pthread_mutex_unlock(&impl->lock);
}
static int loop_check(void *object)
@ -649,7 +644,7 @@ static int loop_check(void *object)
/* we could take the lock, check if we actually locked it somewhere */
res = impl->recurse > 0 ? 1 : -EPERM;
spa_assert_se(pthread_mutex_unlock(&impl->lock) == 0);
pthread_mutex_unlock(&impl->lock);
return res;
}
static int loop_lock(void *object)
@ -727,20 +722,13 @@ static int loop_accept(void *object)
}
struct cancellation_handler_data {
struct impl *impl;
const struct spa_poll_event *ep;
volatile int ep_count;
volatile int unlocked;
volatile int locked;
struct spa_poll_event *ep;
int ep_count;
};
static void cancellation_handler(void *closure)
{
const struct cancellation_handler_data *data = closure;
struct impl *impl = data->impl;
if (data->unlocked && !data->locked)
spa_assert_se(pthread_mutex_lock(&impl->lock) == 0);
for (int i = 0; i < data->ep_count; i++) {
struct spa_source *s = data->ep[i].data;
@ -757,24 +745,20 @@ static int loop_iterate_cancel(void *object, int timeout)
struct spa_poll_event ep[MAX_EP], *e;
int i, nfds;
uint32_t remove_count;
struct cancellation_handler_data cdata = { impl, ep, 0, 0, 0 };
spa_return_val_if_fail(impl->enter_count > 0, -EPERM);
pthread_cleanup_push(cancellation_handler, &cdata);
remove_count = impl->remove_count;
spa_loop_control_hook_before(&impl->hooks_list);
spa_assert_se((cdata.unlocked = (pthread_mutex_unlock(&impl->lock) == 0)));
pthread_mutex_unlock(&impl->lock);
nfds = spa_system_pollfd_wait(impl->system, impl->poll_fd, ep, SPA_N_ELEMENTS(ep), timeout);
spa_assert_se((cdata.locked = (pthread_mutex_lock(&impl->lock) == 0)));
pthread_mutex_lock(&impl->lock);
spa_loop_control_hook_after(&impl->hooks_list);
if (remove_count != impl->remove_count)
nfds = 0;
cdata.ep_count = nfds;
struct cancellation_handler_data cdata = { ep, nfds };
pthread_cleanup_push(cancellation_handler, &cdata);
/* first we set all the rmasks, then call the callbacks. The reason is that
* some callback might also want to look at other sources it manages and
@ -810,15 +794,13 @@ static int loop_iterate(void *object, int timeout)
int i, nfds;
uint32_t remove_count;
spa_return_val_if_fail(impl->enter_count > 0, -EPERM);
remove_count = impl->remove_count;
spa_loop_control_hook_before(&impl->hooks_list);
spa_assert_se(pthread_mutex_unlock(&impl->lock) == 0);
pthread_mutex_unlock(&impl->lock);
nfds = spa_system_pollfd_wait(impl->system, impl->poll_fd, ep, SPA_N_ELEMENTS(ep), timeout);
spa_assert_se(pthread_mutex_lock(&impl->lock) == 0);
pthread_mutex_lock(&impl->lock);
spa_loop_control_hook_after(&impl->hooks_list);
if (remove_count != impl->remove_count)
return 0;

View file

@ -91,6 +91,7 @@ struct impl {
struct spa_io_clock *clock;
struct spa_source timer_source;
struct itimerspec timerspec;
int clock_fd;
bool started;
@ -181,16 +182,13 @@ static void set_timeout(struct impl *this, uint64_t next_time)
* returning -ECANCELED.)
* If timerfd is used with a non-realtime clock, the flag is ignored.
* (Note that the flag only works in combination with SPA_FD_TIMER_ABSTIME.) */
struct itimerspec ts;
spa_log_trace(this->log, "set timeout %"PRIu64, next_time);
ts.it_value.tv_sec = next_time / SPA_NSEC_PER_SEC;
ts.it_value.tv_nsec = next_time % SPA_NSEC_PER_SEC;
ts.it_interval.tv_sec = 0;
ts.it_interval.tv_nsec = 0;
this->timerspec.it_value.tv_sec = next_time / SPA_NSEC_PER_SEC;
this->timerspec.it_value.tv_nsec = next_time % SPA_NSEC_PER_SEC;
spa_system_timerfd_settime(this->data_system,
this->timer_source.fd, SPA_FD_TIMER_ABSTIME |
SPA_FD_TIMER_CANCEL_ON_SET, &ts, NULL);
SPA_FD_TIMER_CANCEL_ON_SET, &this->timerspec, NULL);
}
static inline uint64_t gettime_nsec(struct impl *this, clockid_t clock_id)
@ -1045,6 +1043,10 @@ impl_init(const struct spa_handle_factory *factory,
this->timer_source.mask = SPA_IO_IN;
this->timer_source.rmask = 0;
this->timerspec.it_value.tv_sec = 0;
this->timerspec.it_value.tv_nsec = 0;
this->timerspec.it_interval.tv_sec = 0;
this->timerspec.it_interval.tv_nsec = 0;
spa_loop_add_source(this->data_loop, &this->timer_source);

View file

@ -114,6 +114,7 @@ struct impl {
unsigned int started:1;
unsigned int following:1;
struct spa_source timer_source;
struct itimerspec timerspec;
uint64_t next_time;
};
@ -178,15 +179,11 @@ static int impl_node_enum_params(void *object, int seq,
static void set_timeout(struct impl *this, uint64_t next_time)
{
struct itimerspec ts;
spa_log_trace(this->log, "set timeout %"PRIu64, next_time);
ts.it_value.tv_sec = next_time / SPA_NSEC_PER_SEC;
ts.it_value.tv_nsec = next_time % SPA_NSEC_PER_SEC;
ts.it_interval.tv_sec = 0;
ts.it_interval.tv_nsec = 0;
this->timerspec.it_value.tv_sec = next_time / SPA_NSEC_PER_SEC;
this->timerspec.it_value.tv_nsec = next_time % SPA_NSEC_PER_SEC;
spa_system_timerfd_settime(this->data_system,
this->timer_source.fd, SPA_FD_TIMER_ABSTIME, &ts, NULL);
this->timer_source.fd, SPA_FD_TIMER_ABSTIME, &this->timerspec, NULL);
}
static int set_timers(struct impl *this)
@ -932,6 +929,10 @@ impl_init(const struct spa_handle_factory *factory,
SPA_FD_CLOEXEC | SPA_FD_NONBLOCK);
this->timer_source.mask = SPA_IO_IN;
this->timer_source.rmask = 0;
this->timerspec.it_value.tv_sec = 0;
this->timerspec.it_value.tv_nsec = 0;
this->timerspec.it_interval.tv_sec = 0;
this->timerspec.it_interval.tv_nsec = 0;
spa_loop_add_source(this->data_loop, &this->timer_source);

View file

@ -30,10 +30,6 @@ SPA_LOG_TOPIC_DEFINE_STATIC(log_topic, "spa.system");
# define TFD_TIMER_CANCEL_ON_SET (1 << 1)
#endif
SPA_STATIC_ASSERT(sizeof(struct spa_poll_event) == sizeof(struct epoll_event));
SPA_STATIC_ASSERT(offsetof(struct spa_poll_event, events) == offsetof(struct epoll_event, events));
SPA_STATIC_ASSERT(offsetof(struct spa_poll_event, data) == offsetof(struct epoll_event, data.ptr));
struct impl {
struct spa_handle handle;
struct spa_system system;
@ -136,9 +132,16 @@ static int impl_pollfd_del(void *object, int pfd, int fd)
static int impl_pollfd_wait(void *object, int pfd,
struct spa_poll_event *ev, int n_ev, int timeout)
{
int nfds;
if (SPA_UNLIKELY((nfds = epoll_wait(pfd, (struct epoll_event*)ev, n_ev, timeout)) < 0))
struct epoll_event ep[n_ev];
int i, nfds;
if (SPA_UNLIKELY((nfds = epoll_wait(pfd, ep, n_ev, timeout)) < 0))
return -errno;
for (i = 0; i < nfds; i++) {
ev[i].events = ep[i].events;
ev[i].data = ep[i].data.ptr;
}
return nfds;
}

View file

@ -26,6 +26,10 @@
#define SPA_LOG_TOPIC_DEFAULT &log_topic
SPA_LOG_TOPIC_DEFINE_STATIC(log_topic, "spa.fakesink");
struct props {
bool live;
};
#define MAX_BUFFERS 16
#define MAX_PORTS 1
@ -64,11 +68,13 @@ struct impl {
uint64_t info_all;
struct spa_node_info info;
struct spa_param_info params[1];
struct props props;
struct spa_hook_list hooks;
struct spa_callbacks callbacks;
struct spa_source timer_source;
struct itimerspec timerspec;
bool started;
uint64_t start_time;
@ -81,6 +87,13 @@ struct impl {
#define CHECK_PORT(this,d,p) ((d) == SPA_DIRECTION_INPUT && (p) < MAX_PORTS)
#define DEFAULT_LIVE false
static void reset_props(struct impl *this, struct props *props)
{
props->live = DEFAULT_LIVE;
}
static int impl_node_enum_params(void *object, int seq,
uint32_t id, uint32_t start, uint32_t num,
const struct spa_pod *filter)
@ -103,6 +116,14 @@ static int impl_node_enum_params(void *object, int seq,
spa_pod_builder_init(&b, buffer, sizeof(buffer));
switch (id) {
case SPA_PARAM_Props:
if (result.index > 0)
return 0;
param = spa_pod_builder_add_object(&b,
SPA_TYPE_OBJECT_Props, id,
SPA_PROP_live, SPA_POD_Bool(this->props.live));
break;
default:
return -ENOENT;
}
@ -130,7 +151,26 @@ static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
spa_return_val_if_fail(this != NULL, -EINVAL);
switch (id) {
case SPA_PARAM_Props:
{
struct port *port = &this->port;
if (param == NULL) {
reset_props(this, &this->props);
return 0;
}
spa_pod_parse_object(param,
SPA_TYPE_OBJECT_Props, NULL,
SPA_PROP_live, SPA_POD_OPT_Bool(&this->props.live));
if (this->props.live)
port->info.flags |= SPA_PORT_FLAG_LIVE;
else
port->info.flags &= ~SPA_PORT_FLAG_LIVE;
break;
}
default:
return -ENOENT;
}
@ -139,15 +179,23 @@ static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
static void set_timer(struct impl *this, bool enabled)
{
struct itimerspec ts = {0};
if (this->callbacks.funcs || this->props.live) {
if (enabled) {
if (this->props.live) {
uint64_t next_time = this->start_time + this->elapsed_time;
ts.it_value.tv_sec = next_time / SPA_NSEC_PER_SEC;
ts.it_value.tv_nsec = next_time % SPA_NSEC_PER_SEC;
this->timerspec.it_value.tv_sec = next_time / SPA_NSEC_PER_SEC;
this->timerspec.it_value.tv_nsec = next_time % SPA_NSEC_PER_SEC;
} else {
this->timerspec.it_value.tv_sec = 0;
this->timerspec.it_value.tv_nsec = 1;
}
} else {
this->timerspec.it_value.tv_sec = 0;
this->timerspec.it_value.tv_nsec = 0;
}
spa_system_timerfd_settime(this->data_system,
this->timer_source.fd, SPA_FD_TIMER_ABSTIME, &this->timerspec, NULL);
}
spa_system_timerfd_settime(this->data_system, this->timer_source.fd, SPA_FD_TIMER_ABSTIME, &ts, NULL);
}
static inline int read_timer(struct impl *this)
@ -155,12 +203,14 @@ static inline int read_timer(struct impl *this)
uint64_t expirations;
int res = 0;
if ((res = spa_system_timerfd_read(this->data_system, this->timer_source.fd, &expirations)) < 0) {
if (this->callbacks.funcs || this->props.live) {
if ((res = spa_system_timerfd_read(this->data_system,
this->timer_source.fd, &expirations)) < 0) {
if (res != -EAGAIN)
spa_log_error(this->log, "%p: timerfd error: %s",
this, spa_strerror(res));
}
}
return res;
}
@ -248,7 +298,10 @@ static int impl_node_send_command(void *object, const struct spa_command *comman
return 0;
clock_gettime(CLOCK_MONOTONIC, &now);
if (this->props.live)
this->start_time = SPA_TIMESPEC_TO_NSEC(&now);
else
this->start_time = 0;
this->buffer_count = 0;
this->elapsed_time = 0;
@ -598,7 +651,9 @@ static int impl_node_process(void *object)
io->buffer_id = SPA_ID_INVALID;
io->status = SPA_STATUS_OK;
}
if (this->callbacks.funcs == NULL)
return consume_buffer(this);
else
return SPA_STATUS_OK;
}
@ -703,6 +758,8 @@ impl_init(const struct spa_handle_factory *factory,
this->params[0] = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_READWRITE);
this->info.params = this->params;
this->info.n_params = 1;
reset_props(this, &this->props);
this->timer_source.func = on_input;
this->timer_source.data = this;
@ -710,6 +767,10 @@ impl_init(const struct spa_handle_factory *factory,
SPA_FD_CLOEXEC | SPA_FD_NONBLOCK);
this->timer_source.mask = SPA_IO_IN;
this->timer_source.rmask = 0;
this->timerspec.it_value.tv_sec = 0;
this->timerspec.it_value.tv_nsec = 0;
this->timerspec.it_interval.tv_sec = 0;
this->timerspec.it_interval.tv_nsec = 0;
if (this->data_loop)
spa_loop_add_source(this->data_loop, &this->timer_source);
@ -718,7 +779,9 @@ impl_init(const struct spa_handle_factory *factory,
port->info_all = SPA_PORT_CHANGE_MASK_FLAGS |
SPA_PORT_CHANGE_MASK_PARAMS;
port->info = SPA_PORT_INFO_INIT();
port->info.flags = SPA_PORT_FLAG_NO_REF | SPA_PORT_FLAG_LIVE;
port->info.flags = SPA_PORT_FLAG_NO_REF;
if (this->props.live)
port->info.flags |= SPA_PORT_FLAG_LIVE;
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_IO, 0);
port->params[2] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);

View file

@ -27,6 +27,7 @@
SPA_LOG_TOPIC_DEFINE_STATIC(log_topic, "spa.fakesrc");
struct props {
bool live;
uint32_t pattern;
};
@ -74,6 +75,7 @@ struct impl {
struct spa_callbacks callbacks;
struct spa_source timer_source;
struct itimerspec timerspec;
bool started;
uint64_t start_time;
@ -87,10 +89,12 @@ struct impl {
#define CHECK_PORT(this,d,p) ((d) == SPA_DIRECTION_OUTPUT && (p) < MAX_PORTS)
#define DEFAULT_LIVE false
#define DEFAULT_PATTERN 0
static void reset_props(struct impl *this, struct props *props)
{
props->live = DEFAULT_LIVE;
props->pattern = DEFAULT_PATTERN;
}
@ -125,6 +129,7 @@ static int impl_node_enum_params(void *object, int seq,
param = spa_pod_builder_add_object(&b,
SPA_TYPE_OBJECT_Props, id,
SPA_PROP_live, SPA_POD_Bool(p->live),
SPA_PROP_patternType, SPA_POD_CHOICE_ENUM_Int(2, p->pattern, p->pattern));
break;
}
@ -159,6 +164,7 @@ static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
case SPA_PARAM_Props:
{
struct props *p = &this->props;
struct port *port = &this->port;
if (param == NULL) {
reset_props(this, p);
@ -166,7 +172,13 @@ static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
}
spa_pod_parse_object(param,
SPA_TYPE_OBJECT_Props, NULL,
SPA_PROP_live, SPA_POD_OPT_Bool(&p->live),
SPA_PROP_patternType, SPA_POD_OPT_Int(&p->pattern));
if (p->live)
port->info.flags |= SPA_PORT_FLAG_LIVE;
else
port->info.flags &= ~SPA_PORT_FLAG_LIVE;
break;
}
default:
@ -182,15 +194,23 @@ static int fill_buffer(struct impl *this, struct buffer *b)
static void set_timer(struct impl *this, bool enabled)
{
struct itimerspec ts = {0};
if (this->callbacks.funcs || this->props.live) {
if (enabled) {
if (this->props.live) {
uint64_t next_time = this->start_time + this->elapsed_time;
ts.it_value.tv_sec = next_time / SPA_NSEC_PER_SEC;
ts.it_value.tv_nsec = next_time % SPA_NSEC_PER_SEC;
this->timerspec.it_value.tv_sec = next_time / SPA_NSEC_PER_SEC;
this->timerspec.it_value.tv_nsec = next_time % SPA_NSEC_PER_SEC;
} else {
this->timerspec.it_value.tv_sec = 0;
this->timerspec.it_value.tv_nsec = 1;
}
} else {
this->timerspec.it_value.tv_sec = 0;
this->timerspec.it_value.tv_nsec = 0;
}
spa_system_timerfd_settime(this->data_system,
this->timer_source.fd, SPA_FD_TIMER_ABSTIME, &this->timerspec, NULL);
}
spa_system_timerfd_settime(this->data_system, this->timer_source.fd, SPA_FD_TIMER_ABSTIME, &ts, NULL);
}
static inline int read_timer(struct impl *this)
@ -198,12 +218,14 @@ static inline int read_timer(struct impl *this)
uint64_t expirations;
int res = 0;
if ((res = spa_system_timerfd_read(this->data_system, this->timer_source.fd, &expirations)) < 0) {
if (this->callbacks.funcs || this->props.live) {
if ((res = spa_system_timerfd_read(this->data_system,
this->timer_source.fd, &expirations)) < 0) {
if (res != -EAGAIN)
spa_log_error(this->log, "%p: timerfd error: %s",
this, spa_strerror(res));
}
}
return res;
}
@ -289,7 +311,10 @@ static int impl_node_send_command(void *object, const struct spa_command *comman
return 0;
clock_gettime(CLOCK_MONOTONIC, &now);
if (this->props.live)
this->start_time = SPA_TIMESPEC_TO_NSEC(&now);
else
this->start_time = 0;
this->buffer_count = 0;
this->elapsed_time = 0;
@ -657,6 +682,9 @@ static int impl_node_process(void *object)
io->buffer_id = SPA_ID_INVALID;
}
if (this->callbacks.funcs == NULL)
return make_buffer(this);
else
return SPA_STATUS_OK;
}
@ -769,6 +797,10 @@ impl_init(const struct spa_handle_factory *factory,
SPA_FD_CLOEXEC | SPA_FD_NONBLOCK);
this->timer_source.mask = SPA_IO_IN;
this->timer_source.rmask = 0;
this->timerspec.it_value.tv_sec = 0;
this->timerspec.it_value.tv_nsec = 0;
this->timerspec.it_interval.tv_sec = 0;
this->timerspec.it_interval.tv_nsec = 0;
if (this->data_loop)
spa_loop_add_source(this->data_loop, &this->timer_source);
@ -777,7 +809,9 @@ impl_init(const struct spa_handle_factory *factory,
port->info_all = SPA_PORT_CHANGE_MASK_FLAGS |
SPA_PORT_CHANGE_MASK_PARAMS;
port->info = SPA_PORT_INFO_INIT();
port->info.flags = SPA_PORT_FLAG_NO_REF | SPA_PORT_FLAG_LIVE;
port->info.flags = SPA_PORT_FLAG_NO_REF;
if (this->props.live)
port->info.flags |= SPA_PORT_FLAG_LIVE;
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_IO, 0);
port->params[2] = SPA_PARAM_INFO(SPA_PARAM_Format, SPA_PARAM_INFO_WRITE);

View file

@ -98,9 +98,9 @@ static int emit_info(struct impl *this, bool full)
(this->dev.cap.version >> 8) & 0xFF,
(this->dev.cap.version) & 0xFF);
ADD_ITEM(SPA_KEY_API_V4L2_CAP_VERSION, version);
snprintf(capabilities, sizeof(capabilities), "0x%08x", this->dev.cap.capabilities);
snprintf(capabilities, sizeof(capabilities), "%08x", this->dev.cap.capabilities);
ADD_ITEM(SPA_KEY_API_V4L2_CAP_CAPABILITIES, capabilities);
snprintf(device_caps, sizeof(device_caps), "0x%08x", this->dev.cap.device_caps);
snprintf(device_caps, sizeof(device_caps), "%08x", this->dev.cap.device_caps);
ADD_ITEM(SPA_KEY_API_V4L2_CAP_DEVICE_CAPS, device_caps);
#undef ADD_ITEM
info.props = &SPA_DICT_INIT(items, n_items);

View file

@ -35,14 +35,17 @@ enum pattern {
PATTERN_SNOW,
};
#define DEFAULT_LIVE true
#define DEFAULT_PATTERN PATTERN_SMPTE_SNOW
struct props {
bool live;
uint32_t pattern;
};
static void reset_props(struct props *props)
{
props->live = DEFAULT_LIVE;
props->pattern = DEFAULT_PATTERN;
}
@ -94,7 +97,9 @@ struct impl {
struct spa_hook_list hooks;
struct spa_callbacks callbacks;
bool async;
struct spa_source *timer_source;
struct itimerspec timerspec;
bool started;
uint64_t start_time;
@ -136,6 +141,13 @@ static int impl_node_enum_params(void *object, int seq,
switch (result.index) {
case 0:
param = spa_pod_builder_add_object(&b,
SPA_TYPE_OBJECT_PropInfo, id,
SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_live),
SPA_PROP_INFO_description, SPA_POD_String("Configure live mode of the source"),
SPA_PROP_INFO_type, SPA_POD_Bool(p->live));
break;
case 1:
spa_pod_builder_push_object(&b, &f[0], SPA_TYPE_OBJECT_PropInfo, id);
spa_pod_builder_add(&b,
SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_patternType),
@ -164,6 +176,7 @@ static int impl_node_enum_params(void *object, int seq,
case 0:
param = spa_pod_builder_add_object(&b,
SPA_TYPE_OBJECT_Props, id,
SPA_PROP_live, SPA_POD_Bool(p->live),
SPA_PROP_patternType, SPA_POD_Int(p->pattern));
break;
default:
@ -218,6 +231,7 @@ static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
case SPA_PARAM_Props:
{
struct props *p = &this->props;
struct port *port = &this->port;
if (param == NULL) {
reset_props(p);
@ -225,8 +239,13 @@ static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
}
spa_pod_parse_object(param,
SPA_TYPE_OBJECT_Props, NULL,
SPA_PROP_live, SPA_POD_OPT_Bool(&p->live),
SPA_PROP_patternType, SPA_POD_OPT_Int(&p->pattern));
if (p->live)
port->info.flags |= SPA_PORT_FLAG_LIVE;
else
port->info.flags &= ~SPA_PORT_FLAG_LIVE;
break;
}
default:
@ -244,15 +263,22 @@ static int fill_buffer(struct impl *this, struct buffer *b)
static void set_timer(struct impl *this, bool enabled)
{
struct timespec ts = {0};
if (this->async || this->props.live) {
if (enabled) {
if (this->props.live) {
uint64_t next_time = this->start_time + this->elapsed_time;
ts.tv_sec = next_time / SPA_NSEC_PER_SEC;
ts.tv_nsec = next_time % SPA_NSEC_PER_SEC;
this->timerspec.it_value.tv_sec = next_time / SPA_NSEC_PER_SEC;
this->timerspec.it_value.tv_nsec = next_time % SPA_NSEC_PER_SEC;
} else {
this->timerspec.it_value.tv_sec = 0;
this->timerspec.it_value.tv_nsec = 1;
}
} else {
this->timerspec.it_value.tv_sec = 0;
this->timerspec.it_value.tv_nsec = 0;
}
spa_loop_utils_update_timer(this->loop_utils, this->timer_source, &this->timerspec.it_value, &this->timerspec.it_interval, true);
}
spa_loop_utils_update_timer(this->loop_utils, this->timer_source, &ts, NULL, true);
}
static int make_buffer(struct impl *this)
@ -332,7 +358,10 @@ static int impl_node_send_command(void *object, const struct spa_command *comman
return 0;
clock_gettime(CLOCK_MONOTONIC, &now);
if (this->props.live)
this->start_time = SPA_TIMESPEC_TO_NSEC(&now);
else
this->start_time = 0;
this->frame_count = 0;
this->elapsed_time = 0;
@ -726,6 +755,9 @@ static inline void reuse_buffer(struct impl *this, struct port *port, uint32_t i
b->outstanding = false;
spa_list_append(&port->empty, &b->link);
if (!this->props.live)
set_timer(this, true);
}
static int impl_node_port_reuse_buffer(void *object, uint32_t port_id, uint32_t buffer_id)
@ -763,6 +795,9 @@ static int impl_node_process(void *object)
io->buffer_id = SPA_ID_INVALID;
}
if (!this->props.live)
return make_buffer(this);
else
return SPA_STATUS_OK;
}
@ -872,12 +907,18 @@ impl_init(const struct spa_handle_factory *factory,
reset_props(&this->props);
this->timer_source = spa_loop_utils_add_timer(this->loop_utils, on_output, this);
this->timerspec.it_value.tv_sec = 0;
this->timerspec.it_value.tv_nsec = 0;
this->timerspec.it_interval.tv_sec = 0;
this->timerspec.it_interval.tv_nsec = 0;
port = &this->port;
port->info_all = SPA_PORT_CHANGE_MASK_FLAGS |
SPA_PORT_CHANGE_MASK_PARAMS;
port->info = SPA_PORT_INFO_INIT();
port->info.flags = SPA_PORT_FLAG_NO_REF | SPA_PORT_FLAG_LIVE;
port->info.flags = SPA_PORT_FLAG_NO_REF;
if (this->props.live)
port->info.flags |= SPA_PORT_FLAG_LIVE;
port->params[0] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
port->params[1] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
port->params[2] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);

View file

@ -12,10 +12,8 @@
#include <fcntl.h>
#include <string.h>
#include <vulkan/vulkan_core.h>
#ifdef __linux__
#if !defined(__FreeBSD__) && !defined(__MidnightBSD__)
#include <alloca.h>
#else
#include <stdlib.h>
#endif
#include <errno.h>
#include <stdio.h>

View file

@ -33,6 +33,17 @@ SPA_LOG_TOPIC_DEFINE_STATIC(log_topic, "spa.vulkan.compute-source");
#define FRAMES_TO_TIME(this,f) ((this->position->video.framerate.denom * (f) * SPA_NSEC_PER_SEC) / \
(this->position->video.framerate.num))
#define DEFAULT_LIVE true
struct props {
bool live;
};
static void reset_props(struct props *props)
{
props->live = DEFAULT_LIVE;
}
struct buffer {
uint32_t id;
#define BUFFER_FLAG_OUT (1<<0)
@ -84,11 +95,14 @@ struct impl {
#define IDX_Props 1
#define N_NODE_PARAMS 2
struct spa_param_info params[N_NODE_PARAMS];
struct props props;
struct spa_hook_list hooks;
struct spa_callbacks callbacks;
bool async;
struct spa_source timer_source;
struct itimerspec timerspec;
bool started;
uint64_t start_time;
@ -124,6 +138,38 @@ static int impl_node_enum_params(void *object, int seq,
spa_pod_builder_init(&b, buffer, sizeof(buffer));
switch (id) {
case SPA_PARAM_PropInfo:
{
struct props *p = &this->props;
switch (result.index) {
case 0:
param = spa_pod_builder_add_object(&b,
SPA_TYPE_OBJECT_PropInfo, id,
SPA_PROP_INFO_id, SPA_POD_Id(SPA_PROP_live),
SPA_PROP_INFO_description, SPA_POD_String("Configure live mode of the source"),
SPA_PROP_INFO_type, SPA_POD_Bool(p->live));
break;
default:
return 0;
}
break;
}
case SPA_PARAM_Props:
{
struct props *p = &this->props;
switch (result.index) {
case 0:
param = spa_pod_builder_add_object(&b,
SPA_TYPE_OBJECT_Props, id,
SPA_PROP_live, SPA_POD_Bool(p->live));
break;
default:
return 0;
}
break;
}
default:
return -ENOENT;
}
@ -168,6 +214,25 @@ static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
spa_return_val_if_fail(this != NULL, -EINVAL);
switch (id) {
case SPA_PARAM_Props:
{
struct props *p = &this->props;
struct port *port = &this->port;
if (param == NULL) {
reset_props(p);
return 0;
}
spa_pod_parse_object(param,
SPA_TYPE_OBJECT_Props, NULL,
SPA_PROP_live, SPA_POD_OPT_Bool(&p->live));
if (p->live)
port->info.flags |= SPA_PORT_FLAG_LIVE;
else
port->info.flags &= ~SPA_PORT_FLAG_LIVE;
break;
}
default:
return -ENOENT;
}
@ -177,15 +242,23 @@ static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
static void set_timer(struct impl *this, bool enabled)
{
struct itimerspec ts = {0};
if (this->async || this->props.live) {
if (enabled) {
if (this->props.live) {
uint64_t next_time = this->start_time + this->elapsed_time;
ts.it_value.tv_sec = next_time / SPA_NSEC_PER_SEC;
ts.it_value.tv_nsec = next_time % SPA_NSEC_PER_SEC;
this->timerspec.it_value.tv_sec = next_time / SPA_NSEC_PER_SEC;
this->timerspec.it_value.tv_nsec = next_time % SPA_NSEC_PER_SEC;
} else {
this->timerspec.it_value.tv_sec = 0;
this->timerspec.it_value.tv_nsec = 1;
}
} else {
this->timerspec.it_value.tv_sec = 0;
this->timerspec.it_value.tv_nsec = 0;
}
spa_system_timerfd_settime(this->data_system,
this->timer_source.fd, SPA_FD_TIMER_ABSTIME, &this->timerspec, NULL);
}
spa_system_timerfd_settime(this->data_system, this->timer_source.fd, SPA_FD_TIMER_ABSTIME, &ts, NULL);
}
static int read_timer(struct impl *this)
@ -193,12 +266,14 @@ static int read_timer(struct impl *this)
uint64_t expirations;
int res = 0;
if ((res = spa_system_timerfd_read(this->data_system, this->timer_source.fd, &expirations)) < 0) {
if (this->async || this->props.live) {
if ((res = spa_system_timerfd_read(this->data_system,
this->timer_source.fd, &expirations)) < 0) {
if (res != -EAGAIN)
spa_log_error(this->log, "%p: timerfd error: %s",
this, spa_strerror(res));
}
}
return res;
}
@ -273,6 +348,9 @@ static inline void reuse_buffer(struct impl *this, struct port *port, uint32_t i
SPA_FLAG_CLEAR(b->flags, BUFFER_FLAG_OUT);
spa_list_append(&port->empty, &b->link);
if (!this->props.live)
set_timer(this, true);
}
}
@ -331,7 +409,10 @@ static int impl_node_send_command(void *object, const struct spa_command *comman
return 0;
clock_gettime(CLOCK_MONOTONIC, &now);
if (this->props.live)
this->start_time = SPA_TIMESPEC_TO_NSEC(&now);
else
this->start_time = 0;
this->frame_count = 0;
this->elapsed_time = 0;
@ -793,6 +874,9 @@ static int impl_node_process(void *object)
io->buffer_id = SPA_ID_INVALID;
}
if (!this->props.live)
return make_buffer(this);
else
return SPA_STATUS_OK;
}
@ -901,6 +985,7 @@ impl_init(const struct spa_handle_factory *factory,
this->params[IDX_Props] = SPA_PARAM_INFO(SPA_PARAM_Props, SPA_PARAM_INFO_READWRITE);
this->info.params = this->params;
this->info.n_params = N_NODE_PARAMS;
reset_props(&this->props);
this->timer_source.func = on_output;
this->timer_source.data = this;
@ -908,6 +993,10 @@ impl_init(const struct spa_handle_factory *factory,
SPA_FD_CLOEXEC | SPA_FD_NONBLOCK);
this->timer_source.mask = SPA_IO_IN;
this->timer_source.rmask = 0;
this->timerspec.it_value.tv_sec = 0;
this->timerspec.it_value.tv_nsec = 0;
this->timerspec.it_interval.tv_sec = 0;
this->timerspec.it_interval.tv_nsec = 0;
if (this->data_loop)
spa_loop_add_source(this->data_loop, &this->timer_source);
@ -917,7 +1006,9 @@ impl_init(const struct spa_handle_factory *factory,
SPA_PORT_CHANGE_MASK_PARAMS |
SPA_PORT_CHANGE_MASK_PROPS;
port->info = SPA_PORT_INFO_INIT();
port->info.flags = SPA_PORT_FLAG_NO_REF | SPA_PORT_FLAG_LIVE;
port->info.flags = SPA_PORT_FLAG_NO_REF;
if (this->props.live)
port->info.flags |= SPA_PORT_FLAG_LIVE;
port->params[IDX_EnumFormat] = SPA_PARAM_INFO(SPA_PARAM_EnumFormat, SPA_PARAM_INFO_READ);
port->params[IDX_Meta] = SPA_PARAM_INFO(SPA_PARAM_Meta, SPA_PARAM_INFO_READ);
port->params[IDX_IO] = SPA_PARAM_INFO(SPA_PARAM_IO, SPA_PARAM_INFO_READ);

View file

@ -11,10 +11,8 @@
#include <fcntl.h>
#include <string.h>
#include <vulkan/vulkan_core.h>
#ifdef __linux__
#if !defined(__FreeBSD__) && !defined(__MidnightBSD__)
#include <alloca.h>
#else
#include <stdlib.h>
#endif
#include <errno.h>
#include <stdio.h>

Some files were not shown because too many files have changed in this diff Show more