mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-04-06 07:15:35 -04:00
Compare commits
No commits in common. "master" and "1.5.85" have entirely different histories.
197 changed files with 5458 additions and 12782 deletions
|
|
@ -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
102
NEWS
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 hardware‑offload data path for HFP/HSP using the Bluetooth
|
||||
SIG–specified 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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -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.)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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': {},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
573
po/kk.po
|
|
@ -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
155
po/sl.po
|
|
@ -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
382
po/sv.po
|
|
@ -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)"
|
||||
|
|
|
|||
173
po/zh_CN.po
173
po/zh_CN.po
|
|
@ -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 "蓝牙免提"
|
||||
|
||||
|
|
|
|||
538
po/zh_TW.po
538
po/zh_TW.po
|
|
@ -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 "藍牙輸入"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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++) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
struct volume {
|
||||
uint32_t cpu_flags;
|
||||
uint32_t func_cpu_flags;
|
||||
const char *func_name;
|
||||
|
||||
struct spa_log *log;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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++;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue