diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 2918ce62e..448bfa06e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -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
diff --git a/NEWS b/NEWS
index 1f0a39a28..6e8b7f6f5 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,69 @@
+# PipeWire 1.6.2 (2026-03-16)
+
+This is a bugfix release that is API and ABI compatible with the previous
+1.6.x releases.
+
+## Highlights
+ - Fix a potential crash when the wrong memory was freed.
+ - Fix a optimization with shared memory over some links that could
+ cause errors later on.
+ - Fix SOFA filter and default control input in LADSPA and LV2.
+ - Some other small fixes and improvements.
+
+
+## PipeWire
+ - Remove an optimization to skip share mem in links, it causes problems
+ later on. (#5159)
+
+## Modules
+ - Don't try to free invalid memory or close invalid fds when the client
+ aborted before allocating buffer memory. (#5162)
+
+## SPA
+ - support ACP_IGNORE_DB in udev.
+ - Use 0x as a prefix for hex values.
+ - Mark Props as write-only in libcamera.
+ - Small optimization in the audio mixer.
+ - Fix initialization of control properties for SOFA and biquads in the
+ filter-graph. (#5152)
+ - Fix min/max default values for LADSPA and LV2.
+
+## JACK
+ - Fix jack_port_type_id(). Return values that are compatible with JACK1/2.
+
+
+Older versions:
+
+# PipeWire 1.6.1 (2026-03-09)
+
+This is a bugfix release that is API and ABI compatible with the previous
+1.6.x releases.
+
+## Highlights
+ - Fix socket activation, which could cause a failure to start PipeWire in
+ some setups.
+ - Fix crashes in many JACK apps when nodes/ports are quickly added/removed
+ such as when there are notifications (like when changing the volume in
+ KDE).
+ - Fix playback of encoded formats in pw-cat again.
+ - Some other smaller fixes and improvements.
+
+## Modules
+ - Fix socket activation. (#5140)
+ - Remove node.link-group from driver nodes.
+
+## SPA
+ - Fix the libcamera stop sequence.
+
+## JACK
+ - Never return NULL from jack_port_by_id(). (#3512)
+
+## GStreamer
+ - Improve the timestamps on buffers.
+
+## Tools
+ - Fix playback of encoded formats. (#5155)
+
# PipeWire 1.6.0 (2026-02-19)
This is the 1.6 release that is API and ABI compatible with previous
@@ -95,8 +161,6 @@ the 1.4 release last year, including:
- 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
diff --git a/doc/dox/config/pipewire-client.conf.5.md b/doc/dox/config/pipewire-client.conf.5.md
index 321538a79..db43839a0 100644
--- a/doc/dox/config/pipewire-client.conf.5.md
+++ b/doc/dox/config/pipewire-client.conf.5.md
@@ -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
diff --git a/doc/dox/config/pipewire-props.7.md b/doc/dox/config/pipewire-props.7.md
index 44b16f505..e561979d5 100644
--- a/doc/dox/config/pipewire-props.7.md
+++ b/doc/dox/config/pipewire-props.7.md
@@ -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.
@@ -1398,9 +1375,9 @@ 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.
+If not set or set to "balanced", both low-latency and high-reliabilty QoS configuration table are used.
This property is experimental.
-Available: low-latency, high-reliability, balanced
+Available: low-latency, high-reliabilty, balanced
## Node properties
@@ -1443,11 +1420,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
diff --git a/doc/dox/config/pipewire-pulse.conf.5.md b/doc/dox/config/pipewire-pulse.conf.5.md
index 9cc8d4c48..ad1b213c7 100644
--- a/doc/dox/config/pipewire-pulse.conf.5.md
+++ b/doc/dox/config/pipewire-pulse.conf.5.md
@@ -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
diff --git a/doc/dox/config/pipewire.conf.5.md b/doc/dox/config/pipewire.conf.5.md
index 8c551ba55..617f04751 100644
--- a/doc/dox/config/pipewire.conf.5.md
+++ b/doc/dox/config/pipewire.conf.5.md
@@ -6,55 +6,31 @@ The PipeWire server configuration file
# SYNOPSIS
-*$PIPEWIRE_CONFIG_DIR/pipewire/pipewire.conf*
-
*$XDG_CONFIG_HOME/pipewire/pipewire.conf*
*$(PIPEWIRE_CONFIG_DIR)/pipewire.conf*
*$(PIPEWIRE_CONFDATADIR)/pipewire.conf*
-*$PIPEWIRE_CONFIG_DIR/pipewire/pipewire.conf.d/*
-
*$(PIPEWIRE_CONFDATADIR)/pipewire.conf.d/*
*$(PIPEWIRE_CONFIG_DIR)/pipewire.conf.d/*
*$XDG_CONFIG_HOME/pipewire/pipewire.conf.d/*
-
# DESCRIPTION
PipeWire is a service that facilitates sharing of multimedia content
between devices and applications.
On startup, the daemon reads a main configuration file to configure
-itself. After that it will apply a set of drop-in config overrides.
+itself. It executes a series of commands listed in the config file.
-By default the pipewire daemon will read `pipewire.conf` and looks
-for drop-in config files in the `pipewire.conf.d` subdirectory.
-The environment variable `PIPEWIRE_CONFIG_NAME` can be used to specify
-an alternative config file name and the drop-in config file directory
-name (by appending `.d` to the config name).
-
-The config file and the drop-in config directories are looked up in
-the order listed in the [SYNOPSIS](#synopsis).
-
-If the environment variable `PIPEWIRE_CONFIG_DIR` is set, it is the
-only place where the main config file and the drop-in config files
-are looked up.
-
-If the environment variable `PIPEWIRE_CONFIG_PREFIX` contains an
-absolute path, it will be searched first for the main config file and
-the drop-in config files.
-If `PIPEWIRE_CONFIG_PREFIX` does not contain an absolute path, it is
-used as a subdirectory to locate the main config file and the drop-in
-config files.
-
-When the environment variable `PIPEWIRE_NO_CONFIG` is set to `true`,
-only the data config directory $(PIPEWIRE_CONFDATADIR) is searched.
-This is useful when you want to run with the default configuration
-without any system or user overrides.
+The config file is looked up in the order listed in the
+[SYNOPSIS](#synopsis). The environment variables `PIPEWIRE_CONFIG_DIR`,
+`PIPEWIRE_CONFIG_PREFIX` and `PIPEWIRE_CONFIG_NAME` can be used to
+specify an alternative config directory, subdirectory and file
+respectively.
Other PipeWire configuration files generally follow the same lookup
logic, replacing `pipewire.conf` with the name of the particular
@@ -62,19 +38,11 @@ config file.
# DROP-IN CONFIGURATION FILES @IDX@ pipewire.conf
-The config file drop-in overrides are looked up in the order
-of the `pipewire.conf.d` directories listed in the[SYNOPSIS](#synopsis).
-
All `*.conf` files in the `pipewire.conf.d/` directories are loaded
-in alphabetical order and merged into the main configuration.
-Dictionary sections are merged, overriding properties if they already
-existed, and array sections are appended to. The drop-in files have
-same format as the main configuration file, but only contain the
-settings to be modified.
-
-If a config overrides with the same name exists in multiple `conf.d`
-directories, the one from the last directory in the above search order
-is used.
+and merged into the configuration. Dictionary sections are merged,
+overriding properties if they already existed, and array sections are
+appended to. The drop-in files have same format as the main
+configuration file, but only contain the settings to be modified.
As the `pipewire.conf` configuration file contains various parts
that must be present for correct functioning, using drop-in files
diff --git a/doc/dox/internals/index.dox b/doc/dox/internals/index.dox
index 357e2f126..89d2e9da3 100644
--- a/doc/dox/internals/index.dox
+++ b/doc/dox/internals/index.dox
@@ -10,7 +10,6 @@
- \subpage page_objects_design
- \subpage page_library
- \subpage page_dma_buf
-- \subpage page_running
- \subpage page_scheduling
- \subpage page_driver
- \subpage page_latency
diff --git a/doc/dox/internals/latency.dox b/doc/dox/internals/latency.dox
index efc2b4c8b..0ff2cbe95 100644
--- a/doc/dox/internals/latency.dox
+++ b/doc/dox/internals/latency.dox
@@ -103,7 +103,7 @@ down and upstream.
# Async nodes
When a node has the node.async property set to true, it will be considered an async
-node and will be scheduled differently, see \ref page_scheduling .
+node and will be scheduled differently, see scheduling.dox.
A link between a port of an async node and another port (async or not) is called an
async link and will have the link.async=true property.
diff --git a/doc/dox/internals/midi.dox b/doc/dox/internals/midi.dox
index e89b24578..4c86c516b 100644
--- a/doc/dox/internals/midi.dox
+++ b/doc/dox/internals/midi.dox
@@ -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
diff --git a/doc/dox/internals/running.dox b/doc/dox/internals/running.dox
deleted file mode 100644
index e7ffe06db..000000000
--- a/doc/dox/internals/running.dox
+++ /dev/null
@@ -1,393 +0,0 @@
-/** \page page_running Node running
-
-This document tries to explain how the Nodes in a PipeWire graph become
-runnable so that they can be scheduled later.
-
-It also describes how nodes are grouped together and scheduled together.
-
-# Runnable Nodes
-
-A runnable node is a node that will participate in the dataflow in the
-PipeWire graph.
-
-Not all nodes should participate by default. For example, filters or device
-nodes that are not linked to any runnable nodes should not do useless
-processing.
-
-Nodes form one or more groups depending on properties and how they are
-linked. For each group, one driver is selected to run the group. Inside the
-group, all runnable nodes are scheduled by the group driver. If there are no
-runnable nodes in a group, the driver is not started.
-
-PipeWire provides mechanisms to precisely describe how and when nodes should
-be scheduled and grouped using:
-
- - port properties to control how port links control runnable state
- - node properties to control processing
- - grouping of nodes and internal links between nodes
-
-# Port passive modes
-
-A Port has 4 passive modes, this depends on the value of the `port.passive` property:
-
- - `false`, the port will make the peer active and an active peer will make this port
- active.
- - `true`, the port will not make the peer active and an active peer will not make this
- port active.
- - `follow`, the port will not make the peer active but an active peer will make this
- port active.
- - `follow-suspend`, the port will only make another follow-suspend peer active but any
- active peer will make this port active.
-
-The combination of these 4 modes on the output and input ports of a link results in a
-wide range of use cases.
-
-# Node passive modes
-
-A Node can have 10 passive modes, `node.passive` can be set to a comma separated list
-of the following values:
-
- - `false`, both input and output ports have `port.passive = false`
- - `in`, input ports have `port.passive = true`
- - `out`, output ports have `port.passive = true`
- - `true`, both input and output ports have `port.passive = true`. This is the same
- as `in,out`.
- - `in-follow`, input ports have `port.passive = follow`
- - `out-follow`, output ports have `port.passive = follow`
- - `follow`, input and output ports have `port.passive = follow`. This is the same
- as `in-follow,out-follow`.
- - `in-follow-suspend`, input ports have `port.passive = follow-suspend`
- - `out-follow-suspend`, output ports have `port.passive = follow-suspend`
- - `follow-suspend`, input and output ports have `port.passive = follow-suspend`.
- This is the same as `in-follow-suspend,out-follow-suspend`.
-
-Nodes by default have the `false` mode but nodes with the `media.class` property
-containing `Sink`, `Source` or `Duplex` receive the `follow-suspend` mode by default.
-
-Unless explicitly configured, ports inherit the mode from their parent node.
-
-# Updating the node runnable state
-
-We iterate all nodes A in the graph and look at its peers B.
-
-Based on the port passive modes of the port links we can decide if the nodes are
-runnable or not. A link will always make both nodes runnable or none.
-
-The following table decides the runnability of the 2 nodes based on the port.passive
-mode of the link between the 2 ports:
-
-```
- B-false B-true B-follow B-follow-suspend
-
-A-false X X X X
-A-true
-A-follow
-A-follow-suspend X
- Table 1
-```
-
-
-When a node is made runnable, the port passive mode will then decide if the peer ports
-should become active as well with the following table.
-
-```
- B-false B-true B-follow B-follow-suspend
-
-A-false X X X
-A-true X X X
-A-follow X X X
-A-follow-suspend X X X
- Table 2
-```
-
-So when A is runnable, all peers are activated except those with `port.passive=true`.
-
-When A is runnable, all the nodes that share the same group or link-group will also
-be made runnable.
-
-# Use cases
-
-Let's check some cases that we want to solve with these node and port properties.
-
-## Device nodes
-
-```
- +--------+ +--------+
- | ALSA | | ALSA |
- | Source | | Sink |
- | FL FL |
- | FR FR |
- +--------+ +--------+
-```
-
-Unlinked device nodes are supposed to stay suspended when nothing is linked to
-them.
-
-```
- +----------+ +--------+
- | playback | | ALSA |
- | | | Sink |
- | FL ------ FL |
- | FR ------ FR |
- +----------+ +--------+
-```
-
-An (active) player node linked to a device node should make both nodes runnable.
-
-Device nodes have the `port.passive = follow-suspend` property by default. The
-playback node has the `port.passive = false` by default.
-
-If we look at the playback node as A and the sink as B, both nodes will be made
-runnable according to Table 1.
-
-The two runnable nodes form a group and will be scheduled together. One of the
-nodes of a group with the `node.driver = true` property is selected as the
-driver. In the above case, that will be the ALSA Sink.
-
-Likewise, a capture node linked to an ALSA Source should make both nodes runnable.
-
-```
- +--------+ +---------+
- | ALSA | | capture |
- | Source | | |
- | FL ------ FL |
- | FR ------ FR |
- +--------+ +---------+
-```
-
-The ALSA Source is now the driver.
-
-Also, linking 2 device nodes together should make them runnable:
-
-```
- +--------+ +--------+
- | ALSA | | ALSA |
- | Source | | Sink |
- | FL ----------------------- FL |
- | FR ----------------------- FR |
- +--------+ +--------+
-```
-
-This is the case because in Table 1, the two `port.passive = follow-suspend` ports
-from the Source and Sink activate each other.
-
-## Filter nodes
-
-When there is a filter in front of the ALSA Sink, it should not make the filter and
-sink runnable.
-
-```
- +--------+ +--------+
- | filter | | ALSA |
- | | | Sink |
- FL FL ------ FL |
- FR FR ------ FR |
- +--------+ +--------+
-```
-
-The links between the filter and ALSA Sink are `port.passive = true` and don't make
-the nodes runnable.
-
-The filter needs to be made runnable via some other means to also make the ALSA
-Sink runnable, for example by linking a playback node:
-
-```
- +----------+ +--------+ +--------+
- | playback | | filter | | ALSA |
- | | | | | Sink |
- | FL ------ FL FL ------ FL |
- | FR ------ FR FR ------ FR |
- +----------+ +--------+ +--------+
-```
-
-The input port of the filter is `port.passive = follow-suspend' and so it can be
-activated by the playback node.
-
-Likewise, if the ALSA Sink is runnable, it should not automatically make the
-filter runnable. For example:
-
-```
- +--------+ +--------+
- | filter | | ALSA |
- | | | Sink |
- FL FL ---+-- FL |
- FR FR ---|+- FR |
- +--------+ || +--------+
- ||
- +----------+ ||
- | playback | ||
- | | ||
- | FL ---+|
- | FR ----+
- +----------+
-```
-
-Here the playback node makes the ALSA Sink runnable but the filter
-stays not-runnable because the output port is `port.passive = true`.
-
-## Device node monitor
-
-Consider the case where we have an ALSA Sink and a monitor stream
-connected to the sink monitor ports.
-
-```
- +-------+ +--------++
- | ALSA | | monitor |
- | Sink | | |
- FL FL ------ FL |
- FR FR ------ FR |
- +-------+ +---------+
-```
-
-We would like to keep the monitor stream and the ALSA sink suspended
-unless something else activates the ALSA Sink:
-
-
-```
- +----------+ +-------+ +---------+
- | playback | | ALSA | | monitor |
- | | | Sink | | |
- | FL ------ FL FL ------ FL |
- | FR ------ FR FR ------ FR |
- +----------+ +-------+ +---------+
-```
-
-We can do this by making the monitor stream input ports `port.passive = follow`
-and leave the ALSA Sink monitor output ports as `port.passive = follow-suspend`.
-
-According to Table 1, both nodes will not activate each other but when ALSA Sink
-becomes runnable because of playback, according to Table 2, the monitor will
-become runnable as well.
-
-Note how we need the distinction between `follow` and `follow-suspend` for this
-use case.
-
-## Node groups
-
-Normally when an application makes a capture and playback node, both nodes will
-be scheduled in different groups, consider:
-
-
-```
- +--------+ +---------+
- | ALSA | | capture |
- | Source | | |
- | FL ------ FL |
- | FR ------ FR |
- +--------+ +---------+
-
- +----------+ +--------+
- | playback | | ALSA |
- | | | Sink |
- | FL ------ FL |
- | FR ------ FR |
- +----------+ +--------+
-```
-
-Here we see 2 groups with the ALSA Source and ALSA Sink respectively as the
-drivers. Depending on the clocks of the nodes, the capture and playback will not
-be in sync. They will each run in their own time domain depending on the rate of
-the drivers.
-
-When we place a node.group property with the same value on the capture and playback
-nodes, they will be grouped together and this whole graph becomes one single group.
-
-Because there are 2 potential drivers in the group, the one with the highest
-`priority.driver` property is selected as the driver in the group. The other nodes
-in the group (including the other driver) become followers in the group.
-
-When a node becomes runnable, all other nodes with the same node.group property
-become runnable as well.
-
-## Node link groups
-
-When we have a filter that is constructed from two nodes, an input and an output
-node, we could use the `node.group` property to make sure they are both scheduled
-and made runnable together.
-
-```
- +--------+ +-------+ +--------+ +-------+
- | ALSA | | input | | output | | ALSA |
- | Source | | | | | | Sink |
- | FL ------ FL -- processing-- FL ------ FL |
- | FR ------ FR | | FR ------ FR |
- +--------+ +-------+ +--------+ +-------+
-```
-
-This would work fine but it does not describe that there is an implicit internal
-link between the input and output node. This information is important for the
-session manager to avoid linking the output node to the input node and make a
-loop.
-
-The `node.link-group` property can be used to both group the nodes together and
-descibe that they are internally linked together.
-
-When a node becomes runnable, all other nodes with the same node.link-group property
-become runnable as well.
-
-For the 2 node filters, like loopback and filter-chain, the same `port.passive`
-property rules apply as for the filter nodes. Note that for the virtual devices,
-the Source/Sink nodes will be `follow-suspend` by default and the other node should
-be set to `node.passive = true` to make the ports passive.
-
-## Want driver
-
-When there is no driver node in the group, nothing should be scheduled. This can
-happen when a playback node is linked to a capture node:
-
-```
- +--------+ +---------+
- | player | | capture |
- | | | |
- | FL ----------- FL |
- | FR ----------- FR |
- +--------+ +---------+
-```
-
-None of these nodes is a driver so there is no driver in the group and nothing
-will be scheduled.
-
-When one of the nodes has `node.want-driver = true` they are grouped and
-scheduled with a random driver node. This is often the driver node with the
-highest priority (usually the Dummy-Driver) or otherwise a driver that is already
-scheduling some other nodes.
-
-## Always process nodes
-
-A simple node, unlinked to anything should normally not run.
-
-```
- +--------+
- | player |
- | |
- | FL
- | FR
- +--------+
-```
-
-When the `node.always-process = true` property is set, the node will however be
-made runnable even if unlinked. This is done by adding the node to a random driver.
-
-`node.always-process = true` implies the `node.want-driver = true` property.
-
-## Sync groups
-
-In some cases, you only want to group nodes together depending on some condition.
-
-For example, when the JACK transport is activated, all nodes in the graph should share
-the same driver node, regardless of the grouping or linking of the nodes.
-
-This is done by setting the same node.sync-group property on all nodes (by default all
-nodes have `node.sync-group = group.sync.0`). When a node sets `node.sync = true` all
-the other nodes with the same `node.sync-group` property are grouped together.
-
-This can be used to implement the JACK transport. When the transport is started, the
-`node.sync=true` property is set and all nodes join one group with a shared driver
-and timing information.
-
-
-
-
-*/
-
-
diff --git a/doc/dox/internals/scheduling.dox b/doc/dox/internals/scheduling.dox
index c74124480..38b05596b 100644
--- a/doc/dox/internals/scheduling.dox
+++ b/doc/dox/internals/scheduling.dox
@@ -23,9 +23,6 @@ node is scheduled to run.
This document describes the processing that happens in the data processing
thread after the main thread has configured it.
-Before scheduling of the node happens, the scheduler will collect a list of
-nodes that are runnable, see \ref page_running
-
# Nodes
Nodes are objects with 0 or more input and output ports.
diff --git a/doc/dox/internals/tag.dox b/doc/dox/internals/tag.dox
index 4bb48c1bf..9374d10c0 100644
--- a/doc/dox/internals/tag.dox
+++ b/doc/dox/internals/tag.dox
@@ -54,11 +54,11 @@ in the graph. Output Tag objects on output ports are propagated to linked input
ports and input Tag objects on input ports are propagated to linked output ports.
If a port has links with multiple other ports, the Tag objects are merged by
-appending the dictionaries to the Tag param. Intermediate nodes or sinks are allowed
+appending the dictionaties to the Tag param. Intermediate nodes or sinks are allowed
to take the multiple dictionaries in a Tag and combine them into one dictionary if
they would like to do so.
-This way, Output Tag always describes the aggregated total upstream metadata of the
+This way, Output Tag always describes the aggragated total upstream metadata of
signal up to the port and Input tag describes the aggregated downstream metadata
of the signal from the port.
diff --git a/doc/dox/modules.dox b/doc/dox/modules.dox
index 85b0a1418..4e9358197 100644
--- a/doc/dox/modules.dox
+++ b/doc/dox/modules.dox
@@ -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
diff --git a/doc/dox/overview.dox b/doc/dox/overview.dox
index 9e2530163..1490cd444 100644
--- a/doc/dox/overview.dox
+++ b/doc/dox/overview.dox
@@ -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
diff --git a/doc/dox/programs/index.md b/doc/dox/programs/index.md
index 01ba07720..991ec7263 100644
--- a/doc/dox/programs/index.md
+++ b/doc/dox/programs/index.md
@@ -4,7 +4,6 @@ Manual pages:
- \subpage page_man_pipewire_1
- \subpage page_man_pipewire-pulse_1
-- \subpage page_man_pw-audioconvert_1
- \subpage page_man_pw-cat_1
- \subpage page_man_pw-cli_1
- \subpage page_man_pw-config_1
diff --git a/doc/dox/programs/pw-audioconvert.1.md b/doc/dox/programs/pw-audioconvert.1.md
deleted file mode 100644
index e78e4c7ec..000000000
--- a/doc/dox/programs/pw-audioconvert.1.md
+++ /dev/null
@@ -1,62 +0,0 @@
-\page page_man_pw-audioconvert_1 pw-audioconvert
-
-The PipeWire audioconvert utility
-
-# SYNOPSIS
-
-**pw-audioconvert** \[*OPTIONS*\] *INFILE* *OUTFILE*
-
-# DESCRIPTION
-
-Use the PipeWire audioconvert to convert input file to output file,
-following the given options.
-
-This is useful only for doing audio conversion but also apply effects
-on the audio using a filter-graph.
-
-It understands all audio file formats supported by `libsndfile` for input
-and output. The filename extension is used to guess the output file
-container and format with the WAV file format as the default.
-
-# OPTIONS
-
-\par -r RATE | \--rate=RATE
-Output sample rate. Default the same as the input sample rate.
-
-\par -f FORMAT | \--format=FORMAT
-Output sample format (s8 | s16 | s32 | f32 | f64). Default the same
-as the input format.
-
-\par -b BLOCKSIZE | \--blocksize=BLOCKSIZE
-Number of samples per iteration (default 4096)
-
-\par -P PROPERTIES | \--properties=PROPERTIES
-Set extra stream properties as a JSON object. One can also use @filename to
-read the JSON object with properties from filename.
-
-\par -c CHANNELS | \--channels=CHANNELS
-The number of output channels, default the same as the input.
-
-\par \--channel-map=VALUE
-The channelmap. Possible values include are either a predefined channel layout
-such as **Mono**, **Stereo**, **2.1**, **Quad**, **2.2**, **5.1**,
-or comma separated array of channel names such as **FL,FR**.
-
-\par -h
-Show help.
-
-\par -v
-Verbose operation.
-
-# EXAMPLES
-
-**pw-audioconvert** -r 48000 -f s32 in.wav out.wav
-
-# AUTHORS
-
-The PipeWire Developers <$(PACKAGE_BUGREPORT)>;
-PipeWire is available from <$(PACKAGE_URL)>
-
-# SEE ALSO
-
-\ref page_man_pipewire_1 "pipewire(1)"
diff --git a/doc/dox/programs/pw-cat.1.md b/doc/dox/programs/pw-cat.1.md
index 8ec02c711..b681e54a1 100644
--- a/doc/dox/programs/pw-cat.1.md
+++ b/doc/dox/programs/pw-cat.1.md
@@ -124,9 +124,6 @@ Set a node target (default auto). The value can be:
- \: 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)
diff --git a/doc/dox/programs/pw-top.1.md b/doc/dox/programs/pw-top.1.md
index 353015d1a..1207e3205 100644
--- a/doc/dox/programs/pw-top.1.md
+++ b/doc/dox/programs/pw-top.1.md
@@ -188,11 +188,6 @@ Quit
Clear the ERR counters. This does *not* clear the counters globally,
it will only reset the counters in this instance of *pw-top*.
-\par [f|F]
-Cycle through filter presets. If any nodes are filtered from view,
-the current preset will be indicated in the header bar. Only nodes
-with the indicated state or higher, will be printed.
-
# OPTIONS
\par -h | \--help
@@ -204,9 +199,6 @@ Run in non-interactive batch mode, similar to top\'s batch mode.
\par -n | \--iterations=NUMBER
Exit after NUMBER of batch iterations. Only used in batch mode.
-\par -f | \--filter=NUMBER
-Start with filter preset NUMBER selected.
-
\par -r | \--remote=NAME
The name the *remote* instance to monitor. If left unspecified, a
connection is made to the default PipeWire instance.
diff --git a/doc/meson.build b/doc/meson.build
index 645b4b26a..f4aa4ba6a 100644
--- a/doc/meson.build
+++ b/doc/meson.build
@@ -67,7 +67,6 @@ extra_docs = [
'dox/internals/session-manager.dox',
'dox/internals/objects.dox',
'dox/internals/audio.dox',
- 'dox/internals/running.dox',
'dox/internals/scheduling.dox',
'dox/internals/driver.dox',
'dox/internals/protocol.dox',
@@ -100,7 +99,6 @@ manpage_docs = [
'dox/config/libpipewire-modules.7.md',
'dox/programs/pipewire-pulse.1.md',
'dox/programs/pipewire.1.md',
- 'dox/programs/pw-audioconvert.1.md',
'dox/programs/pw-cat.1.md',
'dox/programs/pw-cli.1.md',
'dox/programs/pw-config.1.md',
diff --git a/meson.build b/meson.build
index 37badca51..536502a68 100644
--- a/meson.build
+++ b/meson.build
@@ -1,5 +1,5 @@
project('pipewire', ['c' ],
- version : '1.7.0',
+ version : '1.6.2',
license : [ 'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' ],
meson_version : '>= 0.61.1',
default_options : [ 'warning_level=3',
@@ -368,7 +368,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 +412,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': {},
}
diff --git a/meson_options.txt b/meson_options.txt
index 7c8cc15ba..206d68659 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -294,10 +294,6 @@ option('legacy-rtkit',
description: 'Build legacy rtkit module',
type: 'boolean',
value: true)
-option('avb-virtual',
- description: 'Enable AVB Virtual code for testing',
- type: 'feature',
- value: 'disabled')
option('avb',
description: 'Enable AVB code',
type: 'feature',
diff --git a/pipewire-jack/src/pipewire-jack.c b/pipewire-jack/src/pipewire-jack.c
index f1b707fe0..c7017e936 100644
--- a/pipewire-jack/src/pipewire-jack.c
+++ b/pipewire-jack/src/pipewire-jack.c
@@ -73,6 +73,7 @@ PW_LOG_TOPIC_STATIC(jack_log_topic, "jack");
#define TYPE_ID_IS_EVENT(t) ((t) >= TYPE_ID_MIDI && (t) <= TYPE_ID_UMP)
#define TYPE_ID_CAN_OSC(t) ((t) == TYPE_ID_MIDI || (t) == TYPE_ID_OSC)
+#define TYPE_ID_IS_HIDDEN(t) ((t) >= TYPE_ID_OTHER)
#define TYPE_ID_IS_COMPATIBLE(a,b)(((a) == (b)) || (TYPE_ID_IS_EVENT(a) && TYPE_ID_IS_EVENT(b)))
#define SELF_CONNECT_ALLOW 0
@@ -85,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 {
@@ -103,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;
};
@@ -1447,9 +1448,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:
@@ -1466,15 +1466,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;
+ 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;
- spa_pod_builder_control(&b, ev.time, ev_type);
- spa_pod_builder_bytes(&b, ev.buffer, ev.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;
+ 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;
@@ -1766,7 +1778,7 @@ static inline void process_empty(struct port *p, uint32_t frames)
case TYPE_ID_AUDIO:
ptr = get_buffer_output(p, frames, sizeof(float), NULL);
if (SPA_LIKELY(ptr != NULL))
- spa_memcpy(ptr, src, frames * sizeof(float));
+ memcpy(ptr, src, frames * sizeof(float));
break;
case TYPE_ID_MIDI:
case TYPE_ID_OSC:
@@ -1780,7 +1792,7 @@ static inline void process_empty(struct port *p, uint32_t frames)
* to do this concurrently */
b->datas[0].chunk->size = convert_from_event(src, midi_scratch,
MIDI_SCRATCH_FRAMES * sizeof(float), type);
- spa_memcpy(ptr, midi_scratch, b->datas[0].chunk->size);
+ memcpy(ptr, midi_scratch, b->datas[0].chunk->size);
}
break;
}
@@ -2198,7 +2210,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);
@@ -3714,8 +3726,8 @@ static int update_port_name(struct object *o, const char *name)
if (spa_streq(port_name, o->port.name))
return 0;
- snprintf(o->port.old_name, sizeof(o->port.old_name), "%s", o->port.name);
- snprintf(o->port.name, sizeof(o->port.name), "%s", port_name);
+ strcpy(o->port.old_name, o->port.name);
+ strcpy(o->port.name, port_name);
return 1;
}
@@ -3893,9 +3905,8 @@ static void registry_event_global(void *data, uint32_t id,
const char *name;
if ((str = spa_dict_lookup(props, PW_KEY_FORMAT_DSP)) == NULL)
- goto exit;
- if ((type_id = string_to_type(str)) == SPA_ID_INVALID ||
- !type_is_dsp(type_id))
+ str = "other";
+ if ((type_id = string_to_type(str)) == SPA_ID_INVALID)
goto exit;
if ((str = spa_dict_lookup(props, PW_KEY_NODE_ID)) == NULL)
@@ -4864,7 +4875,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;
@@ -5445,7 +5456,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 +5473,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
@@ -5531,8 +5542,7 @@ jack_port_t * jack_port_register (jack_client_t *client,
return NULL;
}
- if ((type_id = string_to_type(port_type)) == SPA_ID_INVALID ||
- !type_is_dsp(type_id)) {
+ if ((type_id = string_to_type(port_type)) == SPA_ID_INVALID) {
pw_log_warn("unknown port type %s", port_type);
return NULL;
}
@@ -5560,7 +5570,7 @@ jack_port_t * jack_port_register (jack_client_t *client,
o = p->object;
o->port.flags = flags;
- snprintf(o->port.name, sizeof(o->port.name), "%s", name);
+ strcpy(o->port.name, name);
o->port.type_id = type_id;
init_buffer(p, c->max_frames);
@@ -5851,11 +5861,11 @@ static void *get_buffer_input_midi(struct port *p, jack_nframes_t frames)
* the per port buffer. This makes it possible to call this function concurrently
* but also have different pointers per port */
convert_to_event(mix_info, n_mix_info, mb, p->client->fix_midi_events, p->object->port.type_id);
- spa_memcpy(ptr, mb, sizeof(struct midi_buffer) + (mb->event_count
+ memcpy(ptr, mb, sizeof(struct midi_buffer) + (mb->event_count
* sizeof(struct midi_event)));
if (mb->write_pos > 0) {
size_t offs = mb->buffer_size - mb->write_pos;
- spa_memcpy(SPA_PTROFF(ptr, offs, void), SPA_PTROFF(mb, offs, void), mb->write_pos);
+ memcpy(SPA_PTROFF(ptr, offs, void), SPA_PTROFF(mb, offs, void), mb->write_pos);
}
return ptr;
}
@@ -6514,10 +6524,10 @@ int jack_connect (jack_client_t *client,
if ((res = check_connect(c, src, dst)) != 1)
goto exit;
- snprintf(val[0], sizeof(val[0]), "%u", src->port.node_id);
- snprintf(val[1], sizeof(val[1]), "%u", src->id);
- snprintf(val[2], sizeof(val[2]), "%u", dst->port.node_id);
- snprintf(val[3], sizeof(val[3]), "%u", dst->id);
+ snprintf(val[0], sizeof(val[0]), "%d", src->port.node_id);
+ snprintf(val[1], sizeof(val[1]), "%d", src->id);
+ snprintf(val[2], sizeof(val[2]), "%d", dst->port.node_id);
+ snprintf(val[3], sizeof(val[3]), "%d", dst->id);
props = SPA_DICT_INIT(items, 0);
items[props.n_items++] = SPA_DICT_ITEM_INIT(PW_KEY_LINK_OUTPUT_NODE, val[0]);
@@ -6936,6 +6946,8 @@ const char ** jack_get_ports (jack_client_t *client,
continue;
pw_log_debug("%p: check port type:%d flags:%08lx name:\"%s\"", c,
o->port.type_id, o->port.flags, o->port.name);
+ if (TYPE_ID_IS_HIDDEN(o->port.type_id))
+ continue;
if (!SPA_FLAG_IS_SET(o->port.flags, flags))
continue;
if (str != NULL && o->port.node != NULL) {
diff --git a/pipewire-jack/src/ringbuffer.c b/pipewire-jack/src/ringbuffer.c
index be4014c23..ba1cc23f3 100644
--- a/pipewire-jack/src/ringbuffer.c
+++ b/pipewire-jack/src/ringbuffer.c
@@ -132,10 +132,10 @@ size_t jack_ringbuffer_read(jack_ringbuffer_t *rb, char *dest, size_t cnt)
n2 = 0;
}
- spa_memcpy (dest, &(rb->buf[rb->read_ptr]), n1);
+ memcpy (dest, &(rb->buf[rb->read_ptr]), n1);
rb->read_ptr = (rb->read_ptr + n1) & rb->size_mask;
if (n2) {
- spa_memcpy (dest + n1, &(rb->buf[rb->read_ptr]), n2);
+ memcpy (dest + n1, &(rb->buf[rb->read_ptr]), n2);
rb->read_ptr = (rb->read_ptr + n2) & rb->size_mask;
}
return to_read;
@@ -167,11 +167,11 @@ size_t jack_ringbuffer_peek(jack_ringbuffer_t *rb, char *dest, size_t cnt)
n2 = 0;
}
- spa_memcpy (dest, &(rb->buf[tmp_read_ptr]), n1);
+ memcpy (dest, &(rb->buf[tmp_read_ptr]), n1);
tmp_read_ptr = (tmp_read_ptr + n1) & rb->size_mask;
if (n2)
- spa_memcpy (dest + n1, &(rb->buf[tmp_read_ptr]), n2);
+ memcpy (dest + n1, &(rb->buf[tmp_read_ptr]), n2);
return to_read;
}
@@ -249,10 +249,10 @@ size_t jack_ringbuffer_write(jack_ringbuffer_t *rb, const char *src,
n2 = 0;
}
- spa_memcpy (&(rb->buf[rb->write_ptr]), src, n1);
+ memcpy (&(rb->buf[rb->write_ptr]), src, n1);
rb->write_ptr = (rb->write_ptr + n1) & rb->size_mask;
if (n2) {
- spa_memcpy (&(rb->buf[rb->write_ptr]), src + n1, n2);
+ memcpy (&(rb->buf[rb->write_ptr]), src + n1, n2);
rb->write_ptr = (rb->write_ptr + n2) & rb->size_mask;
}
return to_write;
diff --git a/pipewire-v4l2/src/pipewire-v4l2.c b/pipewire-v4l2/src/pipewire-v4l2.c
index 7a5e5c057..8fc07151a 100644
--- a/pipewire-v4l2/src/pipewire-v4l2.c
+++ b/pipewire-v4l2/src/pipewire-v4l2.c
@@ -2570,10 +2570,7 @@ static void *v4l2_mmap(void *addr, size_t length, int prot,
buf = &file->buffers[id];
data = &buf->buf->buffer->datas[0];
- if (pw_map_range_init(&range, data->mapoffset, data->maxsize, 1024) < 0) {
- res = MAP_FAILED;
- goto error_unlock;
- }
+ pw_map_range_init(&range, data->mapoffset, data->maxsize, 1024);
if (!SPA_FLAG_IS_SET(data->flags, SPA_DATA_FLAG_READABLE))
prot &= ~PROT_READ;
diff --git a/po/LINGUAS b/po/LINGUAS
index f5ef59cf7..8ebdbea2e 100644
--- a/po/LINGUAS
+++ b/po/LINGUAS
@@ -7,10 +7,9 @@ bn_IN
ca
cs
da
-de
de_CH
+de
el
-eo
es
fi
fr
@@ -37,15 +36,14 @@ oc
or
pa
pl
-pt
pt_BR
+pt
ro
ru
-si
sk
sl
-sr
sr@latin
+sr
sv
ta
te
@@ -53,3 +51,5 @@ tr
uk
zh_CN
zh_TW
+eo
+si
diff --git a/po/kk.po b/po/kk.po
index 507c967e0..6a00211f3 100644
--- a/po/kk.po
+++ b/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 , 2020-2026.
+# Baurzhan Muftakhidinov , 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 \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] [|-]\n"
+"%s [options] \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 "Құлаққап"
diff --git a/po/sr.po b/po/sr.po
index 9ae7491dc..247b58701 100644
--- a/po/sr.po
+++ b/po/sr.po
@@ -3,239 +3,111 @@
# This file is distributed under the same license as the pipewire package.
# Igor Miletic (Игор Милетић) , 2009.
# Miloš Komarčević , 2009, 2012.
-# Марко Костић , 2026
#
msgid ""
msgstr ""
"Project-Id-Version: pipewire\n"
-"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/-/"
-"issues\n"
-"POT-Creation-Date: 2026-04-09 14:32+0000\n"
-"PO-Revision-Date: 2026-04-11 15:05+0200\n"
-"Last-Translator: Марко Костић \n"
+"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/"
+"issues/new\n"
+"POT-Creation-Date: 2021-04-18 16:54+0800\n"
+"PO-Revision-Date: 2012-01-30 09:55+0000\n"
+"Last-Translator: Miloš Komarčević \n"
"Language-Team: Serbian (sr) \n"
-"Language: sr\n"
+"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
-"n%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);\n"
-"X-Generator: Poedit 3.9\n"
+"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
+"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\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 "Пајпвајер медијски систем"
#: src/daemon/pipewire.desktop.in:4
+msgid "PipeWire Media System"
+msgstr ""
+
+#: src/daemon/pipewire.desktop.in:5
msgid "Start the PipeWire Media System"
-msgstr "Покрени Пајпвајер медијски систем"
+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:1183
+#: src/tools/pw-cat.c:991
#, c-format
msgid ""
-"%s [options] [|-]\n"
+"%s [options] \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:1190
+#: 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"
-" -C --monitor Capture monitor ports (in recording "
-"mode)\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"
-" -C --monitor Хватај прикључнике за надзор (у "
-"режиму снимања)\n"
-" --latency Постави латентност чвора "
-"(подразумевано %s)\n"
-" Xјединица (јединица = s, ms, us, "
-"ns)\n"
-" или директни узорци (256)\n"
-" проток је онај из изворне "
-"датотеке\n"
-" -P --properties Постави својства чвора\n"
-"\n"
-#: src/tools/pw-cat.c:1209
+#: 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 Сирови (RAW) режим\n"
-" -M, --force-midi Приморај МИДИ формат, један од "
-"„midi“ или „ump“, (подразумевано ump)\n"
-" -n, --sample-count БРОЈ Заустави након БРОЈ узорака\n"
-"\n"
-#: src/tools/pw-cat.c:1234
+#: 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 МИДИ режим\n"
-" -d, --dsd DSD режим\n"
-" -o, --encoded Кодирани режим\n"
-" -s, --sysex SysEx режим\n"
-" -c, --midi-clip Режим МИДИ одсечка\n"
-"\n"
-#: src/tools/pw-cat.c:1839
-#, 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"
@@ -243,365 +115,376 @@ 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 "Професионални звук"
+msgstr ""
-#: spa/plugins/alsa/acp/acp.c:535 spa/plugins/alsa/acp/alsa-mixer.c:4699
-#: spa/plugins/bluez5/bluez5-device.c:2163
+#: 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
+#, fuzzy
msgid "Docking Station Microphone"
msgstr "Микрофон прикључне станице"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2724
+#: spa/plugins/alsa/acp/alsa-mixer.c:2712
+#, fuzzy
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:2596
+#: 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
+#, fuzzy
msgid "Front Microphone"
-msgstr "Предњи микрофон"
+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
+#, fuzzy
msgid "Rear Microphone"
-msgstr "Задњи микрофон"
+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
+#, fuzzy
msgid "Bass Boost"
-msgstr "Појачање баса"
+msgstr "Подизање"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2740
+#: spa/plugins/alsa/acp/alsa-mixer.c:2728
+#, fuzzy
msgid "No Bass Boost"
-msgstr "Без појачања баса"
+msgstr "Без подизања"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2741
-#: spa/plugins/bluez5/bluez5-device.c:2602
+#: spa/plugins/alsa/acp/alsa-mixer.c:2729
+#: spa/plugins/bluez5/bluez5-device.c:1150
msgid "Speaker"
-msgstr "Звучник"
+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:2608
-#: spa/plugins/bluez5/bluez5-device.c:2675
+#: 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
+#, fuzzy
msgid "Headset Microphone"
-msgstr "Микрофон са слушалицама"
+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
+#, fuzzy
msgid "Headphones Mono Output"
-msgstr "Моно излаз за слушалице"
+msgstr "Аналогни моно излаз"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2823
+#: spa/plugins/alsa/acp/alsa-mixer.c:2811
+#, fuzzy
msgid "Line Out"
-msgstr "Линијски излаз"
+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
+#, fuzzy
msgid "Speakers"
-msgstr "Говорници"
+msgstr "Аналогни стерео"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2826
+#: spa/plugins/alsa/acp/alsa-mixer.c:2814
msgid "HDMI / DisplayPort"
-msgstr "ХДМИ / Дисплеј-порт"
+msgstr ""
-#: spa/plugins/alsa/acp/alsa-mixer.c:2827
+#: spa/plugins/alsa/acp/alsa-mixer.c:2815
+#, fuzzy
msgid "Digital Output (S/PDIF)"
-msgstr "Дигитални излаз (С/ПДИФ)"
+msgstr "Дигитални стерео (HDMI)"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2828
+#: spa/plugins/alsa/acp/alsa-mixer.c:2816
+#, fuzzy
msgid "Digital Input (S/PDIF)"
-msgstr "Дигитални улаз (С/ПДИФ)"
+msgstr "Дигитални стерео (HDMI)"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2829
+#: spa/plugins/alsa/acp/alsa-mixer.c:2817
msgid "Multichannel Input"
-msgstr "Вишеканални улаз"
+msgstr ""
-#: spa/plugins/alsa/acp/alsa-mixer.c:2830
+#: spa/plugins/alsa/acp/alsa-mixer.c:2818
+#, fuzzy
msgid "Multichannel Output"
-msgstr "Вишеканални излаз"
+msgstr "Празан излаз"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2831
+#: spa/plugins/alsa/acp/alsa-mixer.c:2819
+#, fuzzy
msgid "Game Output"
-msgstr "Излаз за игре"
+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
+#, fuzzy
msgid "Chat Output"
-msgstr "Излаз за ћаскање"
+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 "Аналогни окружујући 7.1"
-#: 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:2584
+#: 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 "Слушалице са микрофоном"
+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 "Вишеканални"
+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
+#, fuzzy
msgid "Digital Surround 5.1 (IEC958/DTS)"
-msgstr "Дигитални окружујући 5.1 (IEC958/DTS)"
+msgstr "Дигитални окружујући 5.1 (IEC958/AC3)"
-#: 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
+#, fuzzy
msgid "Digital Surround 5.1 (HDMI)"
-msgstr "Дигитални окружујући 5.1 (HDMI)"
+msgstr "Дигитални окружујући 5.1 (IEC958/AC3)"
-#: 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 "Вишеканални дуплекс"
+msgstr ""
-#: spa/plugins/alsa/acp/alsa-mixer.c:4697
+#: spa/plugins/alsa/acp/alsa-mixer.c:4702
+#, fuzzy
msgid "Stereo Duplex"
-msgstr "Стерео дуплекс"
+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
-#, c-format
+#: spa/plugins/alsa/acp/alsa-mixer.c:4806
+#, fuzzy, c-format
msgid "%s Output"
-msgstr "%s излаз"
+msgstr "Празан излаз"
-#: spa/plugins/alsa/acp/alsa-mixer.c:4807
-#, c-format
+#: spa/plugins/alsa/acp/alsa-mixer.c:4813
+#, fuzzy, c-format
msgid "%s Input"
-msgstr "%s улаз"
+msgstr "Улаз"
-#: spa/plugins/alsa/acp/alsa-util.c:1233 spa/plugins/alsa/acp/alsa-util.c:1327
-#, c-format
+#: spa/plugins/alsa/acp/alsa-util.c:1175 spa/plugins/alsa/acp/alsa-util.c:1269
+#, fuzzy, c-format
msgid ""
"snd_pcm_avail() returned a value that is exceptionally large: %lu byte (%lu "
"ms).\n"
@@ -613,9 +496,9 @@ msgid_plural ""
"Most likely this is a bug in the ALSA driver '%s'. Please report this issue "
"to the ALSA developers."
msgstr[0] ""
-"snd_pcm_avail() је вратио вредност која је изузетно велика: %lu бајт (%lu "
+"snd_pcm_avail() је вратио вредност која је необично велика: %lu бајтова (%lu "
"ms).\n"
-"Највероватније је ово грешка у ALSA управљачком програму „%s“. Пријавите "
+"Ово је највероватније грешка у „%s“ ALSA управљачком програму. Пријавите "
"овај проблем ALSA програмерима."
msgstr[1] ""
"snd_pcm_avail() је вратио вредност која је необично велика: %lu бајтова (%lu "
@@ -628,49 +511,49 @@ msgstr[2] ""
"Ово је највероватније грешка у „%s“ ALSA управљачком програму. Пријавите "
"овај проблем ALSA програмерима."
-#: spa/plugins/alsa/acp/alsa-util.c:1299
-#, c-format
+#: spa/plugins/alsa/acp/alsa-util.c:1241
+#, fuzzy, c-format
msgid ""
-"snd_pcm_delay() returned a value that is exceptionally large: %li byte "
-"(%s%lu ms).\n"
+"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 бајт (%s%lu "
-"ms).\n"
-"Највероватније је ово грешка у ALSA управљачком програму „%s“. Пријавите "
+"snd_pcm_delay() је вратио вредност која је необично велика: %li бајтова (%s"
+"%lu ms).\n"
+"Ово је највероватније грешка у „%s“ ALSA управљачком програму. Пријавите "
"овај проблем ALSA програмерима."
msgstr[1] ""
-"snd_pcm_delay() је вратио вредност која је необично велика: %li бајтова "
-"(%s%lu ms).\n"
+"snd_pcm_delay() је вратио вредност која је необично велика: %li бајтова (%s"
+"%lu ms).\n"
"Ово је највероватније грешка у „%s“ ALSA управљачком програму. Пријавите "
"овај проблем ALSA програмерима."
msgstr[2] ""
-"snd_pcm_delay() је вратио вредност која је необично велика: %li бајтова "
-"(%s%lu ms).\n"
+"snd_pcm_delay() је вратио вредност која је необично велика: %li бајтова (%s"
+"%lu ms).\n"
"Ово је највероватније грешка у „%s“ ALSA управљачком програму. Пријавите "
"овај проблем ALSA програмерима."
-#: spa/plugins/alsa/acp/alsa-util.c:1346
-#, c-format
+#: spa/plugins/alsa/acp/alsa-util.c:1288
+#, fuzzy, c-format
msgid ""
"snd_pcm_avail_delay() returned strange values: delay %lu is less than avail "
"%lu.\n"
"Most likely this is a bug in the ALSA driver '%s'. Please report this issue "
"to the ALSA developers."
msgstr ""
-"snd_pcm_avail_delay() је вратио чудне вредности: кашњење %lu је мање од "
-"доступног %lu.\n"
-"Највероватније је ово грешка у ALSA управљачком програму „%s“. Пријавите "
+"snd_pcm_avail() је вратио вредност која је необично велика: %lu бајтова (%lu "
+"ms).\n"
+"Ово је највероватније грешка у „%s“ ALSA управљачком програму. Пријавите "
"овај проблем ALSA програмерима."
-#: spa/plugins/alsa/acp/alsa-util.c:1389
-#, c-format
+#: spa/plugins/alsa/acp/alsa-util.c:1331
+#, fuzzy, c-format
msgid ""
"snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu byte "
"(%lu ms).\n"
@@ -682,9 +565,9 @@ msgid_plural ""
"Most likely this is a bug in the ALSA driver '%s'. Please report this issue "
"to the ALSA developers."
msgstr[0] ""
-"snd_pcm_mmap_begin() је вратио вредност која је изузетно велика: %lu бајт "
-"(%lu ms).\n"
-"Највероватније је ово грешка у ALSA управљачком програму „%s“. Пријавите "
+"snd_pcm_mmap_begin() је вратио вредност која је необично велика: %lu "
+"бајтова (%lu ms).\n"
+"Ово је највероватније грешка у „%s“ ALSA управљачком програму. Пријавите "
"овај проблем ALSA програмерима."
msgstr[1] ""
"snd_pcm_mmap_begin() је вратио вредност која је необично велика: %lu "
@@ -697,120 +580,62 @@ msgstr[2] ""
"Ово је највероватније грешка у „%s“ ALSA управљачком програму. Пријавите "
"овај проблем 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:2174
+#: spa/plugins/bluez5/bluez5-device.c:1010
msgid "Audio Gateway (A2DP Source & HSP/HFP AG)"
-msgstr "Звучни мрежни пролаз (А2ДП извор и HSP/HFP AG)"
+msgstr ""
-#: spa/plugins/bluez5/bluez5-device.c:2203
-msgid "Audio Streaming for Hearing Aids (ASHA Sink)"
-msgstr "Струјање звука за слушне апарате (ASHA сливник)"
-
-#: spa/plugins/bluez5/bluez5-device.c:2246
+#: spa/plugins/bluez5/bluez5-device.c:1033
#, c-format
msgid "High Fidelity Playback (A2DP Sink, codec %s)"
-msgstr "Пуштање високе верности (А2ДП сливник, кодек %s)"
+msgstr ""
-#: spa/plugins/bluez5/bluez5-device.c:2249
+#: spa/plugins/bluez5/bluez5-device.c:1035
#, c-format
msgid "High Fidelity Duplex (A2DP Source/Sink, codec %s)"
-msgstr "Двосмерно високе верности (А2ДП извор/сливник, кодек %s)"
+msgstr ""
-#: spa/plugins/bluez5/bluez5-device.c:2257
+#: spa/plugins/bluez5/bluez5-device.c:1041
msgid "High Fidelity Playback (A2DP Sink)"
-msgstr "Пуштање високе верности (А2ДП сливник)"
+msgstr ""
-#: spa/plugins/bluez5/bluez5-device.c:2259
+#: spa/plugins/bluez5/bluez5-device.c:1043
msgid "High Fidelity Duplex (A2DP Source/Sink)"
-msgstr "Двосмерно високе верности (А2ДП извор/сливник)"
+msgstr ""
-#: spa/plugins/bluez5/bluez5-device.c:2281
-msgid "Auto: Prefer Quality (A2DP)"
-msgstr "Ауто: предност квалитету (А2ДП)"
-
-#: spa/plugins/bluez5/bluez5-device.c:2286
-msgid "Auto: Prefer Latency (A2DP)"
-msgstr "Ауто: предност кашњењу (А2ДП)"
-
-#: spa/plugins/bluez5/bluez5-device.c:2366
-#, c-format
-msgid "High Fidelity Playback (BAP Sink, codec %s)"
-msgstr "Пуштање високе верности (БАП сливник, кодек %s)"
-
-#: spa/plugins/bluez5/bluez5-device.c:2371
-#, c-format
-msgid "High Fidelity Input (BAP Source, codec %s)"
-msgstr "Улаз високе верности (БАП извор, кодек %s)"
-
-#: spa/plugins/bluez5/bluez5-device.c:2375
-#, c-format
-msgid "High Fidelity Duplex (BAP Source/Sink, codec %s)"
-msgstr "Двосмерно високе верности (БАП извор/сливник, кодек %s)"
-
-#: spa/plugins/bluez5/bluez5-device.c:2384
-msgid "High Fidelity Playback (BAP Sink)"
-msgstr "Пуштање високе верности (БАП сливник)"
-
-#: spa/plugins/bluez5/bluez5-device.c:2388
-msgid "High Fidelity Input (BAP Source)"
-msgstr "Улаз високе верности (БАП извор)"
-
-#: spa/plugins/bluez5/bluez5-device.c:2391
-msgid "High Fidelity Duplex (BAP Source/Sink)"
-msgstr "Двосмерно високе верности (БАП извор/сливник)"
-
-#: spa/plugins/bluez5/bluez5-device.c:2431
+#: spa/plugins/bluez5/bluez5-device.c:1070
#, c-format
msgid "Headset Head Unit (HSP/HFP, codec %s)"
-msgstr "Слушалице са микрофоном (ХСП/ХФП, кодек %s)"
+msgstr ""
-#: spa/plugins/bluez5/bluez5-device.c:2585
-#: spa/plugins/bluez5/bluez5-device.c:2590
-#: spa/plugins/bluez5/bluez5-device.c:2597
-#: spa/plugins/bluez5/bluez5-device.c:2603
-#: spa/plugins/bluez5/bluez5-device.c:2609
-#: spa/plugins/bluez5/bluez5-device.c:2615
-#: spa/plugins/bluez5/bluez5-device.c:2621
-#: spa/plugins/bluez5/bluez5-device.c:2627
-#: spa/plugins/bluez5/bluez5-device.c:2633
+#: spa/plugins/bluez5/bluez5-device.c:1074
+msgid "Headset Head Unit (HSP/HFP)"
+msgstr ""
+
+#: spa/plugins/bluez5/bluez5-device.c:1140
msgid "Handsfree"
-msgstr "Хендсфри"
+msgstr ""
-#: spa/plugins/bluez5/bluez5-device.c:2591
-msgid "Handsfree (HFP)"
-msgstr "Хендсфри (ХФП)"
+#: spa/plugins/bluez5/bluez5-device.c:1155
+#, fuzzy
+msgid "Headphone"
+msgstr "Аналогне слушалице"
-#: spa/plugins/bluez5/bluez5-device.c:2614
+#: spa/plugins/bluez5/bluez5-device.c:1160
msgid "Portable"
-msgstr "Преносно"
+msgstr ""
-#: spa/plugins/bluez5/bluez5-device.c:2620
+#: spa/plugins/bluez5/bluez5-device.c:1165
msgid "Car"
-msgstr "Кола"
+msgstr ""
-#: spa/plugins/bluez5/bluez5-device.c:2626
+#: spa/plugins/bluez5/bluez5-device.c:1170
msgid "HiFi"
-msgstr "Хи-фи"
+msgstr ""
-#: spa/plugins/bluez5/bluez5-device.c:2632
+#: spa/plugins/bluez5/bluez5-device.c:1175
msgid "Phone"
-msgstr "Телефон"
+msgstr ""
-#: spa/plugins/bluez5/bluez5-device.c:2639
+#: spa/plugins/bluez5/bluez5-device.c:1181
msgid "Bluetooth"
-msgstr "Блутут"
-
-#: spa/plugins/bluez5/bluez5-device.c:2640
-msgid "Bluetooth Handsfree"
-msgstr "Блутут хендсфри"
+msgstr ""
diff --git a/po/sr@latin.po b/po/sr@latin.po
index bc7572621..6f56d8608 100644
--- a/po/sr@latin.po
+++ b/po/sr@latin.po
@@ -1,241 +1,113 @@
-# Serbian translations for pipewire
+# Serbian(Latin) translations for pipewire
# Copyright (C) 2006 Lennart Poettering
# This file is distributed under the same license as the pipewire package.
# Igor Miletic (Igor Miletić) , 2009.
# Miloš Komarčević , 2009, 2012.
-# Marko Kostić , 2026
#
msgid ""
msgstr ""
"Project-Id-Version: pipewire\n"
-"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/-/"
-"issues\n"
-"POT-Creation-Date: 2026-04-09 14:32+0000\n"
-"PO-Revision-Date: 2026-04-11 15:05+0200\n"
-"Last-Translator: Marko Kostić \n"
+"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/"
+"issues/new\n"
+"POT-Creation-Date: 2021-04-18 16:54+0800\n"
+"PO-Revision-Date: 2012-01-30 09:55+0000\n"
+"Last-Translator: Miloš Komarčević \n"
"Language-Team: Serbian (sr) \n"
-"Language: sr\n"
+"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
-"n%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);\n"
-"X-Generator: Poedit 3.9\n"
+"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
+"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\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 [opcije]\n"
-" -h, --help Prikaži ovu pomoć\n"
-" -v, --verbose Povećaj opširnost za jedan nivo\n"
-" --version Prikaži izdanje\n"
-" -c, --config Učitaj podešavanja (podrazumevano "
-"%s)\n"
-" -P --properties Postavi svojstva konteksta\n"
-
-#: src/daemon/pipewire.desktop.in:3
-msgid "PipeWire Media System"
-msgstr "Pajpvajer medijski sistem"
#: src/daemon/pipewire.desktop.in:4
+msgid "PipeWire Media System"
+msgstr ""
+
+#: src/daemon/pipewire.desktop.in:5
msgid "Start the PipeWire Media System"
-msgstr "Pokreni Pajpvajer medijski sistem"
+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 "Tunel do %s%s%s"
+#: src/examples/media-session/alsa-monitor.c:526
+#: spa/plugins/alsa/acp/compat.c:187
+msgid "Built-in Audio"
+msgstr "Unutrašnji zvuk"
-#: src/modules/module-fallback-sink.c:40
-msgid "Dummy Output"
-msgstr "Lažan izlaz"
+#: src/examples/media-session/alsa-monitor.c:530
+#: spa/plugins/alsa/acp/compat.c:192
+msgid "Modem"
+msgstr "Modem"
-#: src/modules/module-pulse-tunnel.c:761
-#, c-format
-msgid "Tunnel for %s@%s"
-msgstr "Tunel za %s@%s"
-
-#: src/modules/module-zeroconf-discover.c:290
+#: src/examples/media-session/alsa-monitor.c:539
msgid "Unknown device"
-msgstr "Nepoznati uređaj"
+msgstr ""
-#: src/modules/module-zeroconf-discover.c:302
-#, c-format
-msgid "%s on %s@%s"
-msgstr "%s na %s@%s"
-
-#: src/modules/module-zeroconf-discover.c:306
-#, c-format
-msgid "%s on %s"
-msgstr "%s na %s"
-
-#: src/tools/pw-cat.c:269
-#, c-format
-msgid "Supported formats:\n"
-msgstr "Podržani formati:\n"
-
-#: src/tools/pw-cat.c:754
-#, c-format
-msgid "Supported channel layouts:\n"
-msgstr "Podržani rasporedi kanala:\n"
-
-#: src/tools/pw-cat.c:764
-#, c-format
-msgid "Supported channel layout aliases:\n"
-msgstr "Podržani nadimci rasporeda kanala:\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 "Podržani nazivi kanala:\n"
-
-#: src/tools/pw-cat.c:1183
+#: src/tools/pw-cat.c:991
#, c-format
msgid ""
-"%s [options] [|-]\n"
+"%s [options] \n"
" -h, --help Show this help\n"
" --version Show version\n"
" -v, --verbose Enable verbose operations\n"
"\n"
msgstr ""
-"%s [opcije] [|-]\n"
-" -h, --help Prikaži ovu pomoć\n"
-" --version Prikaži izdanje\n"
-" -v, --verbose Omogući opširan rad\n"
-"\n"
-#: src/tools/pw-cat.c:1190
+#: 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"
-" -C --monitor Capture monitor ports (in recording "
-"mode)\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 Naziv udaljenog uslužnog programa\n"
-" --media-type Postavi vrstu medija (podrazumevano "
-"%s)\n"
-" --media-category Postavi kategoriju medija "
-"(podrazumevano %s)\n"
-" --media-role Postavi ulogu medija (podrazumevano "
-"%s)\n"
-" --target Postavi ciljni serijski broj ili "
-"naziv čvora (podrazumevano %s)\n"
-" 0 znači bez povezivanja\n"
-" -C --monitor Hvataj priključnike za nadzor (u "
-"režimu snimanja)\n"
-" --latency Postavi latentnost čvora "
-"(podrazumevano %s)\n"
-" Xjedinica (jedinica = s, ms, us, "
-"ns)\n"
-" ili direktni uzorci (256)\n"
-" protok je onaj iz izvorne "
-"datoteke\n"
-" -P --properties Postavi svojstva čvora\n"
-"\n"
-#: src/tools/pw-cat.c:1209
+#: 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čestalost uzorkovanja (podrazumevano "
-"%u)\n"
-" --channels Broj kanala (podrazumevano %u)\n"
-" --channel-map Mapa kanala\n"
-" raspored kanala: „Stereo“, "
-"„5.1“,... ili\n"
-" zarezom razdvojen spisak naziva "
-"kanala: npr. „FL,FR“\n"
-" --list-layouts Ispiši podržane rasporede kanala\n"
-" --list-channel-names Ispiši podržane mape kanala\n"
-" --format Format uzorka (podrazumevano %s)\n"
-" --list-formats Ispiši podržane formate uzoraka\n"
-" --container Format kontejnera\n"
-" --list-containers Ispiši podržane kontejnere i "
-"proširenja\n"
-" --volume Jačina toka 0-1.0 (podrazumevano "
-"%.3f)\n"
-" -q --quality Kvalitet promene uzorkovanja (0 - 15) "
-"(podrazumevano %d)\n"
-" -a, --raw Sirovi (RAW) režim\n"
-" -M, --force-midi Primoraj MIDI format, jedan od "
-"„midi“ ili „ump“, (podrazumevano ump)\n"
-" -n, --sample-count BROJ Zaustavi nakon BROJ uzoraka\n"
-"\n"
-#: src/tools/pw-cat.c:1234
+#: 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 Režim puštanja\n"
-" -r, --record Režim snimanja\n"
-" -m, --midi MIDI režim\n"
-" -d, --dsd DSD režim\n"
-" -o, --encoded Kodirani režim\n"
-" -s, --sysex SysEx režim\n"
-" -c, --midi-clip Režim MIDI odsečka\n"
-"\n"
-#: src/tools/pw-cat.c:1839
-#, c-format
-msgid "Supported containers and extensions:\n"
-msgstr "Podržani kontejneri i proširenja:\n"
-
-#: src/tools/pw-cli.c:2386
+#: src/tools/pw-cli.c:2932
#, c-format
msgid ""
"%s [options] [command]\n"
@@ -243,365 +115,376 @@ 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 [opcije] [naredba]\n"
-" -h, --help Prikaži ovu pomoć\n"
-" --version Prikaži izdanje\n"
-" -d, --daemon Pokreni kao uslužni program "
-"(podrazumevano netačno)\n"
-" -r, --remote Naziv udaljenog uslužnog programa\n"
-" -m, --monitor Nadgledaj aktivnost\n"
-"\n"
-#: spa/plugins/alsa/acp/acp.c:361
+#: spa/plugins/alsa/acp/acp.c:290
msgid "Pro Audio"
-msgstr "Profesionalni zvuk"
+msgstr ""
-#: spa/plugins/alsa/acp/acp.c:535 spa/plugins/alsa/acp/alsa-mixer.c:4699
-#: spa/plugins/bluez5/bluez5-device.c:2163
+#: 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 "Isključeno"
-#: spa/plugins/alsa/acp/acp.c:618
-#, c-format
-msgid "%s [ALSA UCM error]"
-msgstr "%s [ALSA UCM greška]"
+#: spa/plugins/alsa/acp/channelmap.h:466
+msgid "(invalid)"
+msgstr "(neispravno)"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2721
+#: spa/plugins/alsa/acp/alsa-mixer.c:2709
msgid "Input"
msgstr "Ulaz"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2722
+#: spa/plugins/alsa/acp/alsa-mixer.c:2710
msgid "Docking Station Input"
msgstr "Ulaz priključne stanice"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2723
+#: spa/plugins/alsa/acp/alsa-mixer.c:2711
+#, fuzzy
msgid "Docking Station Microphone"
msgstr "Mikrofon priključne stanice"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2724
+#: spa/plugins/alsa/acp/alsa-mixer.c:2712
+#, fuzzy
msgid "Docking Station Line In"
msgstr "Ulaz priključne stanice"
-#: 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 "Linija u"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2726
-#: spa/plugins/alsa/acp/alsa-mixer.c:2810
-#: spa/plugins/bluez5/bluez5-device.c:2596
+#: 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 "Mikrofon"
-#: 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
+#, fuzzy
msgid "Front Microphone"
-msgstr "Prednji mikrofon"
+msgstr "Mikrofon priključne stanice"
-#: 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
+#, fuzzy
msgid "Rear Microphone"
-msgstr "Zadnji mikrofon"
+msgstr "Mikrofon"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2729
+#: spa/plugins/alsa/acp/alsa-mixer.c:2717
msgid "External Microphone"
msgstr "Spoljni mikrofon"
-#: 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 "Unutrašnji mikrofon"
-#: 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 "Radio"
-#: 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 "Video"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2733
+#: spa/plugins/alsa/acp/alsa-mixer.c:2721
msgid "Automatic Gain Control"
msgstr "Samostalna kontrola pojačanja"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2734
+#: spa/plugins/alsa/acp/alsa-mixer.c:2722
msgid "No Automatic Gain Control"
msgstr "Bez samostalne kontrole pojačanja"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2735
+#: spa/plugins/alsa/acp/alsa-mixer.c:2723
msgid "Boost"
msgstr "Podizanje"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2736
+#: spa/plugins/alsa/acp/alsa-mixer.c:2724
msgid "No Boost"
msgstr "Bez podizanja"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2737
+#: spa/plugins/alsa/acp/alsa-mixer.c:2725
msgid "Amplifier"
msgstr "Pojačalo"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2738
+#: spa/plugins/alsa/acp/alsa-mixer.c:2726
msgid "No Amplifier"
msgstr "Bez pojačala"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2739
+#: spa/plugins/alsa/acp/alsa-mixer.c:2727
+#, fuzzy
msgid "Bass Boost"
-msgstr "Pojačanje basa"
+msgstr "Podizanje"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2740
+#: spa/plugins/alsa/acp/alsa-mixer.c:2728
+#, fuzzy
msgid "No Bass Boost"
-msgstr "Bez pojačanja basa"
+msgstr "Bez podizanja"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2741
-#: spa/plugins/bluez5/bluez5-device.c:2602
+#: spa/plugins/alsa/acp/alsa-mixer.c:2729
+#: spa/plugins/bluez5/bluez5-device.c:1150
msgid "Speaker"
-msgstr "Zvučnik"
+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:2608
-#: spa/plugins/bluez5/bluez5-device.c:2675
+#: spa/plugins/alsa/acp/alsa-mixer.c:2730
+#: spa/plugins/alsa/acp/alsa-mixer.c:2808
msgid "Headphones"
msgstr "Analogne slušalice"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2809
+#: spa/plugins/alsa/acp/alsa-mixer.c:2797
msgid "Analog Input"
msgstr "Analogni ulaz"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2813
+#: spa/plugins/alsa/acp/alsa-mixer.c:2801
msgid "Dock Microphone"
msgstr "Mikrofon priključne stanice"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2815
+#: spa/plugins/alsa/acp/alsa-mixer.c:2803
+#, fuzzy
msgid "Headset Microphone"
-msgstr "Mikrofon sa slušalicama"
+msgstr "Mikrofon"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2819
+#: spa/plugins/alsa/acp/alsa-mixer.c:2807
msgid "Analog Output"
msgstr "Analogni izlaz"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2821
+#: spa/plugins/alsa/acp/alsa-mixer.c:2809
+#, fuzzy
msgid "Headphones 2"
-msgstr "Slušalice 2"
+msgstr "Analogne slušalice"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2822
+#: spa/plugins/alsa/acp/alsa-mixer.c:2810
+#, fuzzy
msgid "Headphones Mono Output"
-msgstr "Mono izlaz za slušalice"
+msgstr "Analogni mono izlaz"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2823
+#: spa/plugins/alsa/acp/alsa-mixer.c:2811
+#, fuzzy
msgid "Line Out"
-msgstr "Linijski izlaz"
+msgstr "Linija u"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2824
+#: spa/plugins/alsa/acp/alsa-mixer.c:2812
msgid "Analog Mono Output"
msgstr "Analogni mono izlaz"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2825
+#: spa/plugins/alsa/acp/alsa-mixer.c:2813
+#, fuzzy
msgid "Speakers"
-msgstr "Govornici"
+msgstr "Analogni stereo"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2826
+#: spa/plugins/alsa/acp/alsa-mixer.c:2814
msgid "HDMI / DisplayPort"
-msgstr "HDMI / Displej-port"
+msgstr ""
-#: spa/plugins/alsa/acp/alsa-mixer.c:2827
+#: spa/plugins/alsa/acp/alsa-mixer.c:2815
+#, fuzzy
msgid "Digital Output (S/PDIF)"
-msgstr "Digitalni izlaz (S/PDIF)"
+msgstr "Digitalni stereo (HDMI)"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2828
+#: spa/plugins/alsa/acp/alsa-mixer.c:2816
+#, fuzzy
msgid "Digital Input (S/PDIF)"
-msgstr "Digitalni ulaz (S/PDIF)"
+msgstr "Digitalni stereo (HDMI)"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2829
+#: spa/plugins/alsa/acp/alsa-mixer.c:2817
msgid "Multichannel Input"
-msgstr "Višekanalni ulaz"
+msgstr ""
-#: spa/plugins/alsa/acp/alsa-mixer.c:2830
+#: spa/plugins/alsa/acp/alsa-mixer.c:2818
+#, fuzzy
msgid "Multichannel Output"
-msgstr "Višekanalni izlaz"
+msgstr "Prazan izlaz"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2831
+#: spa/plugins/alsa/acp/alsa-mixer.c:2819
+#, fuzzy
msgid "Game Output"
-msgstr "Izlaz za igre"
+msgstr "Prazan izlaz"
-#: 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
+#, fuzzy
msgid "Chat Output"
-msgstr "Izlaz za ćaskanje"
+msgstr "Prazan izlaz"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2834
+#: spa/plugins/alsa/acp/alsa-mixer.c:2822
+#, fuzzy
msgid "Chat Input"
-msgstr "Ulaz za ćaskanje"
+msgstr "Ulaz"
-#: spa/plugins/alsa/acp/alsa-mixer.c:2835
+#: spa/plugins/alsa/acp/alsa-mixer.c:2823
+#, fuzzy
msgid "Virtual Surround 7.1"
-msgstr "Virtuelni okružujući zvuk 7.1"
+msgstr "Analogni okružujući 7.1"
-#: spa/plugins/alsa/acp/alsa-mixer.c:4522
+#: spa/plugins/alsa/acp/alsa-mixer.c:4527
msgid "Analog Mono"
msgstr "Analogni mono"
-#: spa/plugins/alsa/acp/alsa-mixer.c:4523
+#: spa/plugins/alsa/acp/alsa-mixer.c:4528
+#, fuzzy
msgid "Analog Mono (Left)"
-msgstr "Analogni mono (levi)"
+msgstr "Analogni mono"
-#: spa/plugins/alsa/acp/alsa-mixer.c:4524
+#: spa/plugins/alsa/acp/alsa-mixer.c:4529
+#, fuzzy
msgid "Analog Mono (Right)"
-msgstr "Analogni mono (desni)"
+msgstr "Analogni mono"
#. 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 "Analogni stereo"
-#: spa/plugins/alsa/acp/alsa-mixer.c:4526
+#: spa/plugins/alsa/acp/alsa-mixer.c:4531
msgid "Mono"
msgstr "Mono"
-#: spa/plugins/alsa/acp/alsa-mixer.c:4527
+#: spa/plugins/alsa/acp/alsa-mixer.c:4532
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:2584
+#: 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 "Slušalice sa mikrofonom"
+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 "Spikerfon"
+msgstr "Analogni stereo"
-#: 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 "Višekanalni"
+msgstr ""
-#: spa/plugins/alsa/acp/alsa-mixer.c:4539
+#: spa/plugins/alsa/acp/alsa-mixer.c:4544
msgid "Analog Surround 2.1"
msgstr "Analogni okružujući 2.1"
-#: spa/plugins/alsa/acp/alsa-mixer.c:4540
+#: spa/plugins/alsa/acp/alsa-mixer.c:4545
msgid "Analog Surround 3.0"
msgstr "Analogni okružujući 3.0"
-#: spa/plugins/alsa/acp/alsa-mixer.c:4541
+#: spa/plugins/alsa/acp/alsa-mixer.c:4546
msgid "Analog Surround 3.1"
msgstr "Analogni okružujući 3.1"
-#: spa/plugins/alsa/acp/alsa-mixer.c:4542
+#: spa/plugins/alsa/acp/alsa-mixer.c:4547
msgid "Analog Surround 4.0"
msgstr "Analogni okružujući 4.0"
-#: spa/plugins/alsa/acp/alsa-mixer.c:4543
+#: spa/plugins/alsa/acp/alsa-mixer.c:4548
msgid "Analog Surround 4.1"
msgstr "Analogni okružujući 4.1"
-#: spa/plugins/alsa/acp/alsa-mixer.c:4544
+#: spa/plugins/alsa/acp/alsa-mixer.c:4549
msgid "Analog Surround 5.0"
msgstr "Analogni okružujući 5.0"
-#: spa/plugins/alsa/acp/alsa-mixer.c:4545
+#: spa/plugins/alsa/acp/alsa-mixer.c:4550
msgid "Analog Surround 5.1"
msgstr "Analogni okružujući 5.1"
-#: spa/plugins/alsa/acp/alsa-mixer.c:4546
+#: spa/plugins/alsa/acp/alsa-mixer.c:4551
msgid "Analog Surround 6.0"
msgstr "Analogni okružujući 6.0"
-#: spa/plugins/alsa/acp/alsa-mixer.c:4547
+#: spa/plugins/alsa/acp/alsa-mixer.c:4552
msgid "Analog Surround 6.1"
msgstr "Analogni okružujući 6.1"
-#: spa/plugins/alsa/acp/alsa-mixer.c:4548
+#: spa/plugins/alsa/acp/alsa-mixer.c:4553
msgid "Analog Surround 7.0"
msgstr "Analogni okružujući 7.0"
-#: spa/plugins/alsa/acp/alsa-mixer.c:4549
+#: spa/plugins/alsa/acp/alsa-mixer.c:4554
msgid "Analog Surround 7.1"
msgstr "Analogni okružujući 7.1"
-#: spa/plugins/alsa/acp/alsa-mixer.c:4550
+#: spa/plugins/alsa/acp/alsa-mixer.c:4555
msgid "Digital Stereo (IEC958)"
msgstr "Digitalni stereo (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 "Digitalni okružujući 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 "Digitalni okružujući 5.1 (IEC958/AC3)"
-#: spa/plugins/alsa/acp/alsa-mixer.c:4553
+#: spa/plugins/alsa/acp/alsa-mixer.c:4558
+#, fuzzy
msgid "Digital Surround 5.1 (IEC958/DTS)"
-msgstr "Digitalni okružujući 5.1 (IEC958/DTS)"
+msgstr "Digitalni okružujući 5.1 (IEC958/AC3)"
-#: spa/plugins/alsa/acp/alsa-mixer.c:4554
+#: spa/plugins/alsa/acp/alsa-mixer.c:4559
msgid "Digital Stereo (HDMI)"
msgstr "Digitalni stereo (HDMI)"
-#: spa/plugins/alsa/acp/alsa-mixer.c:4555
+#: spa/plugins/alsa/acp/alsa-mixer.c:4560
+#, fuzzy
msgid "Digital Surround 5.1 (HDMI)"
-msgstr "Digitalni okružujući 5.1 (HDMI)"
+msgstr "Digitalni okružujući 5.1 (IEC958/AC3)"
-#: spa/plugins/alsa/acp/alsa-mixer.c:4556
+#: spa/plugins/alsa/acp/alsa-mixer.c:4561
msgid "Chat"
-msgstr "Ćaskanje"
+msgstr ""
-#: spa/plugins/alsa/acp/alsa-mixer.c:4557
+#: spa/plugins/alsa/acp/alsa-mixer.c:4562
msgid "Game"
-msgstr "Igrica"
+msgstr ""
-#: spa/plugins/alsa/acp/alsa-mixer.c:4691
+#: spa/plugins/alsa/acp/alsa-mixer.c:4696
msgid "Analog Mono Duplex"
msgstr "Dvosmerni analogni mono"
-#: spa/plugins/alsa/acp/alsa-mixer.c:4692
+#: spa/plugins/alsa/acp/alsa-mixer.c:4697
msgid "Analog Stereo Duplex"
msgstr "Dvosmerni analogni stereo"
-#: spa/plugins/alsa/acp/alsa-mixer.c:4695
+#: spa/plugins/alsa/acp/alsa-mixer.c:4700
msgid "Digital Stereo Duplex (IEC958)"
msgstr "Dvosmerni digitalni stereo (IEC958)"
-#: spa/plugins/alsa/acp/alsa-mixer.c:4696
+#: spa/plugins/alsa/acp/alsa-mixer.c:4701
msgid "Multichannel Duplex"
-msgstr "Višekanalni dupleks"
+msgstr ""
-#: spa/plugins/alsa/acp/alsa-mixer.c:4697
+#: spa/plugins/alsa/acp/alsa-mixer.c:4702
+#, fuzzy
msgid "Stereo Duplex"
-msgstr "Stereo dupleks"
+msgstr "Dvosmerni analogni stereo"
-#: spa/plugins/alsa/acp/alsa-mixer.c:4698
+#: spa/plugins/alsa/acp/alsa-mixer.c:4703
msgid "Mono Chat + 7.1 Surround"
-msgstr "Mono ćaskanje + 7.1 okružujući"
+msgstr ""
-#: spa/plugins/alsa/acp/alsa-mixer.c:4799
-#, c-format
+#: spa/plugins/alsa/acp/alsa-mixer.c:4806
+#, fuzzy, c-format
msgid "%s Output"
-msgstr "%s izlaz"
+msgstr "Prazan izlaz"
-#: spa/plugins/alsa/acp/alsa-mixer.c:4807
-#, c-format
+#: spa/plugins/alsa/acp/alsa-mixer.c:4813
+#, fuzzy, c-format
msgid "%s Input"
-msgstr "%s ulaz"
+msgstr "Ulaz"
-#: spa/plugins/alsa/acp/alsa-util.c:1233 spa/plugins/alsa/acp/alsa-util.c:1327
-#, c-format
+#: spa/plugins/alsa/acp/alsa-util.c:1175 spa/plugins/alsa/acp/alsa-util.c:1269
+#, fuzzy, c-format
msgid ""
"snd_pcm_avail() returned a value that is exceptionally large: %lu byte (%lu "
"ms).\n"
@@ -613,9 +496,9 @@ msgid_plural ""
"Most likely this is a bug in the ALSA driver '%s'. Please report this issue "
"to the ALSA developers."
msgstr[0] ""
-"snd_pcm_avail() je vratio vrednost koja je izuzetno velika: %lu bajt (%lu "
+"snd_pcm_avail() je vratio vrednost koja je neobično velika: %lu bajtova (%lu "
"ms).\n"
-"Najverovatnije je ovo greška u ALSA upravljačkom programu „%s“. Prijavite "
+"Ovo je najverovatnije greška u „%s“ ALSA upravljačkom programu. Prijavite "
"ovaj problem ALSA programerima."
msgstr[1] ""
"snd_pcm_avail() je vratio vrednost koja je neobično velika: %lu bajtova (%lu "
@@ -628,49 +511,49 @@ msgstr[2] ""
"Ovo je najverovatnije greška u „%s“ ALSA upravljačkom programu. Prijavite "
"ovaj problem ALSA programerima."
-#: spa/plugins/alsa/acp/alsa-util.c:1299
-#, c-format
+#: spa/plugins/alsa/acp/alsa-util.c:1241
+#, fuzzy, c-format
msgid ""
-"snd_pcm_delay() returned a value that is exceptionally large: %li byte "
-"(%s%lu ms).\n"
+"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() je vratio vrednost koja je izuzetno velika: %li bajt (%s%lu "
-"ms).\n"
-"Najverovatnije je ovo greška u ALSA upravljačkom programu „%s“. Prijavite "
+"snd_pcm_delay() je vratio vrednost koja je neobično velika: %li bajtova (%s"
+"%lu ms).\n"
+"Ovo je najverovatnije greška u „%s“ ALSA upravljačkom programu. Prijavite "
"ovaj problem ALSA programerima."
msgstr[1] ""
-"snd_pcm_delay() je vratio vrednost koja je neobično velika: %li bajtova "
-"(%s%lu ms).\n"
+"snd_pcm_delay() je vratio vrednost koja je neobično velika: %li bajtova (%s"
+"%lu ms).\n"
"Ovo je najverovatnije greška u „%s“ ALSA upravljačkom programu. Prijavite "
"ovaj problem ALSA programerima."
msgstr[2] ""
-"snd_pcm_delay() je vratio vrednost koja je neobično velika: %li bajtova "
-"(%s%lu ms).\n"
+"snd_pcm_delay() je vratio vrednost koja je neobično velika: %li bajtova (%s"
+"%lu ms).\n"
"Ovo je najverovatnije greška u „%s“ ALSA upravljačkom programu. Prijavite "
"ovaj problem ALSA programerima."
-#: spa/plugins/alsa/acp/alsa-util.c:1346
-#, c-format
+#: spa/plugins/alsa/acp/alsa-util.c:1288
+#, fuzzy, c-format
msgid ""
"snd_pcm_avail_delay() returned strange values: delay %lu is less than avail "
"%lu.\n"
"Most likely this is a bug in the ALSA driver '%s'. Please report this issue "
"to the ALSA developers."
msgstr ""
-"snd_pcm_avail_delay() je vratio čudne vrednosti: kašnjenje %lu je manje od "
-"dostupnog %lu.\n"
-"Najverovatnije je ovo greška u ALSA upravljačkom programu „%s“. Prijavite "
+"snd_pcm_avail() je vratio vrednost koja je neobično velika: %lu bajtova (%lu "
+"ms).\n"
+"Ovo je najverovatnije greška u „%s“ ALSA upravljačkom programu. Prijavite "
"ovaj problem ALSA programerima."
-#: spa/plugins/alsa/acp/alsa-util.c:1389
-#, c-format
+#: spa/plugins/alsa/acp/alsa-util.c:1331
+#, fuzzy, c-format
msgid ""
"snd_pcm_mmap_begin() returned a value that is exceptionally large: %lu byte "
"(%lu ms).\n"
@@ -682,9 +565,9 @@ msgid_plural ""
"Most likely this is a bug in the ALSA driver '%s'. Please report this issue "
"to the ALSA developers."
msgstr[0] ""
-"snd_pcm_mmap_begin() je vratio vrednost koja je izuzetno velika: %lu bajt "
-"(%lu ms).\n"
-"Najverovatnije je ovo greška u ALSA upravljačkom programu „%s“. Prijavite "
+"snd_pcm_mmap_begin() je vratio vrednost koja je neobično velika: %lu "
+"bajtova (%lu ms).\n"
+"Ovo je najverovatnije greška u „%s“ ALSA upravljačkom programu. Prijavite "
"ovaj problem ALSA programerima."
msgstr[1] ""
"snd_pcm_mmap_begin() je vratio vrednost koja je neobično velika: %lu "
@@ -697,120 +580,62 @@ msgstr[2] ""
"Ovo je najverovatnije greška u „%s“ ALSA upravljačkom programu. Prijavite "
"ovaj problem ALSA programerima."
-#: spa/plugins/alsa/acp/channelmap.h:460
-msgid "(invalid)"
-msgstr "(neispravno)"
-
-#: spa/plugins/alsa/acp/compat.c:194
-msgid "Built-in Audio"
-msgstr "Unutrašnji zvuk"
-
-#: spa/plugins/alsa/acp/compat.c:199
-msgid "Modem"
-msgstr "Modem"
-
-#: spa/plugins/bluez5/bluez5-device.c:2174
+#: spa/plugins/bluez5/bluez5-device.c:1010
msgid "Audio Gateway (A2DP Source & HSP/HFP AG)"
-msgstr "Zvučni mrežni prolaz (A2DP izvor i HSP/HFP AG)"
+msgstr ""
-#: spa/plugins/bluez5/bluez5-device.c:2203
-msgid "Audio Streaming for Hearing Aids (ASHA Sink)"
-msgstr "Strujanje zvuka za slušne aparate (ASHA slivnik)"
-
-#: spa/plugins/bluez5/bluez5-device.c:2246
+#: spa/plugins/bluez5/bluez5-device.c:1033
#, c-format
msgid "High Fidelity Playback (A2DP Sink, codec %s)"
-msgstr "Puštanje visoke vernosti (A2DP slivnik, kodek %s)"
+msgstr ""
-#: spa/plugins/bluez5/bluez5-device.c:2249
+#: spa/plugins/bluez5/bluez5-device.c:1035
#, c-format
msgid "High Fidelity Duplex (A2DP Source/Sink, codec %s)"
-msgstr "Dvosmerno visoke vernosti (A2DP izvor/slivnik, kodek %s)"
+msgstr ""
-#: spa/plugins/bluez5/bluez5-device.c:2257
+#: spa/plugins/bluez5/bluez5-device.c:1041
msgid "High Fidelity Playback (A2DP Sink)"
-msgstr "Puštanje visoke vernosti (A2DP slivnik)"
+msgstr ""
-#: spa/plugins/bluez5/bluez5-device.c:2259
+#: spa/plugins/bluez5/bluez5-device.c:1043
msgid "High Fidelity Duplex (A2DP Source/Sink)"
-msgstr "Dvosmerno visoke vernosti (A2DP izvor/slivnik)"
+msgstr ""
-#: spa/plugins/bluez5/bluez5-device.c:2281
-msgid "Auto: Prefer Quality (A2DP)"
-msgstr "Auto: prednost kvalitetu (A2DP)"
-
-#: spa/plugins/bluez5/bluez5-device.c:2286
-msgid "Auto: Prefer Latency (A2DP)"
-msgstr "Auto: prednost kašnjenju (A2DP)"
-
-#: spa/plugins/bluez5/bluez5-device.c:2366
-#, c-format
-msgid "High Fidelity Playback (BAP Sink, codec %s)"
-msgstr "Puštanje visoke vernosti (BAP slivnik, kodek %s)"
-
-#: spa/plugins/bluez5/bluez5-device.c:2371
-#, c-format
-msgid "High Fidelity Input (BAP Source, codec %s)"
-msgstr "Ulaz visoke vernosti (BAP izvor, kodek %s)"
-
-#: spa/plugins/bluez5/bluez5-device.c:2375
-#, c-format
-msgid "High Fidelity Duplex (BAP Source/Sink, codec %s)"
-msgstr "Dvosmerno visoke vernosti (BAP izvor/slivnik, kodek %s)"
-
-#: spa/plugins/bluez5/bluez5-device.c:2384
-msgid "High Fidelity Playback (BAP Sink)"
-msgstr "Puštanje visoke vernosti (BAP slivnik)"
-
-#: spa/plugins/bluez5/bluez5-device.c:2388
-msgid "High Fidelity Input (BAP Source)"
-msgstr "Ulaz visoke vernosti (BAP izvor)"
-
-#: spa/plugins/bluez5/bluez5-device.c:2391
-msgid "High Fidelity Duplex (BAP Source/Sink)"
-msgstr "Dvosmerno visoke vernosti (BAP izvor/slivnik)"
-
-#: spa/plugins/bluez5/bluez5-device.c:2431
+#: spa/plugins/bluez5/bluez5-device.c:1070
#, c-format
msgid "Headset Head Unit (HSP/HFP, codec %s)"
-msgstr "Slušalice sa mikrofonom (HSP/HFP, kodek %s)"
+msgstr ""
-#: spa/plugins/bluez5/bluez5-device.c:2585
-#: spa/plugins/bluez5/bluez5-device.c:2590
-#: spa/plugins/bluez5/bluez5-device.c:2597
-#: spa/plugins/bluez5/bluez5-device.c:2603
-#: spa/plugins/bluez5/bluez5-device.c:2609
-#: spa/plugins/bluez5/bluez5-device.c:2615
-#: spa/plugins/bluez5/bluez5-device.c:2621
-#: spa/plugins/bluez5/bluez5-device.c:2627
-#: spa/plugins/bluez5/bluez5-device.c:2633
+#: spa/plugins/bluez5/bluez5-device.c:1074
+msgid "Headset Head Unit (HSP/HFP)"
+msgstr ""
+
+#: spa/plugins/bluez5/bluez5-device.c:1140
msgid "Handsfree"
-msgstr "Hendsfri"
+msgstr ""
-#: spa/plugins/bluez5/bluez5-device.c:2591
-msgid "Handsfree (HFP)"
-msgstr "Hendsfri (HFP)"
+#: spa/plugins/bluez5/bluez5-device.c:1155
+#, fuzzy
+msgid "Headphone"
+msgstr "Analogne slušalice"
-#: spa/plugins/bluez5/bluez5-device.c:2614
+#: spa/plugins/bluez5/bluez5-device.c:1160
msgid "Portable"
-msgstr "Prenosno"
+msgstr ""
-#: spa/plugins/bluez5/bluez5-device.c:2620
+#: spa/plugins/bluez5/bluez5-device.c:1165
msgid "Car"
-msgstr "Kola"
+msgstr ""
-#: spa/plugins/bluez5/bluez5-device.c:2626
+#: spa/plugins/bluez5/bluez5-device.c:1170
msgid "HiFi"
-msgstr "Hi-fi"
+msgstr ""
-#: spa/plugins/bluez5/bluez5-device.c:2632
+#: spa/plugins/bluez5/bluez5-device.c:1175
msgid "Phone"
-msgstr "Telefon"
+msgstr ""
-#: spa/plugins/bluez5/bluez5-device.c:2639
+#: spa/plugins/bluez5/bluez5-device.c:1181
msgid "Bluetooth"
-msgstr "Blutut"
-
-#: spa/plugins/bluez5/bluez5-device.c:2640
-msgid "Bluetooth Handsfree"
-msgstr "Blutut hendsfri"
+msgstr ""
diff --git a/po/sv.po b/po/sv.po
index 1474f5084..0bc2796a4 100644
--- a/po/sv.po
+++ b/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 , 2008, 2012.
# Josef Andersson , 2014, 2017.
-# Anders Jonsson , 2021, 2022, 2023, 2024, 2025, 2026.
+# Anders Jonsson , 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 \n"
"Language-Team: Swedish \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] [|-]\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)"
diff --git a/po/zh_CN.po b/po/zh_CN.po
index 3236996bb..8be588b03 100644
--- a/po/zh_CN.po
+++ b/po/zh_CN.po
@@ -13,8 +13,8 @@ msgstr ""
"Project-Id-Version: pipewire.master-tx\n"
"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/pipewire/pipewire/-/"
"issues\n"
-"POT-Creation-Date: 2026-04-08 13:01+0000\n"
-"PO-Revision-Date: 2026-04-09 08:06+0800\n"
+"POT-Creation-Date: 2026-02-11 16:53+0000\n"
+"PO-Revision-Date: 2026-02-13 09:36+0800\n"
"Last-Translator: lumingzh \n"
"Language-Team: Chinese (China) \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,46 @@ msgstr "虚拟输出"
msgid "Tunnel for %s@%s"
msgstr "用于 %s@%s 的隧道"
-#: src/modules/module-zeroconf-discover.c:290
+#: src/modules/module-zeroconf-discover.c:326
msgid "Unknown device"
msgstr "未知设备"
-#: src/modules/module-zeroconf-discover.c:302
+#: src/modules/module-zeroconf-discover.c:338
#, 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:342
#, c-format
msgid "%s on %s"
msgstr "%2$s 上的 %1$s"
-#: src/tools/pw-cat.c:269
+#: src/tools/pw-cat.c:264
#, c-format
msgid "Supported formats:\n"
msgstr "支持的格式:\n"
-#: src/tools/pw-cat.c:754
+#: src/tools/pw-cat.c:749
#, c-format
msgid "Supported channel layouts:\n"
msgstr "支持的声道布局:\n"
-#: src/tools/pw-cat.c:764
+#: src/tools/pw-cat.c:759
#, c-format
msgid "Supported channel layout aliases:\n"
msgstr "支持的声道布局别名:\n"
-#: src/tools/pw-cat.c:766
+#: src/tools/pw-cat.c:761
#, c-format
msgid " %s -> %s\n"
msgstr " %s -> %s\n"
-#: src/tools/pw-cat.c:771
+#: src/tools/pw-cat.c:766
#, c-format
msgid "Supported channel names:\n"
msgstr "支持的声道名称:\n"
-#: src/tools/pw-cat.c:1183
+#: src/tools/pw-cat.c:1177
#, c-format
msgid ""
"%s [options] [|-]\n"
@@ -119,7 +119,7 @@ msgstr ""
" -v, --verbose 输出详细操作\n"
"\n"
-#: src/tools/pw-cat.c:1190
+#: src/tools/pw-cat.c:1184
#, c-format
msgid ""
" -R, --remote Remote daemon name\n"
@@ -129,8 +129,6 @@ msgid ""
" --target Set node target serial or name "
"(default %s)\n"
" 0 means don't link\n"
-" -C --monitor Capture monitor ports (in recording "
-"mode)\n"
" --latency Set node latency (default %s)\n"
" Xunit (unit = s, ms, us, ns)\n"
" or direct samples (256)\n"
@@ -145,7 +143,6 @@ msgstr ""
" --media-role 设置媒体角色 (默认 %s)\n"
" --target 设置节点目标序列或名称 (默认 %s)\n"
" 设为 0 则不链接节点\n"
-" -C --monitor 捕获监视器端口 (录制模式)\n"
" --latency 设置节点延迟 (默认 %s)\n"
" 时间 (单位可为 s, ms, us, ns)\n"
" 或样本数 (如256)\n"
@@ -154,7 +151,7 @@ msgstr ""
" -P --properties 设置节点属性\n"
"\n"
-#: src/tools/pw-cat.c:1209
+#: src/tools/pw-cat.c:1202
#, c-format
msgid ""
" --rate Sample rate (default %u)\n"
@@ -201,7 +198,7 @@ msgstr ""
" -n, --sample-count COUNT 计数采样后停止\n"
"\n"
-#: src/tools/pw-cat.c:1234
+#: src/tools/pw-cat.c:1227
msgid ""
" -p, --playback Playback mode\n"
" -r, --record Recording mode\n"
@@ -221,7 +218,7 @@ msgstr ""
" -c, --midi-clip MIDI 剪辑模式\n"
"\n"
-#: src/tools/pw-cat.c:1839
+#: src/tools/pw-cat.c:1827
#, c-format
msgid "Supported containers and extensions:\n"
msgstr "支持的容器和扩展:\n"
@@ -248,12 +245,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:2163
+#: spa/plugins/alsa/acp/acp.c:537 spa/plugins/alsa/acp/alsa-mixer.c:4699
+#: spa/plugins/bluez5/bluez5-device.c:2021
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 错误]"
@@ -281,7 +278,7 @@ msgstr "输入插孔"
#: spa/plugins/alsa/acp/alsa-mixer.c:2726
#: spa/plugins/alsa/acp/alsa-mixer.c:2810
-#: spa/plugins/bluez5/bluez5-device.c:2596
+#: spa/plugins/bluez5/bluez5-device.c:2422
msgid "Microphone"
msgstr "话筒"
@@ -347,15 +344,15 @@ msgid "No Bass Boost"
msgstr "无重低音增强"
#: spa/plugins/alsa/acp/alsa-mixer.c:2741
-#: spa/plugins/bluez5/bluez5-device.c:2602
+#: spa/plugins/bluez5/bluez5-device.c:2428
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:2608
-#: spa/plugins/bluez5/bluez5-device.c:2675
+#: spa/plugins/bluez5/bluez5-device.c:2434
+#: spa/plugins/bluez5/bluez5-device.c:2501
msgid "Headphones"
msgstr "模拟耳机"
@@ -465,7 +462,7 @@ msgstr "立体声"
#: spa/plugins/alsa/acp/alsa-mixer.c:4535
#: spa/plugins/alsa/acp/alsa-mixer.c:4693
-#: spa/plugins/bluez5/bluez5-device.c:2584
+#: spa/plugins/bluez5/bluez5-device.c:2410
msgid "Headset"
msgstr "耳机"
@@ -660,109 +657,101 @@ msgstr "内置音频"
msgid "Modem"
msgstr "调制解调器"
-#: spa/plugins/bluez5/bluez5-device.c:2174
+#: spa/plugins/bluez5/bluez5-device.c:2032
msgid "Audio Gateway (A2DP Source & HSP/HFP AG)"
msgstr "音频网关 (A2DP 信源 或 HSP/HFP 网关)"
-#: spa/plugins/bluez5/bluez5-device.c:2203
+#: spa/plugins/bluez5/bluez5-device.c:2061
msgid "Audio Streaming for Hearing Aids (ASHA Sink)"
msgstr "助听器音频流 (ASHA 信宿)"
-#: spa/plugins/bluez5/bluez5-device.c:2246
+#: spa/plugins/bluez5/bluez5-device.c:2104
#, c-format
msgid "High Fidelity Playback (A2DP Sink, codec %s)"
msgstr "高保真回放 (A2DP 信宿, 编码 %s)"
-#: spa/plugins/bluez5/bluez5-device.c:2249
+#: spa/plugins/bluez5/bluez5-device.c:2107
#, c-format
msgid "High Fidelity Duplex (A2DP Source/Sink, codec %s)"
msgstr "高保真双工 (A2DP 信源/信宿, 编码 %s)"
-#: spa/plugins/bluez5/bluez5-device.c:2257
+#: spa/plugins/bluez5/bluez5-device.c:2115
msgid "High Fidelity Playback (A2DP Sink)"
msgstr "高保真回放 (A2DP 信宿)"
-#: spa/plugins/bluez5/bluez5-device.c:2259
+#: spa/plugins/bluez5/bluez5-device.c:2117
msgid "High Fidelity Duplex (A2DP Source/Sink)"
msgstr "高保真双工 (A2DP 信源/信宿)"
-#: spa/plugins/bluez5/bluez5-device.c:2281
-msgid "Auto: Prefer Quality (A2DP)"
-msgstr "自动:质量优先 (A2DP)"
-
-#: spa/plugins/bluez5/bluez5-device.c:2286
-msgid "Auto: Prefer Latency (A2DP)"
-msgstr "自动:延迟优先 (A2DP)"
-
-#: spa/plugins/bluez5/bluez5-device.c:2366
+#: 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:2371
+#: 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:2375
+#: 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:2384
+#: spa/plugins/bluez5/bluez5-device.c:2212
msgid "High Fidelity Playback (BAP Sink)"
msgstr "高保真回放 (BAP 信宿)"
-#: spa/plugins/bluez5/bluez5-device.c:2388
+#: spa/plugins/bluez5/bluez5-device.c:2216
msgid "High Fidelity Input (BAP Source)"
msgstr "高保真输入 (BAP 信源)"
-#: spa/plugins/bluez5/bluez5-device.c:2391
+#: spa/plugins/bluez5/bluez5-device.c:2219
msgid "High Fidelity Duplex (BAP Source/Sink)"
msgstr "高保真双工 (BAP 信源/信宿)"
-#: spa/plugins/bluez5/bluez5-device.c:2431
+#: spa/plugins/bluez5/bluez5-device.c:2259
#, c-format
msgid "Headset Head Unit (HSP/HFP, codec %s)"
msgstr "头戴式耳机单元 (HSP/HFP, 编码 %s)"
-#: spa/plugins/bluez5/bluez5-device.c:2585
-#: spa/plugins/bluez5/bluez5-device.c:2590
-#: spa/plugins/bluez5/bluez5-device.c:2597
-#: spa/plugins/bluez5/bluez5-device.c:2603
-#: spa/plugins/bluez5/bluez5-device.c:2609
-#: spa/plugins/bluez5/bluez5-device.c:2615
-#: spa/plugins/bluez5/bluez5-device.c:2621
-#: spa/plugins/bluez5/bluez5-device.c:2627
-#: spa/plugins/bluez5/bluez5-device.c:2633
+#: 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 "免提"
-#: spa/plugins/bluez5/bluez5-device.c:2591
+#: spa/plugins/bluez5/bluez5-device.c:2417
msgid "Handsfree (HFP)"
msgstr "免提(HFP)"
-#: spa/plugins/bluez5/bluez5-device.c:2614
+#: spa/plugins/bluez5/bluez5-device.c:2440
msgid "Portable"
msgstr "便携式"
-#: spa/plugins/bluez5/bluez5-device.c:2620
+#: spa/plugins/bluez5/bluez5-device.c:2446
msgid "Car"
msgstr "车内"
-#: spa/plugins/bluez5/bluez5-device.c:2626
+#: spa/plugins/bluez5/bluez5-device.c:2452
msgid "HiFi"
msgstr "高保真"
-#: spa/plugins/bluez5/bluez5-device.c:2632
+#: spa/plugins/bluez5/bluez5-device.c:2458
msgid "Phone"
msgstr "电话"
-#: spa/plugins/bluez5/bluez5-device.c:2639
+#: spa/plugins/bluez5/bluez5-device.c:2465
msgid "Bluetooth"
msgstr "蓝牙"
-#: spa/plugins/bluez5/bluez5-device.c:2640
+#: spa/plugins/bluez5/bluez5-device.c:2466
msgid "Bluetooth Handsfree"
msgstr "蓝牙免提"
diff --git a/po/zh_TW.po b/po/zh_TW.po
index ab41369cf..1a768a992 100644
--- a/po/zh_TW.po
+++ b/po/zh_TW.po
@@ -4,221 +4,110 @@
#
# Cheng-Chia Tseng , 2010, 2012.
# pan93412 , 2020.
-# SPDX-FileCopyrightText: 2026 Kisaragi Hiu
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 \n"
-"Language-Team: Chinese (Taiwan) \n"
+"POT-Creation-Date: 2021-04-18 16:54+0800\n"
+"PO-Revision-Date: 2020-01-11 13:49+0800\n"
+"Last-Translator: pan93412 \n"
+"Language-Team: Chinese \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] [|-]\n"
+"%s [options] \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 "藍牙輸入"
diff --git a/spa/include/spa/param/audio/dsd-utils.h b/spa/include/spa/param/audio/dsd-utils.h
index 9af62d99d..2dab7cc19 100644
--- a/spa/include/spa/param/audio/dsd-utils.h
+++ b/spa/include/spa/param/audio/dsd-utils.h
@@ -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);
diff --git a/spa/include/spa/param/audio/layout-types.h b/spa/include/spa/param/audio/layout-types.h
index 45cca3a6f..33650202a 100644
--- a/spa/include/spa/param/audio/layout-types.h
+++ b/spa/include/spa/param/audio/layout-types.h
@@ -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;
}
diff --git a/spa/include/spa/param/audio/raw-json.h b/spa/include/spa/param/audio/raw-json.h
index 11540a6b0..6b1b25164 100644
--- a/spa/include/spa/param/audio/raw-json.h
+++ b/spa/include/spa/param/audio/raw-json.h
@@ -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);
}
diff --git a/spa/include/spa/param/audio/raw-utils.h b/spa/include/spa/param/audio/raw-utils.h
index 1e4ae2758..3f81b4a92 100644
--- a/spa/include/spa/param/audio/raw-utils.h
+++ b/spa/include/spa/param/audio/raw-utils.h
@@ -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);
diff --git a/spa/include/spa/pod/body.h b/spa/include/spa/pod/body.h
index 90eadb82e..4ab5d8e5f 100644
--- a/spa/include/spa/pod/body.h
+++ b/spa/include/spa/pod/body.h
@@ -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)
diff --git a/spa/include/spa/support/cpu.h b/spa/include/spa/support/cpu.h
index 2faf42154..c69338855 100644
--- a/spa/include/spa/support/cpu.h
+++ b/spa/include/spa/support/cpu.h
@@ -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 */
diff --git a/spa/include/spa/support/system.h b/spa/include/spa/support/system.h
index 56ceea648..07a31a55f 100644
--- a/spa/include/spa/support/system.h
+++ b/spa/include/spa/support/system.h
@@ -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
+ void *data;
};
-#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)
diff --git a/spa/include/spa/utils/endian.h b/spa/include/spa/utils/endian.h
index 0793ed412..2d002d453 100644
--- a/spa/include/spa/utils/endian.h
+++ b/spa/include/spa/utils/endian.h
@@ -5,7 +5,7 @@
#ifndef SPA_ENDIAN_H
#define SPA_ENDIAN_H
-#if defined(__MidnightBSD__)
+#if defined(__FreeBSD__) || defined(__MidnightBSD__)
#include
#define bswap_16 bswap16
#define bswap_32 bswap32
diff --git a/spa/include/spa/utils/json-builder.h b/spa/include/spa/utils/json-builder.h
deleted file mode 100644
index b41ea9774..000000000
--- a/spa/include/spa/utils/json-builder.h
+++ /dev/null
@@ -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
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-
-#ifdef __cplusplus
-extern "C" {
-#else
-#include
-#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 */
diff --git a/spa/include/spa/utils/json-core.h b/spa/include/spa/utils/json-core.h
index 9745000cf..5616bffe1 100644
--- a/spa/include/spa/utils/json-core.h
+++ b/spa/include/spa/utils/json-core.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)
{
diff --git a/spa/include/spa/utils/string.h b/spa/include/spa/utils/string.h
index 35e4ea026..bab60de2b 100644
--- a/spa/include/spa/utils/string.h
+++ b/spa/include/spa/utils/string.h
@@ -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;
}
diff --git a/spa/lib/lib.c b/spa/lib/lib.c
index 3ded776ad..0aa35fae3 100644
--- a/spa/lib/lib.c
+++ b/spa/lib/lib.c
@@ -2,6 +2,7 @@
#undef SPA_AUDIO_MAX_CHANNELS
#define SPA_API_IMPL SPA_EXPORT
+#include
#include
#include
#include
@@ -125,17 +126,16 @@
#include
#include
#include
-#include
#include
#include
#include
#include
#include
#include
+#include
#include
#include
#include
-#include
#include
#include
#include
@@ -158,7 +158,6 @@
#include
#include
#include
-#include
#include
#include
#include
diff --git a/spa/plugins/aec/aec-webrtc.cpp b/spa/plugins/aec/aec-webrtc.cpp
index 2e451d851..7b8cafcde 100644
--- a/spa/plugins/aec/aec-webrtc.cpp
+++ b/spa/plugins/aec/aec-webrtc.cpp
@@ -39,7 +39,7 @@ struct impl_data {
std::unique_ptr 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::Create(config));
#elif defined(HAVE_WEBRTC1)
diff --git a/spa/plugins/alsa/acp-tool.c b/spa/plugins/alsa/acp-tool.c
index 824d69df6..c12401100 100644
--- a/spa/plugins/alsa/acp-tool.c
+++ b/spa/plugins/alsa/acp-tool.c
@@ -10,9 +10,7 @@
#include
#include
#include
-#ifdef __linux__
#include
-#endif
#include
#include
diff --git a/spa/plugins/alsa/acp/compat.h b/spa/plugins/alsa/acp/compat.h
index 87151d197..f7592e1a6 100644
--- a/spa/plugins/alsa/acp/compat.h
+++ b/spa/plugins/alsa/acp/compat.h
@@ -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)
diff --git a/spa/plugins/alsa/alsa-acp-device.c b/spa/plugins/alsa/alsa-acp-device.c
index eb38b3f9e..44342a7a3 100644
--- a/spa/plugins/alsa/alsa-acp-device.c
+++ b/spa/plugins/alsa/alsa-acp-device.c
@@ -990,22 +990,11 @@ static void card_port_available(void *data, uint32_t index,
for (i = 0; i < p->n_devices; i++) {
struct acp_device *d = p->devices[i];
- struct acp_port *active_port = NULL;
- uint32_t j;
uint32_t best;
if (!(d->flags & ACP_DEVICE_ACTIVE))
continue;
- for (j = 0; j < d->n_ports; j++) {
- if (d->ports[j]->flags & ACP_PORT_ACTIVE) {
- active_port = d->ports[j];
- break;
- }
- }
- if (active_port != NULL && active_port->available != ACP_AVAILABLE_NO)
- continue;
-
best = acp_device_find_best_port_index(d, NULL);
acp_device_set_port(d, best, 0);
}
diff --git a/spa/plugins/alsa/alsa-seq-bridge.c b/spa/plugins/alsa/alsa-seq-bridge.c
index 977c74e0a..06c5bc28f 100644
--- a/spa/plugins/alsa/alsa-seq-bridge.c
+++ b/spa/plugins/alsa/alsa-seq-bridge.c
@@ -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;
@@ -261,7 +261,7 @@ static void emit_port_info(struct seq_state *this, struct seq_port *port, bool f
if (spa_strstartswith(pn, client_name))
pn += strlen(client_name);
- snprintf(name, sizeof(name), "%s%s:%s (%s)", prefix,
+ snprintf(name, sizeof(name), "%s%s%s (%s)", prefix,
client_name, pn, dir);
clean_name(name);
@@ -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,
@@ -388,29 +385,13 @@ static struct seq_port *alloc_port(struct seq_state *state, struct seq_stream *s
return port;
}
-static int do_port_clear(struct spa_loop *loop, bool async, uint32_t seq,
- const void *data, size_t size, void *user_data)
-{
- struct seq_port *port = user_data;
- port->io = NULL;
- if (port->mixing) {
- spa_list_remove(&port->mix_link);
- port->mixing = false;
- }
- return 0;
-}
-
static void free_port(struct seq_state *state, struct seq_stream *stream, struct seq_port *port)
{
stream->ports[port->id] = NULL;
spa_list_remove(&port->link);
- spa_loop_locked(state->data_loop,
- do_port_clear, SPA_ID_INVALID, NULL, 0, port);
-
spa_node_emit_port_info(&state->hooks,
port->direction, port->id, NULL);
-
spa_zero(*port);
spa_list_append(&state->free_list, &port->link);
}
@@ -457,7 +438,7 @@ static void update_stream_port(struct seq_state *state, struct seq_stream *strea
struct seq_port *port = find_port(state, stream, addr);
if (info == NULL) {
- spa_log_debug(state->log, "free port %d.%d %p", addr->client, addr->port, port);
+ spa_log_debug(state->log, "free port %d.%d", addr->client, addr->port);
if (port)
free_port(state, stream, port);
} else {
@@ -469,7 +450,7 @@ static void update_stream_port(struct seq_state *state, struct seq_stream *strea
init_port(state, port, addr, snd_seq_port_info_get_type(info));
} else if (port != NULL) {
if ((caps & stream->caps) != stream->caps) {
- spa_log_debug(state->log, "free port %d.%d %p", addr->client, addr->port, port);
+ spa_log_debug(state->log, "free port %d.%d", addr->client, addr->port);
free_port(state, stream, port);
}
else {
@@ -486,8 +467,8 @@ static int on_port_info(void *data, const snd_seq_addr_t *addr, const snd_seq_po
struct seq_state *state = data;
if (info == NULL) {
- update_stream_port(state, &state->streams[SPA_DIRECTION_INPUT], addr, 0, NULL);
- update_stream_port(state, &state->streams[SPA_DIRECTION_OUTPUT], addr, 0, NULL);
+ update_stream_port(state, &state->streams[SPA_DIRECTION_INPUT], addr, 0, info);
+ update_stream_port(state, &state->streams[SPA_DIRECTION_OUTPUT], addr, 0, info);
} else {
unsigned int caps = snd_seq_port_info_get_capability(info);
@@ -520,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;
@@ -544,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:
@@ -563,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:
@@ -836,7 +800,7 @@ impl_node_port_set_io(void *object,
info.data = data;
info.size = size;
- spa_log_debug(this->log, "%p: %p: io %d.%d %d %p %zd", this, port,
+ spa_log_debug(this->log, "%p: io %d.%d %d %p %zd", this,
direction, port_id, id, data, size);
switch (id) {
@@ -857,7 +821,7 @@ static int impl_node_port_reuse_buffer(void *object, uint32_t port_id, uint32_t
spa_return_val_if_fail(this != NULL, -EINVAL);
- spa_return_val_if_fail(CHECK_PORT(this, SPA_DIRECTION_OUTPUT, port_id), -EINVAL);
+ spa_return_val_if_fail(!CHECK_PORT(this, SPA_DIRECTION_OUTPUT, port_id), -EINVAL);
port = GET_PORT(this, SPA_DIRECTION_OUTPUT, port_id);
@@ -991,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;
diff --git a/spa/plugins/alsa/alsa-seq.c b/spa/plugins/alsa/alsa-seq.c
index c25b49420..8a4ba369c 100644
--- a/spa/plugins/alsa/alsa-seq.c
+++ b/spa/plugins/alsa/alsa-seq.c
@@ -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,21 +715,34 @@ 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;
}
- 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);
+ 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_pod_builder_control(&port->builder, offset, ump ? SPA_CONTROL_UMP : SPA_CONTROL_Midi );
- spa_pod_builder_bytes(&port->builder, data, size);
+ 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);
- /* make sure we can fit at least one control event of max size otherwise
- * we keep the event in the queue and try to copy it in the next cycle */
- if (port->builder.state.offset +
- sizeof(struct spa_pod_control) +
- MAX_EVENT_SIZE > port->buffer->buf->datas[0].maxsize)
- goto done;
+ 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
+ * we keep the event in the queue and try to copy it in the next cycle */
+ if (port->builder.state.offset +
+ 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;
}
}
}
diff --git a/spa/plugins/alsa/alsa-seq.h b/spa/plugins/alsa/alsa-seq.h
index 3100b9587..354fa1d5d 100644
--- a/spa/plugins/alsa/alsa-seq.h
+++ b/spa/plugins/alsa/alsa-seq.h
@@ -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;
diff --git a/spa/plugins/alsa/alsa-udev.c b/spa/plugins/alsa/alsa-udev.c
index 9c3e12f20..fdc255864 100644
--- a/spa/plugins/alsa/alsa-udev.c
+++ b/spa/plugins/alsa/alsa-udev.c
@@ -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 ":." */
- 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)
{
@@ -822,11 +734,7 @@ static void process_card(struct impl *this, enum action action, struct card *car
return;
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 +753,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 +790,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 +918,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 +941,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 +958,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;
diff --git a/spa/plugins/alsa/mixer/paths/analog-output-headphones.conf b/spa/plugins/alsa/mixer/paths/analog-output-headphones.conf
index 0e698bd9c..3c62c5e67 100644
--- a/spa/plugins/alsa/mixer/paths/analog-output-headphones.conf
+++ b/spa/plugins/alsa/mixer/paths/analog-output-headphones.conf
@@ -93,12 +93,6 @@ volume = merge
override-map.1 = all
override-map.2 = all-left,all-right
-; Keep Line Out disabled in the headphones path so selecting headphones
-; does not also drive speaker/line outputs on shared controls.
-[Element Line Out]
-switch = off
-volume = off
-
; This path is intended to control the first headphones, not
; the second headphones. But it should not hurt if we leave the second
; headphone jack enabled nonetheless.
diff --git a/spa/plugins/alsa/mixer/paths/analog-output-lineout.conf b/spa/plugins/alsa/mixer/paths/analog-output-lineout.conf
index a6fcfcb83..1ffce2225 100644
--- a/spa/plugins/alsa/mixer/paths/analog-output-lineout.conf
+++ b/spa/plugins/alsa/mixer/paths/analog-output-lineout.conf
@@ -113,23 +113,10 @@ override-map.1 = all
override-map.2 = all-left,all-right
required-any = any
-[Element Line Out]
-switch = mute
-volume = merge
-override-map.1 = all
-override-map.2 = all-left,all-right
-
[Element Master Mono]
switch = off
volume = off
-; Prefer manual routing decisions by disabling codec auto-mute here.
-[Element Auto-Mute Mode]
-enumeration = select
-
-[Option Auto-Mute Mode:Disabled]
-name = analog-output-lineout
-
[Element Line HP Swap]
switch = off
required-any = any
diff --git a/spa/plugins/audioconvert/audioadapter.c b/spa/plugins/audioconvert/audioadapter.c
index 801b736ab..ccc9f48df 100644
--- a/spa/plugins/audioconvert/audioadapter.c
+++ b/spa/plugins/audioconvert/audioadapter.c
@@ -1086,8 +1086,6 @@ static int impl_node_send_command(void *object, const struct spa_command *comman
spa_log_debug(this->log, "%p: suspending", this);
break;
case SPA_NODE_COMMAND_Pause:
- if ((res = negotiate_format(this)) < 0)
- return res;
spa_log_debug(this->log, "%p: pausing", this);
break;
case SPA_NODE_COMMAND_Flush:
@@ -1812,9 +1810,6 @@ impl_node_port_reuse_buffer(void *object, uint32_t port_id, uint32_t buffer_id)
spa_return_val_if_fail(this != NULL, -EINVAL);
- if (SPA_DIRECTION_OUTPUT != this->direction)
- port_id++;
-
return spa_node_port_reuse_buffer(this->target, port_id, buffer_id);
}
diff --git a/spa/plugins/audioconvert/audioconvert.c b/spa/plugins/audioconvert/audioconvert.c
index 17e0f7ff3..e9355ca41 100644
--- a/spa/plugins/audioconvert/audioconvert.c
+++ b/spa/plugins/audioconvert/audioconvert.c
@@ -7,7 +7,6 @@
#include
#include
#include
-#include
#include
#include
@@ -17,7 +16,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -270,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;
@@ -725,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"),
@@ -761,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"),
@@ -780,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),
@@ -796,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"),
@@ -804,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"),
@@ -812,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"),
@@ -830,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"),
@@ -838,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"),
@@ -846,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"),
@@ -854,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"),
@@ -865,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;
}
@@ -877,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:
@@ -932,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");
@@ -956,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;
@@ -995,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;
@@ -1326,7 +1284,7 @@ static int ensure_tmp(struct impl *this)
return -ENOMEM;
}
this->tmp_datas[0][i] = SPA_PTR_ALIGN(this->tmp[0][i], MAX_ALIGN, void);
- this->tmp_datas[1][i] = SPA_PTR_ALIGN(this->tmp[1][i], MAX_ALIGN, void);
+ this->tmp_datas[0][i] = SPA_PTR_ALIGN(this->tmp[0][i], MAX_ALIGN, void);
}
this->scratch_ports = maxports;
}
@@ -1451,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') {
@@ -1477,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)
@@ -1525,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"))
@@ -1688,7 +1637,7 @@ static struct spa_pod *generate_ramp_seq(struct impl *this, struct volume_ramp_p
while (1) {
float pos = (samples == 0) ? end :
- SPA_CLAMPF(start + (end - start) * offs / samples,
+ SPA_CLAMP(start + (end - start) * offs / samples,
SPA_MIN(start, end), SPA_MAX(start, end));
float vas = get_volume_at_scale(vrp, pos);
@@ -2166,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;
@@ -2323,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;
}
@@ -2371,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;
}
@@ -2463,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;
@@ -2497,7 +2446,7 @@ static uint32_t resample_update_rate_match(struct impl *this, bool passthrough,
match_size = resample_out_len(&this->resample, size);
}
- delay = lround(fdelay);
+ delay = (uint32_t)round(fdelay);
delay_frac = (int32_t)((fdelay - delay) * 1e9);
}
match_size -= SPA_MIN(match_size, queued);
@@ -2643,11 +2592,8 @@ static int impl_node_send_command(void *object, const struct spa_command *comman
break;
case SPA_NODE_COMMAND_Suspend:
reset_node(this);
- this->started = false;
- break;
+ SPA_FALLTHROUGH;
case SPA_NODE_COMMAND_Pause:
- if ((res = setup_convert(this)) < 0)
- return res;
this->started = false;
break;
case SPA_NODE_COMMAND_Flush:
@@ -4288,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);
@@ -4300,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);
@@ -4358,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;
diff --git a/spa/plugins/audioconvert/benchmark-fmt-ops.c b/spa/plugins/audioconvert/benchmark-fmt-ops.c
index e59f1f56b..9ea43ec65 100644
--- a/spa/plugins/audioconvert/benchmark-fmt-ops.c
+++ b/spa/plugins/audioconvert/benchmark-fmt-ops.c
@@ -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];
diff --git a/spa/plugins/audioconvert/benchmark-resample.c b/spa/plugins/audioconvert/benchmark-resample.c
index 9b9fbf1ed..7b9864362 100644
--- a/spa/plugins/audioconvert/benchmark-resample.c
+++ b/spa/plugins/audioconvert/benchmark-resample.c
@@ -39,7 +39,7 @@ static const int in_rates[] = { 44100, 44100, 48000, 96000, 22050, 96000 };
static const int out_rates[] = { 44100, 48000, 44100, 48000, 48000, 44100 };
-#define MAX_RESAMPLER 10
+#define MAX_RESAMPLER 5
#define MAX_SIZES SPA_N_ELEMENTS(sample_sizes)
#define MAX_RATES SPA_N_ELEMENTS(in_rates)
#define MAX_RESULTS MAX_RESAMPLER * MAX_SIZES * MAX_RATES
@@ -123,9 +123,7 @@ int main(int argc, char *argv[])
r.o_rate = out_rates[i];
r.quality = RESAMPLE_DEFAULT_QUALITY;
resample_native_init(&r);
- run_test("full", "c", &r);
- resample_update_rate(&r, 1.001);
- run_test("inter", "c", &r);
+ run_test("native", "c", &r);
resample_free(&r);
}
#if defined (HAVE_SSE)
@@ -138,9 +136,7 @@ int main(int argc, char *argv[])
r.o_rate = out_rates[i];
r.quality = RESAMPLE_DEFAULT_QUALITY;
resample_native_init(&r);
- run_test("full", "sse", &r);
- resample_update_rate(&r, 1.001);
- run_test("inter", "sse", &r);
+ run_test("native", "sse", &r);
resample_free(&r);
}
}
@@ -155,9 +151,7 @@ int main(int argc, char *argv[])
r.o_rate = out_rates[i];
r.quality = RESAMPLE_DEFAULT_QUALITY;
resample_native_init(&r);
- run_test("full", "ssse3", &r);
- resample_update_rate(&r, 1.001);
- run_test("inter", "ssse3", &r);
+ run_test("native", "ssse3", &r);
resample_free(&r);
}
}
@@ -172,9 +166,7 @@ int main(int argc, char *argv[])
r.o_rate = out_rates[i];
r.quality = RESAMPLE_DEFAULT_QUALITY;
resample_native_init(&r);
- run_test("full", "avx2", &r);
- resample_update_rate(&r, 1.001);
- run_test("inter", "avx2", &r);
+ run_test("native", "avx2", &r);
resample_free(&r);
}
}
diff --git a/spa/plugins/audioconvert/channelmix-ops-avx.c b/spa/plugins/audioconvert/channelmix-ops-avx.c
deleted file mode 100644
index 08d8e2b00..000000000
--- a/spa/plugins/audioconvert/channelmix-ops-avx.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/* Spa */
-/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
-/* SPDX-License-Identifier: MIT */
-
-#include "channelmix-ops.h"
-
-#include
-#include
-#include
-
-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);
-}
diff --git a/spa/plugins/audioconvert/channelmix-ops.c b/spa/plugins/audioconvert/channelmix-ops.c
index 574d0dd1b..12edb4b5a 100644
--- a/spa/plugins/audioconvert/channelmix-ops.c
+++ b/spa/plugins/audioconvert/channelmix-ops.c
@@ -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; ic < dst_chan; i++) {
float sum = 0.0f;
char str1[1024], str2[1024];
struct spa_strbuf sb1, sb2;
@@ -735,7 +730,7 @@ done:
if (i < CHANNEL_BITS && (dst_paired & (1UL << i)) == 0)
continue;
- for (jc = 0, j = 0; jc < src_chan && j < MAX_CHANNELS; j++) {
+ for (jc = 0, j = 0; jc < src_chan; j++) {
if (j < CHANNEL_BITS && (src_paired & (1UL << j)) == 0)
continue;
@@ -874,21 +869,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 +885,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);
diff --git a/spa/plugins/audioconvert/channelmix-ops.h b/spa/plugins/audioconvert/channelmix-ops.h
index c66eaddd3..6ea2b9451 100644
--- a/spa/plugins/audioconvert/channelmix-ops.h
+++ b/spa/plugins/audioconvert/channelmix-ops.h
@@ -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
diff --git a/spa/plugins/audioconvert/fmt-ops-avx2.c b/spa/plugins/audioconvert/fmt-ops-avx2.c
index 9c3dce52d..a939da458 100644
--- a/spa/plugins/audioconvert/fmt-ops-avx2.c
+++ b/spa/plugins/audioconvert/fmt-ops-avx2.c
@@ -4,8 +4,6 @@
#include "fmt-ops.h"
-#include
-
#include
// 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);
- for(; i + 1 < n_channels; i += 2)
- conv_s24_to_f32d_2s_gather_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);
- }
+ for(; i + 3 < n_channels; i += 4)
+ 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_avx2(conv, &dst[i], &s[3*i], n_channels, n_samples);
+ for(; i < n_channels; i++)
+ 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);
- }
+ 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);
}
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;
}
}
-
diff --git a/spa/plugins/audioconvert/fmt-ops-sse2.c b/spa/plugins/audioconvert/fmt-ops-sse2.c
index dcba6d2e1..ee5c89c06 100644
--- a/spa/plugins/audioconvert/fmt-ops-sse2.c
+++ b/spa/plugins/audioconvert/fmt-ops-sse2.c
@@ -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++) {
diff --git a/spa/plugins/audioconvert/fmt-ops.c b/spa/plugins/audioconvert/fmt-ops.c
index 34de40445..3fc2c5f0a 100644
--- a/spa/plugins/audioconvert/fmt-ops.c
+++ b/spa/plugins/audioconvert/fmt-ops.c
@@ -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;
diff --git a/spa/plugins/audioconvert/fmt-ops.h b/spa/plugins/audioconvert/fmt-ops.h
index 24b4b1aaf..f738e3858 100644
--- a/spa/plugins/audioconvert/fmt-ops.h
+++ b/spa/plugins/audioconvert/fmt-ops.h
@@ -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;
diff --git a/spa/plugins/audioconvert/meson.build b/spa/plugins/audioconvert/meson.build
index 71d5d56cd..bd60872b6 100644
--- a/spa/plugins/audioconvert/meson.build
+++ b/spa/plugins/audioconvert/meson.build
@@ -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
)
diff --git a/spa/plugins/audioconvert/peaks-ops.c b/spa/plugins/audioconvert/peaks-ops.c
index f7a897f90..29b93a081 100644
--- a/spa/plugins/audioconvert/peaks-ops.c
+++ b/spa/plugins/audioconvert/peaks-ops.c
@@ -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;
diff --git a/spa/plugins/audioconvert/peaks-ops.h b/spa/plugins/audioconvert/peaks-ops.h
index 40b20cfbc..24092a4f7 100644
--- a/spa/plugins/audioconvert/peaks-ops.h
+++ b/spa/plugins/audioconvert/peaks-ops.h
@@ -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;
diff --git a/spa/plugins/audioconvert/resample-native-avx2.c b/spa/plugins/audioconvert/resample-native-avx2.c
index d8d658c3a..ba009a97b 100644
--- a/spa/plugins/audioconvert/resample-native-avx2.c
+++ b/spa/plugins/audioconvert/resample-native-avx2.c
@@ -31,8 +31,8 @@ static inline void inner_product_avx2(float *d, const float * SPA_RESTRICT s,
sx[1] = _mm_fmadd_ps(tx, _mm_load_ps(taps + i + 4), sx[1]);
}
sx[0] = _mm_add_ps(sx[0], sx[1]);
- sx[0] = _mm_add_ps(sx[0], _mm_movehl_ps(sx[0], sx[0]));
- sx[0] = _mm_add_ss(sx[0], _mm_movehdup_ps(sx[0]));
+ sx[0] = _mm_hadd_ps(sx[0], sx[0]);
+ sx[0] = _mm_hadd_ps(sx[0], sx[0]);
_mm_store_ss(d, sx[0]);
}
@@ -40,9 +40,8 @@ static inline void inner_product_ip_avx2(float *d, const float * SPA_RESTRICT s,
const float * SPA_RESTRICT t0, const float * SPA_RESTRICT t1, float x,
uint32_t n_taps)
{
- __m256 sy[4] = { _mm256_setzero_ps(), _mm256_setzero_ps(),
- _mm256_setzero_ps(), _mm256_setzero_ps() }, ty;
- __m128 sx[4], tx;
+ __m256 sy[2] = { _mm256_setzero_ps(), _mm256_setzero_ps() }, ty;
+ __m128 sx[2], tx;
uint32_t i, n_taps4 = n_taps & ~0xf;
for (i = 0; i < n_taps4; i += 16) {
@@ -50,11 +49,9 @@ static inline void inner_product_ip_avx2(float *d, const float * SPA_RESTRICT s,
sy[0] = _mm256_fmadd_ps(ty, _mm256_load_ps(t0 + i + 0), sy[0]);
sy[1] = _mm256_fmadd_ps(ty, _mm256_load_ps(t1 + i + 0), sy[1]);
ty = _mm256_loadu_ps(s + i + 8);
- sy[2] = _mm256_fmadd_ps(ty, _mm256_load_ps(t0 + i + 8), sy[2]);
- sy[3] = _mm256_fmadd_ps(ty, _mm256_load_ps(t1 + i + 8), sy[3]);
+ sy[0] = _mm256_fmadd_ps(ty, _mm256_load_ps(t0 + i + 8), sy[0]);
+ sy[1] = _mm256_fmadd_ps(ty, _mm256_load_ps(t1 + i + 8), sy[1]);
}
- sy[0] = _mm256_add_ps(sy[0], sy[2]);
- sy[1] = _mm256_add_ps(sy[1], sy[3]);
sx[0] = _mm_add_ps(_mm256_extractf128_ps(sy[0], 0), _mm256_extractf128_ps(sy[0], 1));
sx[1] = _mm_add_ps(_mm256_extractf128_ps(sy[1], 0), _mm256_extractf128_ps(sy[1], 1));
@@ -68,8 +65,8 @@ static inline void inner_product_ip_avx2(float *d, const float * SPA_RESTRICT s,
}
sx[1] = _mm_mul_ps(_mm_sub_ps(sx[1], sx[0]), _mm_load1_ps(&x));
sx[0] = _mm_add_ps(sx[0], sx[1]);
- sx[0] = _mm_add_ps(sx[0], _mm_movehl_ps(sx[0], sx[0]));
- sx[0] = _mm_add_ss(sx[0], _mm_movehdup_ps(sx[0]));
+ sx[0] = _mm_hadd_ps(sx[0], sx[0]);
+ sx[0] = _mm_hadd_ps(sx[0], sx[0]);
_mm_store_ss(d, sx[0]);
}
diff --git a/spa/plugins/audioconvert/resample-native-sse.c b/spa/plugins/audioconvert/resample-native-sse.c
index 5fc6ed6ea..241d2b1e0 100644
--- a/spa/plugins/audioconvert/resample-native-sse.c
+++ b/spa/plugins/audioconvert/resample-native-sse.c
@@ -9,31 +9,50 @@
static inline void inner_product_sse(float *d, const float * SPA_RESTRICT s,
const float * SPA_RESTRICT taps, uint32_t n_taps)
{
- __m128 sum[2] = { _mm_setzero_ps(), _mm_setzero_ps() };
- uint32_t i;
+ __m128 sum = _mm_setzero_ps();
+ uint32_t i = 0;
+#if 0
+ uint32_t unrolled = n_taps & ~15;
- for (i = 0; i < n_taps; i += 8) {
- sum[0] = _mm_add_ps(sum[0],
+ for (i = 0; i < unrolled; i += 16) {
+ sum = _mm_add_ps(sum,
_mm_mul_ps(
_mm_loadu_ps(s + i + 0),
_mm_load_ps(taps + i + 0)));
- sum[1] = _mm_add_ps(sum[1],
+ sum = _mm_add_ps(sum,
+ _mm_mul_ps(
+ _mm_loadu_ps(s + i + 4),
+ _mm_load_ps(taps + i + 4)));
+ sum = _mm_add_ps(sum,
+ _mm_mul_ps(
+ _mm_loadu_ps(s + i + 8),
+ _mm_load_ps(taps + i + 8)));
+ sum = _mm_add_ps(sum,
+ _mm_mul_ps(
+ _mm_loadu_ps(s + i + 12),
+ _mm_load_ps(taps + i + 12)));
+ }
+#endif
+ for (; i < n_taps; i += 8) {
+ sum = _mm_add_ps(sum,
+ _mm_mul_ps(
+ _mm_loadu_ps(s + i + 0),
+ _mm_load_ps(taps + i + 0)));
+ sum = _mm_add_ps(sum,
_mm_mul_ps(
_mm_loadu_ps(s + i + 4),
_mm_load_ps(taps + i + 4)));
}
- sum[0] = _mm_add_ps(sum[0], sum[1]);
- sum[0] = _mm_add_ps(sum[0], _mm_movehl_ps(sum[0], sum[0]));
- sum[0] = _mm_add_ss(sum[0], _mm_shuffle_ps(sum[0], sum[0], 0x55));
- _mm_store_ss(d, sum[0]);
+ sum = _mm_add_ps(sum, _mm_movehl_ps(sum, sum));
+ sum = _mm_add_ss(sum, _mm_shuffle_ps(sum, sum, 0x55));
+ _mm_store_ss(d, sum);
}
static inline void inner_product_ip_sse(float *d, const float * SPA_RESTRICT s,
const float * SPA_RESTRICT t0, const float * SPA_RESTRICT t1, float x,
uint32_t n_taps)
{
- __m128 sum[4] = { _mm_setzero_ps(), _mm_setzero_ps(),
- _mm_setzero_ps(), _mm_setzero_ps() }, t;
+ __m128 sum[2] = { _mm_setzero_ps (), _mm_setzero_ps () }, t;
uint32_t i;
for (i = 0; i < n_taps; i += 8) {
@@ -41,11 +60,9 @@ static inline void inner_product_ip_sse(float *d, const float * SPA_RESTRICT s,
sum[0] = _mm_add_ps(sum[0], _mm_mul_ps(t, _mm_load_ps(t0 + i + 0)));
sum[1] = _mm_add_ps(sum[1], _mm_mul_ps(t, _mm_load_ps(t1 + i + 0)));
t = _mm_loadu_ps(s + i + 4);
- sum[2] = _mm_add_ps(sum[2], _mm_mul_ps(t, _mm_load_ps(t0 + i + 4)));
- sum[3] = _mm_add_ps(sum[3], _mm_mul_ps(t, _mm_load_ps(t1 + i + 4)));
+ sum[0] = _mm_add_ps(sum[0], _mm_mul_ps(t, _mm_load_ps(t0 + i + 4)));
+ sum[1] = _mm_add_ps(sum[1], _mm_mul_ps(t, _mm_load_ps(t1 + i + 4)));
}
- sum[0] = _mm_add_ps(sum[0], sum[2]);
- sum[1] = _mm_add_ps(sum[1], sum[3]);
sum[1] = _mm_mul_ps(_mm_sub_ps(sum[1], sum[0]), _mm_load1_ps(&x));
sum[0] = _mm_add_ps(sum[0], sum[1]);
sum[0] = _mm_add_ps(sum[0], _mm_movehl_ps(sum[0], sum[0]));
diff --git a/spa/plugins/audioconvert/resample-native-ssse3.c b/spa/plugins/audioconvert/resample-native-ssse3.c
index e445e316d..c4f1d37f4 100644
--- a/spa/plugins/audioconvert/resample-native-ssse3.c
+++ b/spa/plugins/audioconvert/resample-native-ssse3.c
@@ -9,18 +9,18 @@
static inline void inner_product_ssse3(float *d, const float * SPA_RESTRICT s,
const float * SPA_RESTRICT taps, uint32_t n_taps)
{
- __m128 sum[2] = { _mm_setzero_ps(), _mm_setzero_ps() };
+ __m128 sum = _mm_setzero_ps();
__m128 t0, t1;
uint32_t i;
switch (SPA_PTR_ALIGNMENT(s, 16)) {
case 0:
for (i = 0; i < n_taps; i += 8) {
- sum[0] = _mm_add_ps(sum[0],
+ sum = _mm_add_ps(sum,
_mm_mul_ps(
_mm_load_ps(s + i + 0),
_mm_load_ps(taps + i + 0)));
- sum[1] = _mm_add_ps(sum[1],
+ sum = _mm_add_ps(sum,
_mm_mul_ps(
_mm_load_ps(s + i + 4),
_mm_load_ps(taps + i + 4)));
@@ -31,12 +31,12 @@ static inline void inner_product_ssse3(float *d, const float * SPA_RESTRICT s,
for (i = 0; i < n_taps; i += 8) {
t1 = _mm_load_ps(s + i + 3);
t0 = (__m128)_mm_alignr_epi8((__m128i)t1, (__m128i)t0, 4);
- sum[0] = _mm_add_ps(sum[0],
+ sum = _mm_add_ps(sum,
_mm_mul_ps(t0, _mm_load_ps(taps + i + 0)));
t0 = t1;
t1 = _mm_load_ps(s + i + 7);
t0 = (__m128)_mm_alignr_epi8((__m128i)t1, (__m128i)t0, 4);
- sum[1] = _mm_add_ps(sum[1],
+ sum = _mm_add_ps(sum,
_mm_mul_ps(t0, _mm_load_ps(taps + i + 4)));
t0 = t1;
}
@@ -46,12 +46,12 @@ static inline void inner_product_ssse3(float *d, const float * SPA_RESTRICT s,
for (i = 0; i < n_taps; i += 8) {
t1 = _mm_load_ps(s + i + 2);
t0 = (__m128)_mm_alignr_epi8((__m128i)t1, (__m128i)t0, 8);
- sum[0] = _mm_add_ps(sum[0],
+ sum = _mm_add_ps(sum,
_mm_mul_ps(t0, _mm_load_ps(taps + i + 0)));
t0 = t1;
t1 = _mm_load_ps(s + i + 6);
t0 = (__m128)_mm_alignr_epi8((__m128i)t1, (__m128i)t0, 8);
- sum[1] = _mm_add_ps(sum[1],
+ sum = _mm_add_ps(sum,
_mm_mul_ps(t0, _mm_load_ps(taps + i + 4)));
t0 = t1;
}
@@ -61,96 +61,34 @@ static inline void inner_product_ssse3(float *d, const float * SPA_RESTRICT s,
for (i = 0; i < n_taps; i += 8) {
t1 = _mm_load_ps(s + i + 1);
t0 = (__m128)_mm_alignr_epi8((__m128i)t1, (__m128i)t0, 12);
- sum[0] = _mm_add_ps(sum[0],
+ sum = _mm_add_ps(sum,
_mm_mul_ps(t0, _mm_load_ps(taps + i + 0)));
t0 = t1;
t1 = _mm_load_ps(s + i + 5);
t0 = (__m128)_mm_alignr_epi8((__m128i)t1, (__m128i)t0, 12);
- sum[1] = _mm_add_ps(sum[1],
+ sum = _mm_add_ps(sum,
_mm_mul_ps(t0, _mm_load_ps(taps + i + 4)));
t0 = t1;
}
break;
}
- sum[0] = _mm_add_ps(sum[0], sum[1]);
- sum[0] = _mm_add_ps(sum[0], _mm_movehdup_ps(sum[0]));
- sum[0] = _mm_add_ss(sum[0], _mm_movehl_ps(sum[0], sum[0]));
- _mm_store_ss(d, sum[0]);
+ sum = _mm_add_ps(sum, _mm_movehdup_ps(sum));
+ sum = _mm_add_ss(sum, _mm_movehl_ps(sum, sum));
+ _mm_store_ss(d, sum);
}
static inline void inner_product_ip_ssse3(float *d, const float * SPA_RESTRICT s,
const float * SPA_RESTRICT t0, const float * SPA_RESTRICT t1, float x,
uint32_t n_taps)
{
- __m128 sum[4] = { _mm_setzero_ps(), _mm_setzero_ps(),
- _mm_setzero_ps(), _mm_setzero_ps() };
- __m128 r0, r1, r;
+ float sum[2] = { 0.0f, 0.0f };
uint32_t i;
- switch (SPA_PTR_ALIGNMENT(s, 16)) {
- case 0:
- for (i = 0; i < n_taps; i += 8) {
- r = _mm_load_ps(s + i + 0);
- sum[0] = _mm_add_ps(sum[0], _mm_mul_ps(r, _mm_load_ps(t0 + i + 0)));
- sum[1] = _mm_add_ps(sum[1], _mm_mul_ps(r, _mm_load_ps(t1 + i + 0)));
- r = _mm_load_ps(s + i + 4);
- sum[2] = _mm_add_ps(sum[2], _mm_mul_ps(r, _mm_load_ps(t0 + i + 4)));
- sum[3] = _mm_add_ps(sum[3], _mm_mul_ps(r, _mm_load_ps(t1 + i + 4)));
- }
- break;
- case 4:
- r0 = _mm_load_ps(s - 1);
- for (i = 0; i < n_taps; i += 8) {
- r1 = _mm_load_ps(s + i + 3);
- r = (__m128)_mm_alignr_epi8((__m128i)r1, (__m128i)r0, 4);
- sum[0] = _mm_add_ps(sum[0], _mm_mul_ps(r, _mm_load_ps(t0 + i + 0)));
- sum[1] = _mm_add_ps(sum[1], _mm_mul_ps(r, _mm_load_ps(t1 + i + 0)));
- r0 = r1;
- r1 = _mm_load_ps(s + i + 7);
- r = (__m128)_mm_alignr_epi8((__m128i)r1, (__m128i)r0, 4);
- sum[2] = _mm_add_ps(sum[2], _mm_mul_ps(r, _mm_load_ps(t0 + i + 4)));
- sum[3] = _mm_add_ps(sum[3], _mm_mul_ps(r, _mm_load_ps(t1 + i + 4)));
- r0 = r1;
- }
- break;
- case 8:
- r0 = _mm_load_ps(s - 2);
- for (i = 0; i < n_taps; i += 8) {
- r1 = _mm_load_ps(s + i + 2);
- r = (__m128)_mm_alignr_epi8((__m128i)r1, (__m128i)r0, 8);
- sum[0] = _mm_add_ps(sum[0], _mm_mul_ps(r, _mm_load_ps(t0 + i + 0)));
- sum[1] = _mm_add_ps(sum[1], _mm_mul_ps(r, _mm_load_ps(t1 + i + 0)));
- r0 = r1;
- r1 = _mm_load_ps(s + i + 6);
- r = (__m128)_mm_alignr_epi8((__m128i)r1, (__m128i)r0, 8);
- sum[2] = _mm_add_ps(sum[2], _mm_mul_ps(r, _mm_load_ps(t0 + i + 4)));
- sum[3] = _mm_add_ps(sum[3], _mm_mul_ps(r, _mm_load_ps(t1 + i + 4)));
- r0 = r1;
- }
- break;
- case 12:
- r0 = _mm_load_ps(s - 3);
- for (i = 0; i < n_taps; i += 8) {
- r1 = _mm_load_ps(s + i + 1);
- r = (__m128)_mm_alignr_epi8((__m128i)r1, (__m128i)r0, 12);
- sum[0] = _mm_add_ps(sum[0], _mm_mul_ps(r, _mm_load_ps(t0 + i + 0)));
- sum[1] = _mm_add_ps(sum[1], _mm_mul_ps(r, _mm_load_ps(t1 + i + 0)));
- r0 = r1;
- r1 = _mm_load_ps(s + i + 5);
- r = (__m128)_mm_alignr_epi8((__m128i)r1, (__m128i)r0, 12);
- sum[2] = _mm_add_ps(sum[2], _mm_mul_ps(r, _mm_load_ps(t0 + i + 4)));
- sum[3] = _mm_add_ps(sum[3], _mm_mul_ps(r, _mm_load_ps(t1 + i + 4)));
- r0 = r1;
- }
- break;
+ for (i = 0; i < n_taps; i++) {
+ sum[0] += s[i] * t0[i];
+ sum[1] += s[i] * t1[i];
}
- sum[0] = _mm_add_ps(sum[0], sum[2]);
- sum[1] = _mm_add_ps(sum[1], sum[3]);
- sum[1] = _mm_mul_ps(_mm_sub_ps(sum[1], sum[0]), _mm_load1_ps(&x));
- sum[0] = _mm_add_ps(sum[0], sum[1]);
- sum[0] = _mm_add_ps(sum[0], _mm_movehdup_ps(sum[0]));
- sum[0] = _mm_add_ss(sum[0], _mm_movehl_ps(sum[0], sum[0]));
- _mm_store_ss(d, sum[0]);
+ *d = (sum[1] - sum[0]) * x + sum[0];
}
MAKE_RESAMPLER_FULL(ssse3);
diff --git a/spa/plugins/audioconvert/resample-native.c b/spa/plugins/audioconvert/resample-native.c
index 5bb33ffc1..3604c5b45 100644
--- a/spa/plugins/audioconvert/resample-native.c
+++ b/spa/plugins/audioconvert/resample-native.c
@@ -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);
diff --git a/spa/plugins/audioconvert/resample.h b/spa/plugins/audioconvert/resample.h
index 7b6e58415..fec3bf963 100644
--- a/spa/plugins/audioconvert/resample.h
+++ b/spa/plugins/audioconvert/resample.h
@@ -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;
diff --git a/spa/plugins/audioconvert/test-audioconvert.c b/spa/plugins/audioconvert/test-audioconvert.c
index de18d524b..de3ebb8b5 100644
--- a/spa/plugins/audioconvert/test-audioconvert.c
+++ b/spa/plugins/audioconvert/test-audioconvert.c
@@ -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);
diff --git a/spa/plugins/audioconvert/test-channelmix.c b/spa/plugins/audioconvert/test-channelmix.c
index 529db880f..b68c956bf 100644
--- a/spa/plugins/audioconvert/test-channelmix.c
+++ b/spa/plugins/audioconvert/test-channelmix.c
@@ -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;
diff --git a/spa/plugins/audioconvert/test-fmt-ops.c b/spa/plugins/audioconvert/test-fmt-ops.c
index d5ca414ef..17a26a351 100644
--- a/spa/plugins/audioconvert/test-fmt-ops.c
+++ b/spa/plugins/audioconvert/test-fmt-ops.c
@@ -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);
diff --git a/spa/plugins/audioconvert/volume-ops.c b/spa/plugins/audioconvert/volume-ops.c
index b76ab4bec..bf6aa6909 100644
--- a/spa/plugins/audioconvert/volume-ops.c
+++ b/spa/plugins/audioconvert/volume-ops.c
@@ -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;
diff --git a/spa/plugins/audioconvert/volume-ops.h b/spa/plugins/audioconvert/volume-ops.h
index 51642110f..a50ee9a6f 100644
--- a/spa/plugins/audioconvert/volume-ops.h
+++ b/spa/plugins/audioconvert/volume-ops.h
@@ -13,7 +13,6 @@
struct volume {
uint32_t cpu_flags;
- uint32_t func_cpu_flags;
const char *func_name;
struct spa_log *log;
diff --git a/spa/plugins/audiotestsrc/audiotestsrc.c b/spa/plugins/audiotestsrc/audiotestsrc.c
index 3414e8b18..5e7c521b8 100644
--- a/spa/plugins/audiotestsrc/audiotestsrc.c
+++ b/spa/plugins/audiotestsrc/audiotestsrc.c
@@ -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 (enabled) {
- 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;
+ if (this->async || this->props.live) {
+ if (enabled) {
+ if (this->props.live) {
+ uint64_t next_time = this->start_time + this->elapsed_time;
+ 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 (res != -EAGAIN)
- spa_log_error(this->log, "%p: timerfd error: %s",
- this, spa_strerror(res));
+ 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);
- this->start_time = SPA_TIMESPEC_TO_NSEC(&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);
diff --git a/spa/plugins/bluez5/a2dp-codec-aac.c b/spa/plugins/bluez5/a2dp-codec-aac.c
index f4cbecd9b..c49f7a616 100644
--- a/spa/plugins/bluez5/a2dp-codec-aac.c
+++ b/spa/plugins/bluez5/a2dp-codec-aac.c
@@ -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;
diff --git a/spa/plugins/bluez5/a2dp-codec-sbc.c b/spa/plugins/bluez5/a2dp-codec-sbc.c
index f1b86e76b..b4ebfc2a2 100644
--- a/spa/plugins/bluez5/a2dp-codec-sbc.c
+++ b/spa/plugins/bluez5/a2dp-codec-sbc.c
@@ -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;
}
diff --git a/spa/plugins/bluez5/backend-native.c b/spa/plugins/bluez5/backend-native.c
index 1cb2235ff..4d14183e7 100644
--- a/spa/plugins/bluez5/backend-native.c
+++ b/spa/plugins/bluez5/backend-native.c
@@ -904,7 +904,7 @@ static bool device_supports_codec(struct impl *backend, struct spa_bt_device *de
{
int res;
bool alt6_ok = true, alt1_ok = true;
- bool msbc_alt6_ok = true, msbc_alt1_ok = true, lc3_a127_ok = true;
+ bool msbc_alt6_ok = true, msbc_alt1_ok = true;
uint32_t bt_features;
if (device->adapter == NULL)
@@ -913,7 +913,6 @@ static bool device_supports_codec(struct impl *backend, struct spa_bt_device *de
if (backend->quirks && spa_bt_quirks_get_features(backend->quirks, device->adapter, device, &bt_features) == 0) {
msbc_alt1_ok = (bt_features & (SPA_BT_FEATURE_MSBC_ALT1 | SPA_BT_FEATURE_MSBC_ALT1_RTL));
msbc_alt6_ok = (bt_features & SPA_BT_FEATURE_MSBC);
- lc3_a127_ok = (bt_features & SPA_BT_FEATURE_LC3_A127);
}
switch (codec) {
@@ -923,10 +922,6 @@ static bool device_supports_codec(struct impl *backend, struct spa_bt_device *de
alt1_ok = msbc_alt1_ok;
alt6_ok = msbc_alt6_ok;
break;
- case SPA_BLUETOOTH_AUDIO_CODEC_LC3_A127:
- alt1_ok = false;
- alt6_ok = lc3_a127_ok;
- break;
case SPA_BLUETOOTH_AUDIO_CODEC_LC3_SWB:
default:
/* LC3-SWB has same transport requirements as msbc.
@@ -991,11 +986,8 @@ static void make_available_codec_list(struct impl *backend, struct spa_bt_device
for (i = 0; backend->codecs[i]; ++i) {
const struct media_codec *codec = backend->codecs[i];
-
if (codec->kind != MEDIA_CODEC_HFP)
continue;
- if (!spa_bt_get_hfp_codec(backend->monitor, codec->codec_id))
- continue;
if (device_supports_codec(backend, device, codec->id))
codec_list_add(codec_list, codec);
}
@@ -1977,9 +1969,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) {
@@ -2108,8 +2097,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");
@@ -2258,8 +2245,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)) {
@@ -2270,8 +2256,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;
@@ -2288,7 +2273,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;
@@ -2436,19 +2421,17 @@ 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;
- rfcomm->telephony_ag->volume[SPA_BT_VOLUME_ID_TX] = rfcomm->volumes[SPA_BT_VOLUME_ID_TX].hw_volume = backend->hfp_default_mic_volume;
- telephony_ag_set_callbacks(rfcomm->telephony_ag,
+ 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;
+ rfcomm->telephony_ag->volume[SPA_BT_VOLUME_ID_TX] = rfcomm->volumes[SPA_BT_VOLUME_ID_TX].hw_volume = backend->hfp_default_mic_volume;
+ telephony_ag_set_callbacks(rfcomm->telephony_ag,
&telephony_ag_callbacks, rfcomm);
- if (rfcomm->transport) {
- rfcomm->telephony_ag->transport.codec = rfcomm->transport->media_codec->codec_id;
- rfcomm->telephony_ag->transport.state = rfcomm->transport->state;
- }
- telephony_ag_register(rfcomm->telephony_ag);
+ if (rfcomm->transport) {
+ rfcomm->telephony_ag->transport.codec = rfcomm->transport->media_codec->codec_id;
+ 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;
@@ -2495,7 +2478,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) {
diff --git a/spa/plugins/bluez5/bap-codec-lc3.c b/spa/plugins/bluez5/bap-codec-lc3.c
index 881af4e14..74761f26b 100644
--- a/spa/plugins/bluez5/bap-codec-lc3.c
+++ b/spa/plugins/bluez5/bap-codec-lc3.c
@@ -126,22 +126,22 @@ static const struct bap_qos bap_qos_configs[] = {
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 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, "high-reliabilty"), /* 8_1_2 */
+ BAP_QOS("8_2_2", LC3_CONFIG_FREQ_8KHZ, LC3_CONFIG_DURATION_10, false, 30, 13, 95, 40000, 0, "high-reliabilty"), /* 8_2_2 */
+ BAP_QOS("16_1_2", LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_7_5, false, 30, 13, 75, 40000, 11, "high-reliabilty"), /* 16_1_2 */
+ BAP_QOS("16_2_2", LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_10, false, 40, 13, 95, 40000, 1, "high-reliabilty"), /* 16_2_2 */
+ BAP_QOS("24_1_2", LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_7_5, false, 45, 13, 75, 40000, 12, "high-reliabilty"), /* 24_1_2 */
+ BAP_QOS("24_2_2", LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_10, false, 60, 13, 95, 40000, 2, "high-reliabilty"), /* 24_2_2 */
+ BAP_QOS("32_1_2", LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_7_5, false, 60, 13, 75, 40000, 13, "high-reliabilty"), /* 32_1_2 */
+ BAP_QOS("32_2_2", LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_10, false, 80, 13, 95, 40000, 3, "high-reliabilty"), /* 32_2_2 */
+ BAP_QOS("441_1_2", LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_7_5, true, 97, 13, 80, 40000, 54, "high-reliabilty"), /* 441_1_2 */
+ BAP_QOS("441_2_2", LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_10, true, 130, 13, 85, 40000, 44, "high-reliabilty"), /* 441_2_2 */
+ BAP_QOS("48_1_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 75, 13, 75, 40000, 55, "high-reliabilty"), /* 48_1_2 */
+ BAP_QOS("48_2_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 100, 13, 95, 40000, 45, "high-reliabilty"), /* 48_2_2 */
+ BAP_QOS("48_3_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 90, 13, 75, 40000, 56, "high-reliabilty"), /* 48_3_2 */
+ BAP_QOS("48_4_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 120, 13, 100, 40000, 46, "high-reliabilty"), /* 48_4_2 */
+ BAP_QOS("48_5_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 117, 13, 75, 40000, 57, "high-reliabilty"), /* 48_5_2 */
+ BAP_QOS("48_6_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 155, 13, 100, 40000, 47, "high-reliabilty"), /* 48_6_2 */
};
static const struct bap_qos bap_bcast_qos_configs[] = {
@@ -167,22 +167,22 @@ static const struct bap_qos bap_bcast_qos_configs[] = {
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 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, "high-reliabilty"), /* 8_1_2 */
+ BAP_QOS("8_2_2", LC3_CONFIG_FREQ_8KHZ, LC3_CONFIG_DURATION_10, false, 30, 4, 60, 40000, 0, "high-reliabilty"), /* 8_2_2 */
+ BAP_QOS("16_1_2", LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_7_5, false, 30, 4, 45, 40000, 11, "high-reliabilty"), /* 16_1_2 */
+ BAP_QOS("16_2_2", LC3_CONFIG_FREQ_16KHZ, LC3_CONFIG_DURATION_10, false, 40, 4, 60, 40000, 1, "high-reliabilty"), /* 16_2_2 */
+ BAP_QOS("24_1_2", LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_7_5, false, 45, 4, 45, 40000, 12, "high-reliabilty"), /* 24_1_2 */
+ BAP_QOS("24_2_2", LC3_CONFIG_FREQ_24KHZ, LC3_CONFIG_DURATION_10, false, 60, 4, 60, 40000, 2, "high-reliabilty"), /* 24_2_2 */
+ BAP_QOS("32_1_2", LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_7_5, false, 60, 4, 45, 40000, 13, "high-reliabilty"), /* 32_1_2 */
+ BAP_QOS("32_2_2", LC3_CONFIG_FREQ_32KHZ, LC3_CONFIG_DURATION_10, false, 80, 4, 60, 40000, 3, "high-reliabilty"), /* 32_2_2 */
+ BAP_QOS("441_1_2", LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_7_5, true, 97, 4, 54, 40000, 14, "high-reliabilty"), /* 441_1_2 */
+ BAP_QOS("441_2_2", LC3_CONFIG_FREQ_44KHZ, LC3_CONFIG_DURATION_10, true, 130, 4, 60, 40000, 4, "high-reliabilty"), /* 441_2_2 */
+ BAP_QOS("48_1_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 75, 4, 50, 40000, 15, "high-reliabilty"), /* 48_1_2 */
+ BAP_QOS("48_2_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 100, 4, 65, 40000, 5, "high-reliabilty"), /* 48_2_2 */
+ BAP_QOS("48_3_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 90, 4, 50, 40000, 16, "high-reliabilty"), /* 48_3_2 */
+ BAP_QOS("48_4_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 120, 4, 65, 40000, 6, "high-reliabilty"), /* 48_4_2 */
+ BAP_QOS("48_5_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_7_5, false, 117, 4, 50, 40000, 17, "high-reliabilty"), /* 48_5_2 */
+ BAP_QOS("48_6_2", LC3_CONFIG_FREQ_48KHZ, LC3_CONFIG_DURATION_10, false, 155, 4, 65, 40000, 7, "high-reliabilty"), /* 48_6_2 */
};
static unsigned int get_rate_mask(uint8_t rate) {
@@ -1503,10 +1503,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 +1511,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 +1537,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);
diff --git a/spa/plugins/bluez5/bluez-hardware.conf b/spa/plugins/bluez5/bluez-hardware.conf
index 0148a4ee4..d08ff0bb9 100644
--- a/spa/plugins/bluez5/bluez-hardware.conf
+++ b/spa/plugins/bluez5/bluez-hardware.conf
@@ -15,7 +15,6 @@
# sbc-xq "nonstandard" SBC codec setting with better sound quality
# faststream FastStream codec support
# a2dp-duplex A2DP duplex codec support
-# lc3-a127 HFP LC3-24KHz codec support
#
# Features are disabled with the key "no-features" whose value is an
# array of strings in the match rule.
@@ -84,12 +83,6 @@ bluez5.features.adapter = [
# Realtek Semiconductor Corp.
{ bus-type = "usb", vendor-id = "usb:0bda" },
- # Mediatek MT7925, #pipewire-5213
- { bus-type = "usb", vendor-id = "usb:0e8d", product-id = "~(e025)", no-features = [ lc3-a127 ] },
- { bus-type = "usb", vendor-id = "usb:0489", product-id = "~(e111|e113|e118|e11e|e124|e139|e14e|e14f|e150|e151)", no-features = [ lc3-a127 ] },
- { bus-type = "usb", vendor-id = "usb:13d3", product-id = "~(3602|3603|3604|3608|3613|3627|3628|3630)", no-features = [ lc3-a127 ] },
- { bus-type = "usb", vendor-id = "usb:2c7c", product-id = "~(7009)", no-features = [ lc3-a127 ] },
-
# Generic USB adapters
{ bus-type = "usb", no-features = [ msbc-alt1-rtl ] },
diff --git a/spa/plugins/bluez5/bluez5-dbus.c b/spa/plugins/bluez5/bluez5-dbus.c
index 22d971c37..7dfe45911 100644
--- a/spa/plugins/bluez5/bluez5-dbus.c
+++ b/spa/plugins/bluez5/bluez5-dbus.c
@@ -188,16 +188,9 @@ 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;
};
@@ -594,35 +587,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;
+ return SPA_BT_PROFILE_BAP_BROADCAST_SOURCE;
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;
+ return SPA_BT_PROFILE_BAP_BROADCAST_SINK;
default:
spa_assert_not_reached();
}
@@ -2801,18 +2777,16 @@ bool spa_bt_device_supports_media_codec(struct spa_bt_device *device, const stru
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") &&
@@ -6199,11 +6173,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 +6199,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);
@@ -7122,7 +7078,7 @@ static void parse_broadcast_source_config(struct spa_bt_monitor *monitor, const
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)
+ if (spa_json_get_string(&it[1], 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")) {
@@ -7151,20 +7107,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;
diff --git a/spa/plugins/bluez5/bluez5-device.c b/spa/plugins/bluez5/bluez5-device.c
index 897241954..fc659f655 100644
--- a/spa/plugins/bluez5/bluez5-device.c
+++ b/spa/plugins/bluez5/bluez5-device.c
@@ -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;
@@ -1591,14 +1487,6 @@ static int set_profile(struct impl *this, uint32_t profile, enum spa_bluetooth_a
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;
- break;
default:
profiles = 0;
break;
@@ -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 {
- this->profile = DEVICE_PROFILE_A2DP;
- this->props.codec = t->media_codec->id;
- }
- }
-
+ 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) {
diff --git a/spa/plugins/bluez5/defs.h b/spa/plugins/bluez5/defs.h
index 5e69bb757..24a85a5c9 100644
--- a/spa/plugins/bluez5/defs.h
+++ b/spa/plugins/bluez5/defs.h
@@ -811,7 +811,6 @@ enum spa_bt_feature {
SPA_BT_FEATURE_SBC_XQ = (1 << 5),
SPA_BT_FEATURE_FASTSTREAM = (1 << 6),
SPA_BT_FEATURE_A2DP_DUPLEX = (1 << 7),
- SPA_BT_FEATURE_LC3_A127 = (1 << 8),
};
struct spa_bt_quirks;
diff --git a/spa/plugins/bluez5/iso-io.c b/spa/plugins/bluez5/iso-io.c
index ce1fd7d0c..2cc65a2bf 100644
--- a/spa/plugins/bluez5/iso-io.c
+++ b/spa/plugins/bluez5/iso-io.c
@@ -411,7 +411,7 @@ static void group_on_timeout(struct spa_source *source)
/* Ensure controller fill level */
fill_count = UINT_MAX;
spa_list_for_each(stream, &group->streams, link) {
- if (!stream->sink || !group->started || !stream->tx_latency.enabled)
+ if (!stream->sink || !group->started)
continue;
if (stream->tx_latency.queue < MIN_FILL)
fill_count = SPA_MIN(fill_count, MIN_FILL - stream->tx_latency.queue);
diff --git a/spa/plugins/bluez5/media-source.c b/spa/plugins/bluez5/media-source.c
index e1c01d90c..da2e57b5a 100644
--- a/spa/plugins/bluez5/media-source.c
+++ b/spa/plugins/bluez5/media-source.c
@@ -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);
diff --git a/spa/plugins/bluez5/midi-node.c b/spa/plugins/bluez5/midi-node.c
index 671035b34..7146d6f8a 100644
--- a/spa/plugins/bluez5/midi-node.c
+++ b/spa/plugins/bluez5/midi-node.c
@@ -23,6 +23,7 @@
#include
#include
#include
+#include
#include
#include
@@ -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,11 +460,19 @@ 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);
- 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));
+ 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));
+ }
}
}
@@ -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,28 +786,37 @@ 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);
- spa_log_trace(this->log, "%p: output event:0x%x time:%"PRIu64, this,
- (size > 0) ? event[0] : 0, time);
+ while (ump_size > 0) {
+ size = spa_ump_to_midi(&ump, &ump_size, event, sizeof(event), &state);
+ if (size <= 0)
+ break;
- do {
- res = spa_bt_midi_writer_write(&this->writer,
- time, event, size);
- if (res < 0) {
- return res;
- } else if (res) {
- int res2;
- if ((res2 = flush_packet(this)) < 0)
- return res2;
- }
- } while (res);
+ spa_log_trace(this->log, "%p: output event:0x%x time:%"PRIu64, this,
+ (size > 0) ? event[0] : 0, time);
+
+ do {
+ res = spa_bt_midi_writer_write(&this->writer,
+ time, event, size);
+ if (res < 0) {
+ return res;
+ } else if (res) {
+ int res2;
+ if ((res2 = flush_packet(this)) < 0)
+ return res2;
+ }
+ } while (res);
+ }
}
if ((res = flush_packet(this)) < 0)
diff --git a/spa/plugins/bluez5/quirks.c b/spa/plugins/bluez5/quirks.c
index 23bcec0d4..c4b293e68 100644
--- a/spa/plugins/bluez5/quirks.c
+++ b/spa/plugins/bluez5/quirks.c
@@ -52,7 +52,6 @@ struct spa_bt_quirks {
int force_sbc_xq;
int force_faststream;
int force_a2dp_duplex;
- int force_lc3_a127;
char *device_rules;
char *adapter_rules;
@@ -70,7 +69,6 @@ static enum spa_bt_feature parse_feature(const char *str)
{ "sbc-xq", SPA_BT_FEATURE_SBC_XQ },
{ "faststream", SPA_BT_FEATURE_FASTSTREAM },
{ "a2dp-duplex", SPA_BT_FEATURE_A2DP_DUPLEX },
- { "lc3-a127", SPA_BT_FEATURE_LC3_A127 },
};
SPA_FOR_EACH_ELEMENT_VAR(feature_keys, f) {
if (spa_streq(str, f->key))
@@ -230,7 +228,6 @@ struct spa_bt_quirks *spa_bt_quirks_create(const struct spa_dict *info, struct s
this->force_hw_volume = parse_force_flag(info, "bluez5.enable-hw-volume");
this->force_faststream = parse_force_flag(info, "bluez5.enable-faststream");
this->force_a2dp_duplex = parse_force_flag(info, "bluez5.enable-a2dp-duplex");
- this->force_lc3_a127 = parse_force_flag(info, "bluez5.enable-lc3-a127");
if ((str = spa_dict_lookup(info, "bluez5.hardware-database")) != NULL) {
spa_log_debug(this->log, "loading session manager provided data");
@@ -388,9 +385,6 @@ static int get_features(const struct spa_bt_quirks *this,
if (this->force_a2dp_duplex != -1)
SPA_FLAG_UPDATE(*features, SPA_BT_FEATURE_A2DP_DUPLEX, this->force_a2dp_duplex);
- if (this->force_lc3_a127 != -1)
- SPA_FLAG_UPDATE(*features, SPA_BT_FEATURE_LC3_A127, this->force_lc3_a127);
-
return 0;
}
diff --git a/spa/plugins/bluez5/rate-control.h b/spa/plugins/bluez5/rate-control.h
index 6837c2fa5..d1a36f193 100644
--- a/spa/plugins/bluez5/rate-control.h
+++ b/spa/plugins/bluez5/rate-control.h
@@ -128,7 +128,7 @@ static inline bool spa_bt_ptp_valid(struct spa_bt_ptp *p)
* in 1/z expansion. This guarantees f(z) is causal, and G(z) = (z-1) q(z) / p(z).
* We can choose p(z) and q(z) to improve low-pass properties of F(z).
*
- * Simplest choice is p(z)=(z-1)^2 and q(z)=1, but that does not suppress
+ * Simplest choice is p(z)=(z-1)^2 and q(z)=1, but that does not supress
* high frequency response in F(z). Better choice is p(z) = (z-u)*(z-v)*(z-w)
* and q(z) = z - r. Causality requires r = u + v + w - 2.
* Then,
diff --git a/spa/plugins/control/mixer.c b/spa/plugins/control/mixer.c
index 1b106d3f7..caf3a6b06 100644
--- a/spa/plugins/control/mixer.c
+++ b/spa/plugins/control/mixer.c
@@ -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<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<control_types = 0;
- }
}
spa_hook_list_init(&this->hooks);
diff --git a/spa/plugins/filter-graph/audio-dsp-avx2.c b/spa/plugins/filter-graph/audio-dsp-avx2.c
index 710231ab4..76c7b17d5 100644
--- a/spa/plugins/filter-graph/audio-dsp-avx2.c
+++ b/spa/plugins/filter-graph/audio-dsp-avx2.c
@@ -10,9 +10,7 @@
#include
-#ifdef HAVE_FFTW
-#include
-#else
+#ifndef HAVE_FFTW
#include "pffft.h"
#endif
#include "audio-dsp-impl.h"
@@ -142,10 +140,10 @@ static void dsp_add_n_gain_avx2(void *obj, float *dst,
for (i = 1; i < n_src; i++) {
g = _mm256_set1_ps(gain[i]);
- in[0] = _mm256_fmadd_ps(g, _mm256_load_ps(&s[i][n+ 0]), in[0]);
- in[1] = _mm256_fmadd_ps(g, _mm256_load_ps(&s[i][n+ 8]), in[1]);
- in[2] = _mm256_fmadd_ps(g, _mm256_load_ps(&s[i][n+16]), in[2]);
- in[3] = _mm256_fmadd_ps(g, _mm256_load_ps(&s[i][n+24]), in[3]);
+ in[0] = _mm256_add_ps(in[0], _mm256_mul_ps(g, _mm256_load_ps(&s[i][n+ 0])));
+ in[1] = _mm256_add_ps(in[1], _mm256_mul_ps(g, _mm256_load_ps(&s[i][n+ 8])));
+ in[2] = _mm256_add_ps(in[2], _mm256_mul_ps(g, _mm256_load_ps(&s[i][n+16])));
+ in[3] = _mm256_add_ps(in[3], _mm256_mul_ps(g, _mm256_load_ps(&s[i][n+24])));
}
_mm256_store_ps(&d[n+ 0], in[0]);
_mm256_store_ps(&d[n+ 8], in[1]);
@@ -237,244 +235,93 @@ void dsp_sum_avx2(void *obj, float *r, const float *a, const float *b, uint32_t
}
}
-void dsp_mult_avx2(void *obj,
- float * SPA_RESTRICT dst,
- const float * SPA_RESTRICT src[],
- uint32_t n_src, uint32_t n_samples)
+inline static __m256 _mm256_mul_pz(__m256 ab, __m256 cd)
{
- uint32_t n, i, unrolled;
- __m256 in[4];
-
- if (n_src == 0) {
- memset(dst, 0, n_samples * sizeof(float));
- return;
- }
-
- if (dst != src[0])
- spa_memcpy(dst, src[0], n_samples * sizeof(float));
-
- if (SPA_LIKELY(SPA_IS_ALIGNED(dst, 32))) {
- unrolled = n_samples & ~31;
- for (i = 1; i < n_src; i++) {
- if (SPA_UNLIKELY(!SPA_IS_ALIGNED(src[i], 32))) {
- unrolled = 0;
- break;
- }
- }
- } else
- unrolled = 0;
-
- for (i = 1; i < n_src; i++) {
- for (n = 0; n < unrolled; n += 32) {
- in[0] = _mm256_mul_ps(_mm256_load_ps(&dst[n+ 0]), _mm256_load_ps(&src[i][n+ 0]));
- in[1] = _mm256_mul_ps(_mm256_load_ps(&dst[n+ 8]), _mm256_load_ps(&src[i][n+ 8]));
- in[2] = _mm256_mul_ps(_mm256_load_ps(&dst[n+16]), _mm256_load_ps(&src[i][n+16]));
- in[3] = _mm256_mul_ps(_mm256_load_ps(&dst[n+24]), _mm256_load_ps(&src[i][n+24]));
- _mm256_store_ps(&dst[n+ 0], in[0]);
- _mm256_store_ps(&dst[n+ 8], in[1]);
- _mm256_store_ps(&dst[n+16], in[2]);
- _mm256_store_ps(&dst[n+24], in[3]);
- }
- for (; n < n_samples; n++)
- dst[n] *= src[i][n];
- }
-}
-
-void dsp_linear_avx2(void *obj, float * dst,
- const float * SPA_RESTRICT src, const float mult,
- const float add, uint32_t n_samples)
-{
- uint32_t n, unrolled;
- __m256 m, a;
-
- if (mult == 0.0f) {
- a = _mm256_set1_ps(add);
- unrolled = n_samples & ~31;
- for (n = 0; n < unrolled; n += 32) {
- _mm256_storeu_ps(&dst[n+ 0], a);
- _mm256_storeu_ps(&dst[n+ 8], a);
- _mm256_storeu_ps(&dst[n+16], a);
- _mm256_storeu_ps(&dst[n+24], a);
- }
- for (; n < n_samples; n++)
- dst[n] = add;
- return;
- }
-
- if (SPA_LIKELY(SPA_IS_ALIGNED(src, 32) && SPA_IS_ALIGNED(dst, 32)))
- unrolled = n_samples & ~31;
- else
- unrolled = 0;
-
- m = _mm256_set1_ps(mult);
-
- if (add == 0.0f) {
- if (mult == 1.0f) {
- if (dst != src)
- spa_memcpy(dst, src, n_samples * sizeof(float));
- return;
- }
- for (n = 0; n < unrolled; n += 32) {
- _mm256_store_ps(&dst[n+ 0], _mm256_mul_ps(m, _mm256_load_ps(&src[n+ 0])));
- _mm256_store_ps(&dst[n+ 8], _mm256_mul_ps(m, _mm256_load_ps(&src[n+ 8])));
- _mm256_store_ps(&dst[n+16], _mm256_mul_ps(m, _mm256_load_ps(&src[n+16])));
- _mm256_store_ps(&dst[n+24], _mm256_mul_ps(m, _mm256_load_ps(&src[n+24])));
- }
- for (; n < n_samples; n++)
- dst[n] = mult * src[n];
- } else {
- a = _mm256_set1_ps(add);
- for (n = 0; n < unrolled; n += 32) {
- _mm256_store_ps(&dst[n+ 0], _mm256_fmadd_ps(m, _mm256_load_ps(&src[n+ 0]), a));
- _mm256_store_ps(&dst[n+ 8], _mm256_fmadd_ps(m, _mm256_load_ps(&src[n+ 8]), a));
- _mm256_store_ps(&dst[n+16], _mm256_fmadd_ps(m, _mm256_load_ps(&src[n+16]), a));
- _mm256_store_ps(&dst[n+24], _mm256_fmadd_ps(m, _mm256_load_ps(&src[n+24]), a));
- }
- for (; n < n_samples; n++)
- dst[n] = mult * src[n] + add;
- }
-}
-
-#define FFT_BLOCK 8
-
-struct fft_info {
-#ifdef HAVE_FFTW
- fftwf_plan plan_r2c;
- fftwf_plan plan_c2r;
-#else
- void *setup;
-#endif
- uint32_t size;
- float scale;
-};
-
-#ifdef HAVE_FFTW
-
-/* interleaved [r0,i0,...,r7,i7] -> blocked [r0..r7,i0..i7] */
-static void fft_blocked_avx2(float *data, uint32_t len)
-{
- const __m256i idx = _mm256_setr_epi32(0,2,4,6,1,3,5,7);
- uint32_t i;
- for (i = 0; i < len; i += FFT_BLOCK) {
- __m256 v0 = _mm256_load_ps(&data[0]); /* r0 i0 r1 i1 r2 i2 r3 i3 */
- __m256 v1 = _mm256_load_ps(&data[8]); /* r4 i4 r5 i5 r6 i6 r7 i7 */
- __m256 t0 = _mm256_permutevar8x32_ps(v0, idx); /* r0 r1 r2 r3 i0 i1 i2 i3 */
- __m256 t1 = _mm256_permutevar8x32_ps(v1, idx); /* r4 r5 r6 r7 i4 i5 i6 i7 */
- _mm256_store_ps(&data[0], _mm256_permute2f128_ps(t0, t1, 0x20));
- _mm256_store_ps(&data[8], _mm256_permute2f128_ps(t0, t1, 0x31));
- data += 2 * FFT_BLOCK;
- }
-}
-
-/* blocked [r0..r7,i0..i7] -> interleaved [r0,i0,...,r7,i7] with scaling */
-static void fft_interleaved_avx2(float *data, uint32_t len, float scale)
-{
- const __m256i idx = _mm256_setr_epi32(0,4,1,5,2,6,3,7);
- __m256 s = _mm256_set1_ps(scale);
- uint32_t i;
- for (i = 0; i < len; i += FFT_BLOCK) {
- __m256 r = _mm256_mul_ps(_mm256_load_ps(&data[0]), s);
- __m256 im = _mm256_mul_ps(_mm256_load_ps(&data[8]), s);
- __m256 t0 = _mm256_permute2f128_ps(r, im, 0x20);
- __m256 t1 = _mm256_permute2f128_ps(r, im, 0x31);
- _mm256_store_ps(&data[0], _mm256_permutevar8x32_ps(t0, idx));
- _mm256_store_ps(&data[8], _mm256_permutevar8x32_ps(t1, idx));
- data += 2 * FFT_BLOCK;
- }
-}
-#endif
-
-void *dsp_fft_memalloc_avx2(void *obj, uint32_t size, bool real)
-{
-#ifdef HAVE_FFTW
- return fftwf_alloc_real(real ? size : SPA_ROUND_UP_N(size, FFT_BLOCK) * 2);
-#else
- if (real)
- return pffft_aligned_malloc(size * sizeof(float));
- else
- return pffft_aligned_malloc(size * 2 * sizeof(float));
-#endif
-}
-
-void dsp_fft_memclear_avx2(void *obj, void *data, uint32_t size, bool real)
-{
-#ifdef HAVE_FFTW
- spa_fga_dsp_clear(obj, data, real ? size : SPA_ROUND_UP_N(size, FFT_BLOCK) * 2);
-#else
- spa_fga_dsp_clear(obj, data, real ? size : size * 2);
-#endif
-}
-
-void dsp_fft_run_avx2(void *obj, void *fft, int direction,
- const float * SPA_RESTRICT src, float * SPA_RESTRICT dst)
-{
- struct fft_info *info = fft;
-#ifdef HAVE_FFTW
- uint32_t freq_size = SPA_ROUND_UP_N(info->size / 2 + 1, FFT_BLOCK);
- if (direction > 0) {
- fftwf_execute_dft_r2c(info->plan_r2c, (float*)src, (fftwf_complex*)dst);
- fft_blocked_avx2(dst, freq_size);
- } else {
- fft_interleaved_avx2((float*)src, freq_size, info->scale);
- fftwf_execute_dft_c2r(info->plan_c2r, (fftwf_complex*)src, dst);
- }
-#else
- if (direction < 0)
- spa_fga_dsp_linear(obj, (float*)src, (float*)src,
- info->scale, 0.0f, info->size);
- pffft_transform(info->setup, src, dst, NULL, direction < 0 ? PFFFT_BACKWARD : PFFFT_FORWARD);
-#endif
+ __m256 aa, bb, dc, x0, x1;
+ aa = _mm256_moveldup_ps(ab);
+ bb = _mm256_movehdup_ps(ab);
+ x0 = _mm256_mul_ps(aa, cd);
+ dc = _mm256_shuffle_ps(cd, cd, _MM_SHUFFLE(2,3,0,1));
+ x1 = _mm256_mul_ps(bb, dc);
+ return _mm256_addsub_ps(x0, x1);
}
void dsp_fft_cmul_avx2(void *obj, void *fft,
float * SPA_RESTRICT dst, const float * SPA_RESTRICT a,
- const float * SPA_RESTRICT b, uint32_t len)
+ const float * SPA_RESTRICT b, uint32_t len, const float scale)
{
#ifdef HAVE_FFTW
- uint32_t i, plen = SPA_ROUND_UP_N(len, 8) * 2;
+ __m256 s = _mm256_set1_ps(scale);
+ __m256 aa[2], bb[2], dd[2];
+ uint32_t i, unrolled;
- for (i = 0; i < plen; i += 16) {
- __m256 ar = _mm256_load_ps(&a[i]);
- __m256 ai = _mm256_load_ps(&a[i+8]);
- __m256 br = _mm256_load_ps(&b[i]);
- __m256 bi = _mm256_load_ps(&b[i+8]);
- __m256 dr = _mm256_mul_ps(ar, br);
- __m256 di = _mm256_mul_ps(ar, bi);
- dr = _mm256_fnmadd_ps(ai, bi, dr); /* ar*br - ai*bi */
- di = _mm256_fmadd_ps(ai, br, di); /* ar*bi + ai*br */
- _mm256_store_ps(&dst[i], dr);
- _mm256_store_ps(&dst[i+8], di);
+ if (SPA_IS_ALIGNED(a, 32) &&
+ SPA_IS_ALIGNED(b, 32) &&
+ SPA_IS_ALIGNED(dst, 32))
+ unrolled = len & ~7;
+ else
+ unrolled = 0;
+
+ for (i = 0; i < unrolled; i+=8) {
+ aa[0] = _mm256_load_ps(&a[2*i]); /* ar0 ai0 ar1 ai1 */
+ aa[1] = _mm256_load_ps(&a[2*i+8]); /* ar1 ai1 ar2 ai2 */
+ bb[0] = _mm256_load_ps(&b[2*i]); /* br0 bi0 br1 bi1 */
+ bb[1] = _mm256_load_ps(&b[2*i+8]); /* br2 bi2 br3 bi3 */
+ dd[0] = _mm256_mul_pz(aa[0], bb[0]);
+ dd[1] = _mm256_mul_pz(aa[1], bb[1]);
+ dd[0] = _mm256_mul_ps(dd[0], s);
+ dd[1] = _mm256_mul_ps(dd[1], s);
+ _mm256_store_ps(&dst[2*i], dd[0]);
+ _mm256_store_ps(&dst[2*i+8], dd[1]);
+ }
+ for (; i < len; i++) {
+ dst[2*i ] = (a[2*i] * b[2*i ] - a[2*i+1] * b[2*i+1]) * scale;
+ dst[2*i+1] = (a[2*i] * b[2*i+1] + a[2*i+1] * b[2*i ]) * scale;
}
#else
- struct fft_info *info = fft;
- pffft_zconvolve(info->setup, a, b, dst, 1.0f);
+ pffft_zconvolve(fft, a, b, dst, scale);
#endif
}
void dsp_fft_cmuladd_avx2(void *obj, void *fft,
float * SPA_RESTRICT dst, const float * SPA_RESTRICT src,
const float * SPA_RESTRICT a, const float * SPA_RESTRICT b,
- uint32_t len)
+ uint32_t len, const float scale)
{
#ifdef HAVE_FFTW
- uint32_t i, plen = SPA_ROUND_UP_N(len, 8) * 2;
+ __m256 s = _mm256_set1_ps(scale);
+ __m256 aa[2], bb[2], dd[2], t[2];
+ uint32_t i, unrolled;
- for (i = 0; i < plen; i += 16) {
- __m256 ar = _mm256_load_ps(&a[i]);
- __m256 ai = _mm256_load_ps(&a[i+8]);
- __m256 br = _mm256_load_ps(&b[i]);
- __m256 bi = _mm256_load_ps(&b[i+8]);
- __m256 dr = _mm256_mul_ps(ar, br);
- __m256 di = _mm256_mul_ps(ar, bi);
- dr = _mm256_fnmadd_ps(ai, bi, dr); /* ar*br - ai*bi */
- di = _mm256_fmadd_ps(ai, br, di); /* ar*bi + ai*br */
- _mm256_store_ps(&dst[i], _mm256_add_ps(dr,
- _mm256_load_ps(&src[i])));
- _mm256_store_ps(&dst[i+8], _mm256_add_ps(di,
- _mm256_load_ps(&src[i+8])));
+ if (SPA_IS_ALIGNED(a, 32) &&
+ SPA_IS_ALIGNED(b, 32) &&
+ SPA_IS_ALIGNED(src, 32) &&
+ SPA_IS_ALIGNED(dst, 32))
+ unrolled = len & ~7;
+ else
+ unrolled = 0;
+
+ for (i = 0; i < unrolled; i+=8) {
+ aa[0] = _mm256_load_ps(&a[2*i]); /* ar0 ai0 ar1 ai1 */
+ aa[1] = _mm256_load_ps(&a[2*i+8]); /* ar1 ai1 ar2 ai2 */
+ bb[0] = _mm256_load_ps(&b[2*i]); /* br0 bi0 br1 bi1 */
+ bb[1] = _mm256_load_ps(&b[2*i+8]); /* br2 bi2 br3 bi3 */
+ dd[0] = _mm256_mul_pz(aa[0], bb[0]);
+ dd[1] = _mm256_mul_pz(aa[1], bb[1]);
+ dd[0] = _mm256_mul_ps(dd[0], s);
+ dd[1] = _mm256_mul_ps(dd[1], s);
+ t[0] = _mm256_load_ps(&src[2*i]);
+ t[1] = _mm256_load_ps(&src[2*i+8]);
+ t[0] = _mm256_add_ps(t[0], dd[0]);
+ t[1] = _mm256_add_ps(t[1], dd[1]);
+ _mm256_store_ps(&dst[2*i], t[0]);
+ _mm256_store_ps(&dst[2*i+8], t[1]);
+ }
+ for (; i < len; i++) {
+ dst[2*i ] = src[2*i ] + (a[2*i] * b[2*i ] - a[2*i+1] * b[2*i+1]) * scale;
+ dst[2*i+1] = src[2*i+1] + (a[2*i] * b[2*i+1] + a[2*i+1] * b[2*i ]) * scale;
}
#else
- struct fft_info *info = fft;
- pffft_zconvolve_accumulate(info->setup, a, b, src, dst, 1.0f);
+ pffft_zconvolve_accumulate(fft, a, b, src, dst, scale);
#endif
}
diff --git a/spa/plugins/filter-graph/audio-dsp-c.c b/spa/plugins/filter-graph/audio-dsp-c.c
index e430aae0b..0aab9decc 100644
--- a/spa/plugins/filter-graph/audio-dsp-c.c
+++ b/spa/plugins/filter-graph/audio-dsp-c.c
@@ -235,57 +235,48 @@ void dsp_delay_c(void *obj, float *buffer, uint32_t *pos, uint32_t n_buffer,
}
}
-struct fft_info {
#ifdef HAVE_FFTW
+struct fft_info {
fftwf_plan plan_r2c;
fftwf_plan plan_c2r;
-#else
- void *setup;
-#endif
- uint32_t size;
- float scale;
};
+#endif
void *dsp_fft_new_c(void *obj, uint32_t size, bool real)
{
+#ifdef HAVE_FFTW
struct fft_info *info = calloc(1, sizeof(struct fft_info));
+ float *rdata;
+ fftwf_complex *cdata;
if (info == NULL)
return NULL;
- info->size = size;
- info->scale = 1.0f / size;
+ rdata = fftwf_alloc_real(size * 2);
+ cdata = fftwf_alloc_complex(size + 1);
-#ifdef HAVE_FFTW
- {
- float *rdata;
- fftwf_complex *cdata;
+ info->plan_r2c = fftwf_plan_dft_r2c_1d(size, rdata, cdata, FFTW_ESTIMATE);
+ info->plan_c2r = fftwf_plan_dft_c2r_1d(size, cdata, rdata, FFTW_ESTIMATE);
- rdata = fftwf_alloc_real(size * 2);
- cdata = fftwf_alloc_complex(size + 1);
+ fftwf_free(rdata);
+ fftwf_free(cdata);
- info->plan_r2c = fftwf_plan_dft_r2c_1d(size, rdata, cdata, FFTW_ESTIMATE);
- info->plan_c2r = fftwf_plan_dft_c2r_1d(size, cdata, rdata, FFTW_ESTIMATE);
-
- fftwf_free(rdata);
- fftwf_free(cdata);
- }
-#else
- info->setup = pffft_new_setup(size, real ? PFFFT_REAL : PFFFT_COMPLEX);
-#endif
return info;
+#else
+ return pffft_new_setup(size, real ? PFFFT_REAL : PFFFT_COMPLEX);
+#endif
}
void dsp_fft_free_c(void *obj, void *fft)
{
- struct fft_info *info = fft;
#ifdef HAVE_FFTW
+ struct fft_info *info = fft;
fftwf_destroy_plan(info->plan_r2c);
fftwf_destroy_plan(info->plan_c2r);
-#else
- pffft_destroy_setup(info->setup);
-#endif
free(info);
+#else
+ pffft_destroy_setup(fft);
+#endif
}
void *dsp_fft_memalloc_c(void *obj, uint32_t size, bool real)
@@ -324,51 +315,43 @@ void dsp_fft_memclear_c(void *obj, void *data, uint32_t size, bool real)
void dsp_fft_run_c(void *obj, void *fft, int direction,
const float * SPA_RESTRICT src, float * SPA_RESTRICT dst)
{
- struct fft_info *info = fft;
#ifdef HAVE_FFTW
- if (direction > 0) {
- fftwf_execute_dft_r2c(info->plan_r2c, (float*)src, (fftwf_complex*)dst);
- } else {
- spa_fga_dsp_linear(obj, (float*)src, (float*)src,
- info->scale, 0.0f, (info->size / 2 + 1) * 2);
- fftwf_execute_dft_c2r(info->plan_c2r, (fftwf_complex*)src, dst);
- }
+ struct fft_info *info = fft;
+ if (direction > 0)
+ fftwf_execute_dft_r2c (info->plan_r2c, (float*)src, (fftwf_complex*)dst);
+ else
+ fftwf_execute_dft_c2r (info->plan_c2r, (fftwf_complex*)src, dst);
#else
- if (direction < 0)
- spa_fga_dsp_linear(obj, (float*)src, (float*)src,
- info->scale, 0.0f, info->size);
- pffft_transform(info->setup, src, dst, NULL, direction < 0 ? PFFFT_BACKWARD : PFFFT_FORWARD);
+ pffft_transform(fft, src, dst, NULL, direction < 0 ? PFFFT_BACKWARD : PFFFT_FORWARD);
#endif
}
void dsp_fft_cmul_c(void *obj, void *fft,
float * SPA_RESTRICT dst, const float * SPA_RESTRICT a,
- const float * SPA_RESTRICT b, uint32_t len)
+ const float * SPA_RESTRICT b, uint32_t len, const float scale)
{
#ifdef HAVE_FFTW
for (uint32_t i = 0; i < len; i++) {
- dst[2*i ] = a[2*i] * b[2*i ] - a[2*i+1] * b[2*i+1];
- dst[2*i+1] = a[2*i] * b[2*i+1] + a[2*i+1] * b[2*i ];
+ dst[2*i ] = (a[2*i] * b[2*i ] - a[2*i+1] * b[2*i+1]) * scale;
+ dst[2*i+1] = (a[2*i] * b[2*i+1] + a[2*i+1] * b[2*i ]) * scale;
}
#else
- struct fft_info *info = fft;
- pffft_zconvolve(info->setup, a, b, dst, 1.0f);
+ pffft_zconvolve(fft, a, b, dst, scale);
#endif
}
void dsp_fft_cmuladd_c(void *obj, void *fft,
float * SPA_RESTRICT dst, const float * SPA_RESTRICT src,
const float * SPA_RESTRICT a, const float * SPA_RESTRICT b,
- uint32_t len)
+ uint32_t len, const float scale)
{
#ifdef HAVE_FFTW
for (uint32_t i = 0; i < len; i++) {
- dst[2*i ] = src[2*i ] + a[2*i] * b[2*i ] - a[2*i+1] * b[2*i+1];
- dst[2*i+1] = src[2*i+1] + a[2*i] * b[2*i+1] + a[2*i+1] * b[2*i ];
+ dst[2*i ] = src[2*i ] + (a[2*i] * b[2*i ] - a[2*i+1] * b[2*i+1]) * scale;
+ dst[2*i+1] = src[2*i+1] + (a[2*i] * b[2*i+1] + a[2*i+1] * b[2*i ]) * scale;
}
#else
- struct fft_info *info = fft;
- pffft_zconvolve_accumulate(info->setup, a, b, src, dst, 1.0f);
+ pffft_zconvolve_accumulate(fft, a, b, src, dst, scale);
#endif
}
diff --git a/spa/plugins/filter-graph/audio-dsp-impl.h b/spa/plugins/filter-graph/audio-dsp-impl.h
index 4b63bf22f..a5d3c975f 100644
--- a/spa/plugins/filter-graph/audio-dsp-impl.h
+++ b/spa/plugins/filter-graph/audio-dsp-impl.h
@@ -50,12 +50,12 @@ void dsp_fft_run_##arch(void *obj, void *fft, int direction, \
#define MAKE_FFT_CMUL_FUNC(arch) \
void dsp_fft_cmul_##arch(void *obj, void *fft, \
float * SPA_RESTRICT dst, const float * SPA_RESTRICT a, \
- const float * SPA_RESTRICT b, uint32_t len)
+ const float * SPA_RESTRICT b, uint32_t len, const float scale)
#define MAKE_FFT_CMULADD_FUNC(arch) \
void dsp_fft_cmuladd_##arch(void *obj, void *fft, \
float * dst, const float * src, \
const float * SPA_RESTRICT a, const float * SPA_RESTRICT b, \
- uint32_t len)
+ uint32_t len, const float scale)
MAKE_CLEAR_FUNC(c);
@@ -79,24 +79,14 @@ MAKE_FFT_CMULADD_FUNC(c);
#if defined (HAVE_SSE)
MAKE_MIX_GAIN_FUNC(sse);
MAKE_SUM_FUNC(sse);
-MAKE_LINEAR_FUNC(sse);
-MAKE_MULT_FUNC(sse);
MAKE_BIQUAD_RUN_FUNC(sse);
MAKE_DELAY_FUNC(sse);
-MAKE_FFT_MEMALLOC_FUNC(sse);
-MAKE_FFT_MEMCLEAR_FUNC(sse);
-MAKE_FFT_RUN_FUNC(sse);
MAKE_FFT_CMUL_FUNC(sse);
MAKE_FFT_CMULADD_FUNC(sse);
#endif
#if defined (HAVE_AVX2)
MAKE_MIX_GAIN_FUNC(avx2);
MAKE_SUM_FUNC(avx2);
-MAKE_LINEAR_FUNC(avx2);
-MAKE_MULT_FUNC(avx2);
-MAKE_FFT_MEMALLOC_FUNC(avx2);
-MAKE_FFT_MEMCLEAR_FUNC(avx2);
-MAKE_FFT_RUN_FUNC(avx2);
MAKE_FFT_CMUL_FUNC(avx2);
MAKE_FFT_CMULADD_FUNC(avx2);
#endif
diff --git a/spa/plugins/filter-graph/audio-dsp-sse.c b/spa/plugins/filter-graph/audio-dsp-sse.c
index 54f2f212c..e3a877b71 100644
--- a/spa/plugins/filter-graph/audio-dsp-sse.c
+++ b/spa/plugins/filter-graph/audio-dsp-sse.c
@@ -12,9 +12,7 @@
#include
-#ifdef HAVE_FFTW
-#include
-#else
+#ifndef HAVE_FFTW
#include "pffft.h"
#endif
@@ -615,104 +613,6 @@ void dsp_biquad_run_sse(void *obj, struct biquad *bq, uint32_t n_bq, uint32_t bq
}
}
-void dsp_mult_sse(void *obj,
- float * SPA_RESTRICT dst,
- const float * SPA_RESTRICT src[],
- uint32_t n_src, uint32_t n_samples)
-{
- uint32_t n, i, unrolled;
- __m128 in[4];
-
- if (n_src == 0) {
- memset(dst, 0, n_samples * sizeof(float));
- return;
- }
-
- if (dst != src[0])
- spa_memcpy(dst, src[0], n_samples * sizeof(float));
-
- if (SPA_LIKELY(SPA_IS_ALIGNED(dst, 16))) {
- unrolled = n_samples & ~15;
- for (i = 1; i < n_src; i++) {
- if (SPA_UNLIKELY(!SPA_IS_ALIGNED(src[i], 16))) {
- unrolled = 0;
- break;
- }
- }
- } else
- unrolled = 0;
-
- for (i = 1; i < n_src; i++) {
- for (n = 0; n < unrolled; n += 16) {
- in[0] = _mm_mul_ps(_mm_load_ps(&dst[n+ 0]), _mm_load_ps(&src[i][n+ 0]));
- in[1] = _mm_mul_ps(_mm_load_ps(&dst[n+ 4]), _mm_load_ps(&src[i][n+ 4]));
- in[2] = _mm_mul_ps(_mm_load_ps(&dst[n+ 8]), _mm_load_ps(&src[i][n+ 8]));
- in[3] = _mm_mul_ps(_mm_load_ps(&dst[n+12]), _mm_load_ps(&src[i][n+12]));
- _mm_store_ps(&dst[n+ 0], in[0]);
- _mm_store_ps(&dst[n+ 4], in[1]);
- _mm_store_ps(&dst[n+ 8], in[2]);
- _mm_store_ps(&dst[n+12], in[3]);
- }
- for (; n < n_samples; n++)
- dst[n] *= src[i][n];
- }
-}
-
-void dsp_linear_sse(void *obj, float * dst,
- const float * SPA_RESTRICT src, const float mult,
- const float add, uint32_t n_samples)
-{
- uint32_t n, unrolled;
- __m128 m, a;
-
- if (mult == 0.0f) {
- a = _mm_set1_ps(add);
- unrolled = n_samples & ~15;
- for (n = 0; n < unrolled; n += 16) {
- _mm_storeu_ps(&dst[n+ 0], a);
- _mm_storeu_ps(&dst[n+ 4], a);
- _mm_storeu_ps(&dst[n+ 8], a);
- _mm_storeu_ps(&dst[n+12], a);
- }
- for (; n < n_samples; n++)
- dst[n] = add;
- return;
- }
-
- if (SPA_LIKELY(SPA_IS_ALIGNED(src, 16) && SPA_IS_ALIGNED(dst, 16)))
- unrolled = n_samples & ~15;
- else
- unrolled = 0;
-
- m = _mm_set1_ps(mult);
-
- if (add == 0.0f) {
- if (mult == 1.0f) {
- if (dst != src)
- spa_memcpy(dst, src, n_samples * sizeof(float));
- return;
- }
- for (n = 0; n < unrolled; n += 16) {
- _mm_store_ps(&dst[n+ 0], _mm_mul_ps(m, _mm_load_ps(&src[n+ 0])));
- _mm_store_ps(&dst[n+ 4], _mm_mul_ps(m, _mm_load_ps(&src[n+ 4])));
- _mm_store_ps(&dst[n+ 8], _mm_mul_ps(m, _mm_load_ps(&src[n+ 8])));
- _mm_store_ps(&dst[n+12], _mm_mul_ps(m, _mm_load_ps(&src[n+12])));
- }
- for (; n < n_samples; n++)
- dst[n] = mult * src[n];
- } else {
- a = _mm_set1_ps(add);
- for (n = 0; n < unrolled; n += 16) {
- _mm_store_ps(&dst[n+ 0], _mm_add_ps(_mm_mul_ps(m, _mm_load_ps(&src[n+ 0])), a));
- _mm_store_ps(&dst[n+ 4], _mm_add_ps(_mm_mul_ps(m, _mm_load_ps(&src[n+ 4])), a));
- _mm_store_ps(&dst[n+ 8], _mm_add_ps(_mm_mul_ps(m, _mm_load_ps(&src[n+ 8])), a));
- _mm_store_ps(&dst[n+12], _mm_add_ps(_mm_mul_ps(m, _mm_load_ps(&src[n+12])), a));
- }
- for (; n < n_samples; n++)
- dst[n] = mult * src[n] + add;
- }
-}
-
void dsp_delay_sse(void *obj, float *buffer, uint32_t *pos, uint32_t n_buffer, uint32_t delay,
float *dst, const float *src, uint32_t n_samples, float fb, float ff)
{
@@ -782,134 +682,100 @@ void dsp_delay_sse(void *obj, float *buffer, uint32_t *pos, uint32_t n_buffer, u
*pos = w;
}
-#define FFT_BLOCK 4
-
-struct fft_info {
-#ifdef HAVE_FFTW
- fftwf_plan plan_r2c;
- fftwf_plan plan_c2r;
-#else
- void *setup;
-#endif
- uint32_t size;
- float scale;
-};
-
-#ifdef HAVE_FFTW
-
-/* interleaved [r0,i0,r1,i1,r2,i2,r3,i3] -> blocked [r0,r1,r2,r3,i0,i1,i2,i3] */
-static void fft_blocked_sse(float *data, uint32_t len)
+inline static void _mm_mul_pz(__m128 *a, __m128 *b, __m128 *d)
{
- uint32_t i;
- for (i = 0; i < len; i += FFT_BLOCK) {
- __m128 v0 = _mm_load_ps(&data[0]); /* r0 i0 r1 i1 */
- __m128 v1 = _mm_load_ps(&data[4]); /* r2 i2 r3 i3 */
- _mm_store_ps(&data[0], _mm_shuffle_ps(v0, v1, _MM_SHUFFLE(2,0,2,0)));
- _mm_store_ps(&data[4], _mm_shuffle_ps(v0, v1, _MM_SHUFFLE(3,1,3,1)));
- data += 2 * FFT_BLOCK;
- }
-}
+ __m128 ar, ai, br, bi, arbr, arbi, aibi, aibr, dr, di;
+ ar = _mm_shuffle_ps(a[0], a[1], _MM_SHUFFLE(2,0,2,0)); /* ar0 ar1 ar2 ar3 */
+ ai = _mm_shuffle_ps(a[0], a[1], _MM_SHUFFLE(3,1,3,1)); /* ai0 ai1 ai2 ai3 */
+ br = _mm_shuffle_ps(b[0], b[1], _MM_SHUFFLE(2,0,2,0)); /* br0 br1 br2 br3 */
+ bi = _mm_shuffle_ps(b[0], b[1], _MM_SHUFFLE(3,1,3,1)) /* bi0 bi1 bi2 bi3 */;
-/* blocked [r0,r1,r2,r3,i0,i1,i2,i3] -> interleaved [r0,i0,r1,i1,r2,i2,r3,i3] with scaling */
-static void fft_interleaved_sse(float *data, uint32_t len, float scale)
-{
- uint32_t i;
- __m128 s = _mm_set1_ps(scale);
- for (i = 0; i < len; i += FFT_BLOCK) {
- __m128 r = _mm_mul_ps(_mm_load_ps(&data[0]), s);
- __m128 im = _mm_mul_ps(_mm_load_ps(&data[4]), s);
- _mm_store_ps(&data[0], _mm_unpacklo_ps(r, im));
- _mm_store_ps(&data[4], _mm_unpackhi_ps(r, im));
- data += 2 * FFT_BLOCK;
- }
-}
-#endif
+ arbr = _mm_mul_ps(ar, br); /* ar * br */
+ arbi = _mm_mul_ps(ar, bi); /* ar * bi */
-void *dsp_fft_memalloc_sse(void *obj, uint32_t size, bool real)
-{
-#ifdef HAVE_FFTW
- return fftwf_alloc_real(real ? size : SPA_ROUND_UP_N(size, FFT_BLOCK) * 2);
-#else
- if (real)
- return pffft_aligned_malloc(size * sizeof(float));
- else
- return pffft_aligned_malloc(size * 2 * sizeof(float));
-#endif
-}
+ aibi = _mm_mul_ps(ai, bi); /* ai * bi */
+ aibr = _mm_mul_ps(ai, br); /* ai * br */
-void dsp_fft_memclear_sse(void *obj, void *data, uint32_t size, bool real)
-{
-#ifdef HAVE_FFTW
- spa_fga_dsp_clear(obj, data, real ? size : SPA_ROUND_UP_N(size, FFT_BLOCK) * 2);
-#else
- spa_fga_dsp_clear(obj, data, real ? size : size * 2);
-#endif
-}
-
-void dsp_fft_run_sse(void *obj, void *fft, int direction,
- const float * SPA_RESTRICT src, float * SPA_RESTRICT dst)
-{
- struct fft_info *info = fft;
-#ifdef HAVE_FFTW
- uint32_t freq_size = SPA_ROUND_UP_N(info->size / 2 + 1, FFT_BLOCK);
- if (direction > 0) {
- fftwf_execute_dft_r2c(info->plan_r2c, (float*)src, (fftwf_complex*)dst);
- fft_blocked_sse(dst, freq_size);
- } else {
- fft_interleaved_sse((float*)src, freq_size, info->scale);
- fftwf_execute_dft_c2r(info->plan_c2r, (fftwf_complex*)src, dst);
- }
-#else
- if (direction < 0)
- spa_fga_dsp_linear(obj, (float*)src, (float*)src,
- info->scale, 0.0f, info->size);
- pffft_transform(info->setup, src, dst, NULL, direction < 0 ? PFFFT_BACKWARD : PFFFT_FORWARD);
-#endif
+ dr = _mm_sub_ps(arbr, aibi); /* ar * br - ai * bi */
+ di = _mm_add_ps(arbi, aibr); /* ar * bi + ai * br */
+ d[0] = _mm_unpacklo_ps(dr, di);
+ d[1] = _mm_unpackhi_ps(dr, di);
}
void dsp_fft_cmul_sse(void *obj, void *fft,
float * SPA_RESTRICT dst, const float * SPA_RESTRICT a,
- const float * SPA_RESTRICT b, uint32_t len)
+ const float * SPA_RESTRICT b, uint32_t len, const float scale)
{
#ifdef HAVE_FFTW
- uint32_t i, plen = SPA_ROUND_UP_N(len, FFT_BLOCK) * 2;
+ __m128 s = _mm_set1_ps(scale);
+ __m128 aa[2], bb[2], dd[2];
+ uint32_t i, unrolled;
- for (i = 0; i < plen; i += 2 * FFT_BLOCK) {
- __m128 ar = _mm_load_ps(&a[i]);
- __m128 ai = _mm_load_ps(&a[i + FFT_BLOCK]);
- __m128 br = _mm_load_ps(&b[i]);
- __m128 bi = _mm_load_ps(&b[i + FFT_BLOCK]);
- _mm_store_ps(&dst[i], _mm_sub_ps(
- _mm_mul_ps(ar, br), _mm_mul_ps(ai, bi)));
- _mm_store_ps(&dst[i + FFT_BLOCK], _mm_add_ps(
- _mm_mul_ps(ar, bi), _mm_mul_ps(ai, br)));
+ if (SPA_IS_ALIGNED(a, 16) &&
+ SPA_IS_ALIGNED(b, 16) &&
+ SPA_IS_ALIGNED(dst, 16))
+ unrolled = len & ~3;
+ else
+ unrolled = 0;
+
+ for (i = 0; i < unrolled; i+=4) {
+ aa[0] = _mm_load_ps(&a[2*i]); /* ar0 ai0 ar1 ai1 */
+ aa[1] = _mm_load_ps(&a[2*i+4]); /* ar1 ai1 ar2 ai2 */
+ bb[0] = _mm_load_ps(&b[2*i]); /* br0 bi0 br1 bi1 */
+ bb[1] = _mm_load_ps(&b[2*i+4]); /* br2 bi2 br3 bi3 */
+ _mm_mul_pz(aa, bb, dd);
+ dd[0] = _mm_mul_ps(dd[0], s);
+ dd[1] = _mm_mul_ps(dd[1], s);
+ _mm_store_ps(&dst[2*i], dd[0]);
+ _mm_store_ps(&dst[2*i+4], dd[1]);
+ }
+ for (; i < len; i++) {
+ dst[2*i ] = (a[2*i] * b[2*i ] - a[2*i+1] * b[2*i+1]) * scale;
+ dst[2*i+1] = (a[2*i] * b[2*i+1] + a[2*i+1] * b[2*i ]) * scale;
}
#else
- struct fft_info *info = fft;
- pffft_zconvolve(info->setup, a, b, dst, 1.0f);
+ pffft_zconvolve(fft, a, b, dst, scale);
#endif
}
void dsp_fft_cmuladd_sse(void *obj, void *fft,
float * SPA_RESTRICT dst, const float * SPA_RESTRICT src,
const float * SPA_RESTRICT a, const float * SPA_RESTRICT b,
- uint32_t len)
+ uint32_t len, const float scale)
{
#ifdef HAVE_FFTW
- uint32_t i, plen = SPA_ROUND_UP_N(len, FFT_BLOCK) * 2;
+ __m128 s = _mm_set1_ps(scale);
+ __m128 aa[2], bb[2], dd[2], t[2];
+ uint32_t i, unrolled;
- for (i = 0; i < plen; i += 2 * FFT_BLOCK) {
- __m128 ar = _mm_load_ps(&a[i]);
- __m128 ai = _mm_load_ps(&a[i + FFT_BLOCK]);
- __m128 br = _mm_load_ps(&b[i]);
- __m128 bi = _mm_load_ps(&b[i + FFT_BLOCK]);
- _mm_store_ps(&dst[i], _mm_add_ps(_mm_load_ps(&src[i]),
- _mm_sub_ps(_mm_mul_ps(ar, br), _mm_mul_ps(ai, bi))));
- _mm_store_ps(&dst[i + FFT_BLOCK], _mm_add_ps(_mm_load_ps(&src[i + FFT_BLOCK]),
- _mm_add_ps(_mm_mul_ps(ar, bi), _mm_mul_ps(ai, br))));
+ if (SPA_IS_ALIGNED(a, 16) &&
+ SPA_IS_ALIGNED(b, 16) &&
+ SPA_IS_ALIGNED(src, 16) &&
+ SPA_IS_ALIGNED(dst, 16))
+ unrolled = len & ~3;
+ else
+ unrolled = 0;
+
+ for (i = 0; i < unrolled; i+=4) {
+ aa[0] = _mm_load_ps(&a[2*i]); /* ar0 ai0 ar1 ai1 */
+ aa[1] = _mm_load_ps(&a[2*i+4]); /* ar1 ai1 ar2 ai2 */
+ bb[0] = _mm_load_ps(&b[2*i]); /* br0 bi0 br1 bi1 */
+ bb[1] = _mm_load_ps(&b[2*i+4]); /* br2 bi2 br3 bi3 */
+ _mm_mul_pz(aa, bb, dd);
+ dd[0] = _mm_mul_ps(dd[0], s);
+ dd[1] = _mm_mul_ps(dd[1], s);
+ t[0] = _mm_load_ps(&src[2*i]);
+ t[1] = _mm_load_ps(&src[2*i+4]);
+ t[0] = _mm_add_ps(t[0], dd[0]);
+ t[1] = _mm_add_ps(t[1], dd[1]);
+ _mm_store_ps(&dst[2*i], t[0]);
+ _mm_store_ps(&dst[2*i+4], t[1]);
+ }
+ for (; i < len; i++) {
+ dst[2*i ] = src[2*i ] + (a[2*i] * b[2*i ] - a[2*i+1] * b[2*i+1]) * scale;
+ dst[2*i+1] = src[2*i+1] + (a[2*i] * b[2*i+1] + a[2*i+1] * b[2*i ]) * scale;
}
#else
- struct fft_info *info = fft;
- pffft_zconvolve_accumulate(info->setup, a, b, src, dst, 1.0f);
+ pffft_zconvolve_accumulate(fft, a, b, src, dst, scale);
#endif
}
diff --git a/spa/plugins/filter-graph/audio-dsp.c b/spa/plugins/filter-graph/audio-dsp.c
index d72c46d87..133b53db5 100644
--- a/spa/plugins/filter-graph/audio-dsp.c
+++ b/spa/plugins/filter-graph/audio-dsp.c
@@ -24,20 +24,20 @@ struct dsp_info {
static const struct dsp_info dsp_table[] =
{
#if defined (HAVE_AVX2)
- { SPA_CPU_FLAG_AVX2 | SPA_CPU_FLAG_FMA3,
+ { SPA_CPU_FLAG_AVX2,
.funcs.clear = dsp_clear_c,
.funcs.copy = dsp_copy_c,
.funcs.mix_gain = dsp_mix_gain_avx2,
.funcs.biquad_run = dsp_biquad_run_sse,
.funcs.sum = dsp_sum_avx2,
- .funcs.linear = dsp_linear_avx2,
- .funcs.mult = dsp_mult_avx2,
+ .funcs.linear = dsp_linear_c,
+ .funcs.mult = dsp_mult_c,
.funcs.fft_new = dsp_fft_new_c,
.funcs.fft_free = dsp_fft_free_c,
- .funcs.fft_memalloc = dsp_fft_memalloc_avx2,
+ .funcs.fft_memalloc = dsp_fft_memalloc_c,
.funcs.fft_memfree = dsp_fft_memfree_c,
- .funcs.fft_memclear = dsp_fft_memclear_avx2,
- .funcs.fft_run = dsp_fft_run_avx2,
+ .funcs.fft_memclear = dsp_fft_memclear_c,
+ .funcs.fft_run = dsp_fft_run_c,
.funcs.fft_cmul = dsp_fft_cmul_avx2,
.funcs.fft_cmuladd = dsp_fft_cmuladd_avx2,
.funcs.delay = dsp_delay_sse,
@@ -50,14 +50,14 @@ static const struct dsp_info dsp_table[] =
.funcs.mix_gain = dsp_mix_gain_sse,
.funcs.biquad_run = dsp_biquad_run_sse,
.funcs.sum = dsp_sum_sse,
- .funcs.linear = dsp_linear_sse,
- .funcs.mult = dsp_mult_sse,
+ .funcs.linear = dsp_linear_c,
+ .funcs.mult = dsp_mult_c,
.funcs.fft_new = dsp_fft_new_c,
.funcs.fft_free = dsp_fft_free_c,
- .funcs.fft_memalloc = dsp_fft_memalloc_sse,
+ .funcs.fft_memalloc = dsp_fft_memalloc_c,
.funcs.fft_memfree = dsp_fft_memfree_c,
- .funcs.fft_memclear = dsp_fft_memclear_sse,
- .funcs.fft_run = dsp_fft_run_sse,
+ .funcs.fft_memclear = dsp_fft_memclear_c,
+ .funcs.fft_run = dsp_fft_run_c,
.funcs.fft_cmul = dsp_fft_cmul_sse,
.funcs.fft_cmuladd = dsp_fft_cmuladd_sse,
.funcs.delay = dsp_delay_sse,
diff --git a/spa/plugins/filter-graph/audio-dsp.h b/spa/plugins/filter-graph/audio-dsp.h
index 446d72f1d..81cbdaf36 100644
--- a/spa/plugins/filter-graph/audio-dsp.h
+++ b/spa/plugins/filter-graph/audio-dsp.h
@@ -43,11 +43,11 @@ struct spa_fga_dsp_methods {
const float * SPA_RESTRICT src, float * SPA_RESTRICT dst);
void (*fft_cmul) (void *obj, void *fft,
float * SPA_RESTRICT dst, const float * SPA_RESTRICT a,
- const float * SPA_RESTRICT b, uint32_t len);
+ const float * SPA_RESTRICT b, uint32_t len, const float scale);
void (*fft_cmuladd) (void *obj, void *fft,
float * dst, const float * src,
const float * SPA_RESTRICT a, const float * SPA_RESTRICT b,
- uint32_t len);
+ uint32_t len, const float scale);
void (*linear) (void *obj,
float * dst, const float * SPA_RESTRICT src,
const float mult, const float add, uint32_t n_samples);
@@ -123,18 +123,18 @@ static inline void spa_fga_dsp_fft_run(struct spa_fga_dsp *obj, void *fft, int d
}
static inline void spa_fga_dsp_fft_cmul(struct spa_fga_dsp *obj, void *fft,
float * SPA_RESTRICT dst, const float * SPA_RESTRICT a,
- const float * SPA_RESTRICT b, uint32_t len)
+ const float * SPA_RESTRICT b, uint32_t len, const float scale)
{
spa_api_method_v(spa_fga_dsp, &obj->iface, fft_cmul, 0,
- fft, dst, a, b, len);
+ fft, dst, a, b, len, scale);
}
static inline void spa_fga_dsp_fft_cmuladd(struct spa_fga_dsp *obj, void *fft,
float * dst, const float * src,
const float * SPA_RESTRICT a, const float * SPA_RESTRICT b,
- uint32_t len)
+ uint32_t len, const float scale)
{
spa_api_method_v(spa_fga_dsp, &obj->iface, fft_cmuladd, 0,
- fft, dst, src, a, b, len);
+ fft, dst, src, a, b, len, scale);
}
static inline void spa_fga_dsp_linear(struct spa_fga_dsp *obj,
float * dst, const float * SPA_RESTRICT src,
diff --git a/spa/plugins/filter-graph/audio-plugin.h b/spa/plugins/filter-graph/audio-plugin.h
index fffdc0de5..9f9d1bce6 100644
--- a/spa/plugins/filter-graph/audio-plugin.h
+++ b/spa/plugins/filter-graph/audio-plugin.h
@@ -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);
diff --git a/spa/plugins/filter-graph/convolver.c b/spa/plugins/filter-graph/convolver.c
index 18c70db2a..a077c6ec1 100644
--- a/spa/plugins/filter-graph/convolver.c
+++ b/spa/plugins/filter-graph/convolver.c
@@ -6,57 +6,32 @@
#include "convolver.h"
-#include
-#include
-#include
-#include
-
#include
-struct ir {
+#include
+
+struct convolver1 {
+ int blockSize;
+ int segSize;
+ int segCount;
+ int fftComplexSize;
+
float **segments;
- float *time_buffer[2];
- float *precalc[2];
-};
+ float **segmentsIr;
-struct partition {
- struct convolver *conv;
+ float *fft_buffer[2];
- int block_size;
- int time_size;
- int freq_size;
void *fft;
- float *freq;
+ void *ifft;
+
+ float *pre_mult;
+ float *conv;
+
+ float *inputBuffer;
+ int inputBufferFill;
- int n_segments;
int current;
- float **segments;
-
- int block_fill;
- int n_ir;
- struct ir *ir;
- int time_idx;
- int precalc_idx;
-};
-
-struct convolver
-{
- struct spa_fga_dsp *dsp;
-
- int min_size;
- int max_size;
-
- float *delay[2];
- int delay_fill;
-
- struct partition *partition[16];
- int n_partition;
-
- bool threaded;
- bool running;
- pthread_t thread;
- sem_t sem_start;
- sem_t sem_finish;
+ float scale;
};
static int next_power_of_two(int val)
@@ -67,218 +42,226 @@ static int next_power_of_two(int val)
return r;
}
-static void partition_reset(struct spa_fga_dsp *dsp, struct partition *part)
+static void convolver1_reset(struct spa_fga_dsp *dsp, struct convolver1 *conv)
{
int i;
- for (i = 0; i < part->n_segments; i++)
- spa_fga_dsp_fft_memclear(dsp, part->segments[i], part->freq_size, false);
- for (i = 0; i < part->n_ir; i++) {
- struct ir *r = &part->ir[i];
- spa_fga_dsp_fft_memclear(dsp, r->time_buffer[0], part->time_size, true);
- spa_fga_dsp_fft_memclear(dsp, r->time_buffer[1], part->time_size, true);
- spa_fga_dsp_fft_memclear(dsp, r->precalc[0], part->block_size, true);
- spa_fga_dsp_fft_memclear(dsp, r->precalc[1], part->block_size, true);
- }
- spa_fga_dsp_fft_memclear(dsp, part->freq, part->freq_size, false);
- part->block_fill = 0;
- part->time_idx = 0;
- part->precalc_idx = 0;
- part->current = 0;
+ for (i = 0; i < conv->segCount; i++)
+ spa_fga_dsp_fft_memclear(dsp, conv->segments[i], conv->fftComplexSize, false);
+ spa_fga_dsp_fft_memclear(dsp, conv->fft_buffer[0], conv->segSize, true);
+ spa_fga_dsp_fft_memclear(dsp, conv->fft_buffer[1], conv->segSize, true);
+ spa_fga_dsp_fft_memclear(dsp, conv->inputBuffer, conv->segSize, true);
+ spa_fga_dsp_fft_memclear(dsp, conv->pre_mult, conv->fftComplexSize, false);
+ spa_fga_dsp_fft_memclear(dsp, conv->conv, conv->fftComplexSize, false);
+ conv->inputBufferFill = 0;
+ conv->current = 0;
}
-static void partition_free(struct spa_fga_dsp *dsp, struct partition *part)
+static void convolver1_free(struct spa_fga_dsp *dsp, struct convolver1 *conv)
{
- int i, j;
- for (i = 0; i < part->n_segments; i++) {
- if (part->segments)
- spa_fga_dsp_fft_memfree(dsp, part->segments[i]);
+ int i;
+ for (i = 0; i < conv->segCount; i++) {
+ if (conv->segments)
+ spa_fga_dsp_fft_memfree(dsp, conv->segments[i]);
+ if (conv->segmentsIr)
+ spa_fga_dsp_fft_memfree(dsp, conv->segmentsIr[i]);
}
- for (i = 0; i < part->n_ir; i++) {
- struct ir *r = &part->ir[i];
- for (j = 0; j < part->n_segments; j++) {
- if (r->segments)
- spa_fga_dsp_fft_memfree(dsp, r->segments[j]);
- }
- if (r->time_buffer[0])
- spa_fga_dsp_fft_memfree(dsp, r->time_buffer[0]);
- if (r->time_buffer[1])
- spa_fga_dsp_fft_memfree(dsp, r->time_buffer[1]);
- if (r->precalc[0])
- spa_fga_dsp_fft_memfree(dsp, r->precalc[0]);
- if (r->precalc[1])
- spa_fga_dsp_fft_memfree(dsp, r->precalc[1]);
- free(r->segments);
- }
- if (part->fft)
- spa_fga_dsp_fft_free(dsp, part->fft);
- free(part->segments);
- free(part->ir);
- spa_fga_dsp_fft_memfree(dsp, part->freq);
- free(part);
+ if (conv->fft)
+ spa_fga_dsp_fft_free(dsp, conv->fft);
+ if (conv->ifft)
+ spa_fga_dsp_fft_free(dsp, conv->ifft);
+ if (conv->fft_buffer[0])
+ spa_fga_dsp_fft_memfree(dsp, conv->fft_buffer[0]);
+ if (conv->fft_buffer[1])
+ spa_fga_dsp_fft_memfree(dsp, conv->fft_buffer[1]);
+ free(conv->segments);
+ free(conv->segmentsIr);
+ spa_fga_dsp_fft_memfree(dsp, conv->pre_mult);
+ spa_fga_dsp_fft_memfree(dsp, conv->conv);
+ spa_fga_dsp_fft_memfree(dsp, conv->inputBuffer);
+ free(conv);
}
-static struct partition *partition_new(struct convolver *conv, int block,
- const struct convolver_ir ir[], int n_ir, int iroffset, int irlen)
+static struct convolver1 *convolver1_new(struct spa_fga_dsp *dsp, int block, const float *ir, int irlen)
{
- struct partition *part;
- struct spa_fga_dsp *dsp = conv->dsp;
- int i, j;
+ struct convolver1 *conv;
+ int i;
if (block == 0)
return NULL;
- part = calloc(1, sizeof(*part));
- if (part == NULL)
+ while (irlen > 0 && fabs(ir[irlen-1]) < 0.000001f)
+ irlen--;
+
+ conv = calloc(1, sizeof(*conv));
+ if (conv == NULL)
return NULL;
- part->conv = conv;
+ if (irlen == 0)
+ return conv;
- part->block_size = next_power_of_two(block);
- part->time_size = 2 * part->block_size;
- part->n_segments = (irlen + part->block_size-1) / part->block_size;
- part->freq_size = (part->time_size / 2) + 1;
- part->n_ir = n_ir;
+ conv->blockSize = next_power_of_two(block);
+ conv->segSize = 2 * conv->blockSize;
+ conv->segCount = (irlen + conv->blockSize-1) / conv->blockSize;
+ conv->fftComplexSize = (conv->segSize / 2) + 1;
- part->fft = spa_fga_dsp_fft_new(dsp, part->time_size, true);
- if (part->fft == NULL)
+ conv->fft = spa_fga_dsp_fft_new(dsp, conv->segSize, true);
+ if (conv->fft == NULL)
+ goto error;
+ conv->ifft = spa_fga_dsp_fft_new(dsp, conv->segSize, true);
+ if (conv->ifft == NULL)
goto error;
- part->segments = calloc(part->n_segments, sizeof(float*));
- part->freq = spa_fga_dsp_fft_memalloc(dsp, part->freq_size, false);
- part->ir = calloc(part->n_ir, sizeof(struct ir));
- if (part->segments == NULL || part->freq == NULL || part->ir == NULL)
+ conv->fft_buffer[0] = spa_fga_dsp_fft_memalloc(dsp, conv->segSize, true);
+ conv->fft_buffer[1] = spa_fga_dsp_fft_memalloc(dsp, conv->segSize, true);
+ if (conv->fft_buffer[0] == NULL || conv->fft_buffer[1] == NULL)
goto error;
- for (i = 0; i < part->n_segments; i++) {
- part->segments[i] = spa_fga_dsp_fft_memalloc(dsp, part->freq_size, false);
- if (part->segments[i] == NULL)
- goto error;
- }
+ conv->segments = calloc(conv->segCount, sizeof(float*));
+ conv->segmentsIr = calloc(conv->segCount, sizeof(float*));
+ if (conv->segments == NULL || conv->segmentsIr == NULL)
+ goto error;
- for (i = 0; i < part->n_ir; i++) {
- struct ir *r = &part->ir[i];
+ for (i = 0; i < conv->segCount; i++) {
+ int left = irlen - (i * conv->blockSize);
+ int copy = SPA_MIN(conv->blockSize, left);
- r->segments = calloc(part->n_segments, sizeof(float*));
- r->time_buffer[0] = spa_fga_dsp_fft_memalloc(dsp, part->time_size, true);
- r->time_buffer[1] = spa_fga_dsp_fft_memalloc(dsp, part->time_size, true);
- r->precalc[0] = spa_fga_dsp_fft_memalloc(dsp, part->block_size, true);
- r->precalc[1] = spa_fga_dsp_fft_memalloc(dsp, part->block_size, true);
- if (r->segments == NULL || r->time_buffer[0] == NULL || r->time_buffer[1] == NULL ||
- r->precalc[0] == NULL || r->precalc[1] == NULL)
+ conv->segments[i] = spa_fga_dsp_fft_memalloc(dsp, conv->fftComplexSize, false);
+ conv->segmentsIr[i] = spa_fga_dsp_fft_memalloc(dsp, conv->fftComplexSize, false);
+ if (conv->segments[i] == NULL || conv->segmentsIr[i] == NULL)
goto error;
- for (j = 0; j < part->n_segments; j++) {
- int left = ir[i].len - iroffset - (j * part->block_size);
- int copy = SPA_CLAMP(left, 0, part->block_size);
+ spa_fga_dsp_copy(dsp, conv->fft_buffer[0], &ir[i * conv->blockSize], copy);
+ if (copy < conv->segSize)
+ spa_fga_dsp_fft_memclear(dsp, conv->fft_buffer[0] + copy, conv->segSize - copy, true);
- r->segments[j] = spa_fga_dsp_fft_memalloc(dsp, part->freq_size, false);
- if (r->segments[j] == NULL)
- goto error;
-
- spa_fga_dsp_copy(dsp, r->time_buffer[0], &ir[i].ir[iroffset + (j * part->block_size)], copy);
- spa_fga_dsp_fft_memclear(dsp, r->time_buffer[0] + copy, part->time_size - copy, true);
-
- spa_fga_dsp_fft_run(dsp, part->fft, 1, r->time_buffer[0], r->segments[j]);
- }
+ spa_fga_dsp_fft_run(dsp, conv->fft, 1, conv->fft_buffer[0], conv->segmentsIr[i]);
}
- partition_reset(dsp, part);
+ conv->pre_mult = spa_fga_dsp_fft_memalloc(dsp, conv->fftComplexSize, false);
+ conv->conv = spa_fga_dsp_fft_memalloc(dsp, conv->fftComplexSize, false);
+ conv->inputBuffer = spa_fga_dsp_fft_memalloc(dsp, conv->segSize, true);
+ if (conv->pre_mult == NULL || conv->conv == NULL || conv->inputBuffer == NULL)
+ goto error;
+ conv->scale = 1.0f / conv->segSize;
+ convolver1_reset(dsp, conv);
- return part;
+ return conv;
error:
- partition_free(dsp, part);
+ convolver1_free(dsp, conv);
return NULL;
}
-static int partition_run(struct spa_fga_dsp *dsp, struct partition *part, const float *input,
- float *output[], int offset, int len)
+static int convolver1_run(struct spa_fga_dsp *dsp, struct convolver1 *conv, const float *input, float *output, int len)
{
- int i, j;
- int block_fill = part->block_fill;
- int idx = part->time_idx, pc_idx = part->precalc_idx;
- float *dst;
+ int i, processed = 0;
- spa_fga_dsp_fft_run(dsp, part->fft, 1, input, part->segments[part->current]);
+ if (conv == NULL || conv->segCount == 0) {
+ spa_fga_dsp_fft_memclear(dsp, output, len, true);
+ return len;
+ }
- for (i = 0; i < part->n_ir; i++) {
- struct ir *r = &part->ir[i];
- int current = part->current;
+ int inputBufferFill = conv->inputBufferFill;
+ while (processed < len) {
+ const int processing = SPA_MIN(len - processed, conv->blockSize - inputBufferFill);
- spa_fga_dsp_fft_cmul(dsp, part->fft,
- part->freq,
- part->segments[current],
- r->segments[0],
- part->freq_size);
+ spa_fga_dsp_copy(dsp, conv->inputBuffer + inputBufferFill, input + processed, processing);
+ if (inputBufferFill == 0 && processing < conv->blockSize)
+ spa_fga_dsp_fft_memclear(dsp, conv->inputBuffer + processing,
+ conv->blockSize - processing, true);
+ spa_fga_dsp_fft_run(dsp, conv->fft, 1, conv->inputBuffer, conv->segments[conv->current]);
- for (j = 1; j < part->n_segments; j++) {
- if (++current == part->n_segments)
- current = 0;
+ if (conv->segCount > 1) {
+ if (inputBufferFill == 0) {
+ int indexAudio = (conv->current + 1) % conv->segCount;
- spa_fga_dsp_fft_cmuladd(dsp, part->fft,
- part->freq,
- part->freq,
- part->segments[current],
- r->segments[j],
- part->freq_size);
+ spa_fga_dsp_fft_cmul(dsp, conv->fft, conv->pre_mult,
+ conv->segmentsIr[1],
+ conv->segments[indexAudio],
+ conv->fftComplexSize, conv->scale);
+
+ for (i = 2; i < conv->segCount; i++) {
+ indexAudio = (conv->current + i) % conv->segCount;
+
+ spa_fga_dsp_fft_cmuladd(dsp, conv->fft,
+ conv->pre_mult,
+ conv->pre_mult,
+ conv->segmentsIr[i],
+ conv->segments[indexAudio],
+ conv->fftComplexSize, conv->scale);
+ }
+ }
+ spa_fga_dsp_fft_cmuladd(dsp, conv->fft,
+ conv->conv,
+ conv->pre_mult,
+ conv->segments[conv->current],
+ conv->segmentsIr[0],
+ conv->fftComplexSize, conv->scale);
+ } else {
+ spa_fga_dsp_fft_cmul(dsp, conv->fft,
+ conv->conv,
+ conv->segments[conv->current],
+ conv->segmentsIr[0],
+ conv->fftComplexSize, conv->scale);
}
- spa_fga_dsp_fft_run(dsp, part->fft, -1, part->freq, r->time_buffer[idx]);
- dst = output ? output[i]: r->precalc[pc_idx];
- if (dst)
- spa_fga_dsp_sum(dsp, dst + offset, r->time_buffer[idx] + block_fill,
- r->time_buffer[idx^1] + part->block_size + block_fill, len);
+ spa_fga_dsp_fft_run(dsp, conv->ifft, -1, conv->conv, conv->fft_buffer[0]);
+
+ spa_fga_dsp_sum(dsp, output + processed, conv->fft_buffer[0] + inputBufferFill,
+ conv->fft_buffer[1] + conv->blockSize + inputBufferFill, processing);
+
+ inputBufferFill += processing;
+ if (inputBufferFill == conv->blockSize) {
+ inputBufferFill = 0;
+
+ SPA_SWAP(conv->fft_buffer[0], conv->fft_buffer[1]);
+
+ conv->current = (conv->current > 0) ? (conv->current - 1) : (conv->segCount - 1);
+ }
+
+ processed += processing;
}
-
- block_fill += len;
- if (block_fill == part->block_size) {
- block_fill = 0;
-
- part->time_idx = idx ^ 1;
-
- if (part->current == 0)
- part->current = part->n_segments;
- part->current--;
- }
- part->block_fill = block_fill;
+ conv->inputBufferFill = inputBufferFill;
return len;
}
-static void *do_background_process(void *data)
+struct convolver
{
- struct partition *part = data;
- struct convolver *conv = part->conv;
-
- while (conv->running) {
- sem_wait(&conv->sem_start);
-
- if (!conv->running)
- break;
-
- partition_run(conv->dsp, part, conv->delay[1], NULL, 0, part->block_size);
-
- sem_post(&conv->sem_finish);
- }
- return NULL;
-}
+ struct spa_fga_dsp *dsp;
+ int headBlockSize;
+ int tailBlockSize;
+ struct convolver1 *headConvolver;
+ struct convolver1 *tailConvolver0;
+ float *tailOutput0;
+ float *tailPrecalculated0;
+ struct convolver1 *tailConvolver;
+ float *tailOutput;
+ float *tailPrecalculated;
+ float *tailInput;
+ int tailInputFill;
+};
void convolver_reset(struct convolver *conv)
{
struct spa_fga_dsp *dsp = conv->dsp;
- int i;
- for (i = 0; i < conv->n_partition; i++)
- partition_reset(dsp, conv->partition[i]);
-
- spa_fga_dsp_fft_memclear(dsp, conv->delay[0], 2 * conv->max_size, true);
- spa_fga_dsp_fft_memclear(dsp, conv->delay[1], 2 * conv->max_size, true);
- conv->delay_fill = 0;
+ if (conv->headConvolver)
+ convolver1_reset(dsp, conv->headConvolver);
+ if (conv->tailConvolver0) {
+ convolver1_reset(dsp, conv->tailConvolver0);
+ spa_fga_dsp_fft_memclear(dsp, conv->tailOutput0, conv->tailBlockSize, true);
+ spa_fga_dsp_fft_memclear(dsp, conv->tailPrecalculated0, conv->tailBlockSize, true);
+ }
+ if (conv->tailConvolver) {
+ convolver1_reset(dsp, conv->tailConvolver);
+ spa_fga_dsp_fft_memclear(dsp, conv->tailOutput, conv->tailBlockSize, true);
+ spa_fga_dsp_fft_memclear(dsp, conv->tailPrecalculated, conv->tailBlockSize, true);
+ }
+ conv->tailInputFill = 0;
}
-struct convolver *convolver_new_many(struct spa_fga_dsp *dsp, int head_block, int tail_block,
- const struct convolver_ir ir[], int n_ir)
+struct convolver *convolver_new(struct spa_fga_dsp *dsp, int head_block, int tail_block, const float *ir, int irlen)
{
struct convolver *conv;
- int i, irlen, head_ir_len, min_size, max_size, ir_consumed = 0;
- struct convolver_ir tmp[n_ir];
+ int head_ir_len;
if (head_block == 0 || tail_block == 0)
return NULL;
@@ -287,153 +270,124 @@ struct convolver *convolver_new_many(struct spa_fga_dsp *dsp, int head_block, in
if (head_block > tail_block)
SPA_SWAP(head_block, tail_block);
+ while (irlen > 0 && fabs(ir[irlen-1]) < 0.000001f)
+ irlen--;
+
conv = calloc(1, sizeof(*conv));
if (conv == NULL)
return NULL;
- irlen = 0;
- for (i = 0; i < n_ir; i++) {
- int l = ir[i].len;
- while (l > 0 && fabs(ir[i].ir[l-1]) < 0.000001f)
- l--;
- tmp[i].ir = ir[i].ir;
- tmp[i].len = l;
- irlen = SPA_MAX(irlen, l);
- }
-
conv->dsp = dsp;
- conv->min_size = next_power_of_two(head_block);
- conv->max_size = next_power_of_two(tail_block);
-
- conv->delay[0] = spa_fga_dsp_fft_memalloc(dsp, 2 * conv->max_size, true);
- conv->delay[1] = spa_fga_dsp_fft_memalloc(dsp, 2 * conv->max_size, true);
- if (conv->delay[0] == NULL || conv->delay[1] == NULL)
- goto error;
if (irlen == 0)
return conv;
- min_size = conv->min_size;
- max_size = conv->max_size;
+ conv->headBlockSize = next_power_of_two(head_block);
+ conv->tailBlockSize = next_power_of_two(tail_block);
- while (ir_consumed < irlen) {
- head_ir_len = SPA_MIN(irlen - ir_consumed, 2 * max_size);
+ head_ir_len = SPA_MIN(irlen, conv->tailBlockSize);
+ conv->headConvolver = convolver1_new(dsp, conv->headBlockSize, ir, head_ir_len);
+ if (conv->headConvolver == NULL)
+ goto error;
- conv->partition[conv->n_partition] = partition_new(conv, min_size,
- tmp, n_ir, ir_consumed, head_ir_len);
- if (conv->partition[conv->n_partition] == NULL)
+ if (irlen > conv->tailBlockSize) {
+ int conv1IrLen = SPA_MIN(irlen - conv->tailBlockSize, conv->tailBlockSize);
+ conv->tailConvolver0 = convolver1_new(dsp, conv->headBlockSize, ir + conv->tailBlockSize, conv1IrLen);
+ conv->tailOutput0 = spa_fga_dsp_fft_memalloc(dsp, conv->tailBlockSize, true);
+ conv->tailPrecalculated0 = spa_fga_dsp_fft_memalloc(dsp, conv->tailBlockSize, true);
+ if (conv->tailConvolver0 == NULL || conv->tailOutput0 == NULL ||
+ conv->tailPrecalculated0 == NULL)
goto error;
- conv->n_partition++;
+ }
- ir_consumed += head_ir_len;
- min_size = max_size;
- max_size = min_size * 2;
- if (max_size > conv->max_size)
- max_size = irlen;
+ if (irlen > 2 * conv->tailBlockSize) {
+ int tailIrLen = irlen - (2 * conv->tailBlockSize);
+ conv->tailConvolver = convolver1_new(dsp, conv->tailBlockSize, ir + (2 * conv->tailBlockSize), tailIrLen);
+ conv->tailOutput = spa_fga_dsp_fft_memalloc(dsp, conv->tailBlockSize, true);
+ conv->tailPrecalculated = spa_fga_dsp_fft_memalloc(dsp, conv->tailBlockSize, true);
+ if (conv->tailConvolver == NULL || conv->tailOutput == NULL ||
+ conv->tailPrecalculated == NULL)
+ goto error;
+ }
+
+ if (conv->tailConvolver0 || conv->tailConvolver) {
+ conv->tailInput = spa_fga_dsp_fft_memalloc(dsp, conv->tailBlockSize, true);
+ if (conv->tailInput == NULL)
+ goto error;
}
convolver_reset(conv);
- conv->threaded = false;
-
- if (conv->threaded) {
- int res;
-
- sem_init(&conv->sem_start, 0, 1);
- sem_init(&conv->sem_finish, 0, 0);
- conv->running = true;
-
- res = pthread_create(&conv->thread, NULL,
- do_background_process, conv);
- if (res != 0) {
- conv->threaded = false;
- sem_destroy(&conv->sem_start);
- sem_destroy(&conv->sem_finish);
- }
- }
return conv;
error:
convolver_free(conv);
return NULL;
}
-struct convolver *convolver_new(struct spa_fga_dsp *dsp, int head_block, int tail_block, const float *ir, int irlen)
-{
- const struct convolver_ir tmp = { ir, irlen };
- return convolver_new_many(dsp, head_block, tail_block, &tmp, 1);
-}
-
void convolver_free(struct convolver *conv)
{
struct spa_fga_dsp *dsp = conv->dsp;
- int i;
- if (conv->threaded) {
- conv->running = false;
- sem_post(&conv->sem_start);
- pthread_join(conv->thread, NULL);
- sem_destroy(&conv->sem_start);
- sem_destroy(&conv->sem_finish);
- }
- for (i = 0; i < conv->n_partition; i++)
- partition_free(dsp, conv->partition[i]);
-
- spa_fga_dsp_fft_memfree(dsp, conv->delay[0]);
- spa_fga_dsp_fft_memfree(dsp, conv->delay[1]);
+ if (conv->headConvolver)
+ convolver1_free(dsp, conv->headConvolver);
+ if (conv->tailConvolver0)
+ convolver1_free(dsp, conv->tailConvolver0);
+ if (conv->tailConvolver)
+ convolver1_free(dsp, conv->tailConvolver);
+ spa_fga_dsp_fft_memfree(dsp, conv->tailOutput0);
+ spa_fga_dsp_fft_memfree(dsp, conv->tailPrecalculated0);
+ spa_fga_dsp_fft_memfree(dsp, conv->tailOutput);
+ spa_fga_dsp_fft_memfree(dsp, conv->tailPrecalculated);
+ spa_fga_dsp_fft_memfree(dsp, conv->tailInput);
free(conv);
}
-int convolver_run_many(struct convolver *conv, const float *input, float *output[], int length)
-{
- int processed = 0, i, j;
- struct spa_fga_dsp *dsp = conv->dsp;
-
- if (conv->n_partition == 0)
- return length;
-
- while (processed < length) {
- int remaining = length - processed, pc_idx;
- float *delay = conv->delay[0];
- int delay_fill = conv->delay_fill;
- struct partition *part = conv->partition[0];
- int block_size = part->block_size;
- int block_fill = delay_fill % block_size;
- int processing = SPA_MIN(remaining, block_size - block_fill);
-
- spa_memcpy(delay + delay_fill, input + processed, processing * sizeof(float));
- conv->delay_fill += processing;
-
- partition_run(dsp, part, delay + delay_fill - block_fill, output, processed, processing);
-
- for (i = 1; i < conv->n_partition; i++) {
- part = conv->partition[i];
- pc_idx = part->precalc_idx;
- block_size = part->block_size;
- block_fill = delay_fill % block_size;
-
- for (j = 0; j < part->n_ir; j++) {
- struct ir *r = &part->ir[j];
- spa_fga_dsp_sum(dsp, &output[j][processed], &output[j][processed],
- &r->precalc[pc_idx][block_fill], processing);
- }
- if (block_fill + processing == block_size) {
- part->precalc_idx = pc_idx ^ 1;
- partition_run(dsp, part, delay + conv->delay_fill - block_size,
- NULL, 0, block_size);
- }
- }
- if (conv->delay_fill == conv->max_size) {
- SPA_SWAP(conv->delay[0], conv->delay[1]);
- memset(conv->delay[0], 0, conv->max_size * sizeof(float));
- conv->delay_fill = 0;
- }
- processed += processing;
- }
- return processed;
-}
-
int convolver_run(struct convolver *conv, const float *input, float *output, int length)
{
- float *tmp[1] = { output };
- return convolver_run_many(conv, input, tmp, length);
+ struct spa_fga_dsp *dsp = conv->dsp;
+
+ convolver1_run(dsp, conv->headConvolver, input, output, length);
+
+ if (conv->tailInput) {
+ int processed = 0;
+
+ while (processed < length) {
+ int remaining = length - processed;
+ int processing = SPA_MIN(remaining, conv->headBlockSize - (conv->tailInputFill % conv->headBlockSize));
+
+ if (conv->tailPrecalculated0)
+ spa_fga_dsp_sum(dsp, &output[processed], &output[processed],
+ &conv->tailPrecalculated0[conv->tailInputFill],
+ processing);
+ if (conv->tailPrecalculated)
+ spa_fga_dsp_sum(dsp, &output[processed], &output[processed],
+ &conv->tailPrecalculated[conv->tailInputFill],
+ processing);
+
+ spa_fga_dsp_copy(dsp, conv->tailInput + conv->tailInputFill, input + processed, processing);
+ conv->tailInputFill += processing;
+
+ if (conv->tailPrecalculated0 && (conv->tailInputFill % conv->headBlockSize == 0)) {
+ int blockOffset = conv->tailInputFill - conv->headBlockSize;
+ convolver1_run(dsp, conv->tailConvolver0,
+ conv->tailInput + blockOffset,
+ conv->tailOutput0 + blockOffset,
+ conv->headBlockSize);
+ if (conv->tailInputFill == conv->tailBlockSize)
+ SPA_SWAP(conv->tailPrecalculated0, conv->tailOutput0);
+ }
+
+ if (conv->tailPrecalculated &&
+ conv->tailInputFill == conv->tailBlockSize) {
+ SPA_SWAP(conv->tailPrecalculated, conv->tailOutput);
+ convolver1_run(dsp, conv->tailConvolver, conv->tailInput,
+ conv->tailOutput, conv->tailBlockSize);
+ }
+ if (conv->tailInputFill == conv->tailBlockSize)
+ conv->tailInputFill = 0;
+
+ processed += processing;
+ }
+ }
+ return 0;
}
diff --git a/spa/plugins/filter-graph/convolver.h b/spa/plugins/filter-graph/convolver.h
index 45bc50fde..ad6139a35 100644
--- a/spa/plugins/filter-graph/convolver.h
+++ b/spa/plugins/filter-graph/convolver.h
@@ -7,18 +7,8 @@
#include "audio-dsp.h"
-struct convolver_ir {
- const float *ir;
- int len;
-};
-
struct convolver *convolver_new(struct spa_fga_dsp *dsp, int block, int tail, const float *ir, int irlen);
void convolver_free(struct convolver *conv);
void convolver_reset(struct convolver *conv);
int convolver_run(struct convolver *conv, const float *input, float *output, int length);
-
-
-struct convolver *convolver_new_many(struct spa_fga_dsp *dsp, int block, int tail,
- const struct convolver_ir *ir, int n_ir);
-int convolver_run_many(struct convolver *conv, const float *input, float **output, int length);
diff --git a/spa/plugins/filter-graph/filter-graph.c b/spa/plugins/filter-graph/filter-graph.c
index 4b47d0c9f..05ba7b3fb 100644
--- a/spa/plugins/filter-graph/filter-graph.c
+++ b/spa/plugins/filter-graph/filter-graph.c
@@ -19,7 +19,6 @@
#include
#include
#include
-#include
#include
#include
#include
@@ -222,7 +221,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;
@@ -554,25 +552,19 @@ static int impl_get_props(void *object, struct spa_pod_builder *b, struct spa_po
struct descriptor *desc = node->desc;
const struct spa_fga_descriptor *d = desc->desc;
struct spa_fga_port *p = &d->ports[port->p];
- float v, min, max;
if (node->name[0] != '\0')
snprintf(name, sizeof(name), "%s:%s", node->name, p->name);
else
snprintf(name, sizeof(name), "%s", p->name);
- if (port->control_initialized)
- v = port->control_current;
- else
- get_ranges(impl, p, &v, &min, &max);
-
spa_pod_builder_string(b, name);
if (p->hint & SPA_FGA_HINT_BOOLEAN) {
- spa_pod_builder_bool(b, v <= 0.0f ? false : true);
+ spa_pod_builder_bool(b, port->control_data[0] <= 0.0f ? false : true);
} else if (p->hint & SPA_FGA_HINT_INTEGER) {
- spa_pod_builder_int(b, (int32_t)v);
+ spa_pod_builder_int(b, (int32_t)port->control_data[0]);
} else {
- spa_pod_builder_float(b, v);
+ spa_pod_builder_float(b, port->control_data[0]);
}
}
spa_pod_builder_pop(b, &f[1]);
@@ -706,46 +698,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;
+ const struct spa_fga_descriptor *d = node->desc->desc;
uint32_t i;
- spa_loop_locked(impl->data_loop, do_emit_node_control_sync, 1, NULL, 0, impl);
+ if (!node->control_changed)
+ return;
- spa_list_for_each(node, &graph->node_list, link) {
- const struct spa_fga_descriptor *d = node->desc->desc;
- if (!node->control_changed)
+ for (i = 0; i < node->n_hndl; i++) {
+ if (node->hndl[i] == NULL)
continue;
- if (d->control_changed != NULL) {
- for (i = 0; i < node->n_hndl; i++) {
- if (node->hndl[i] != NULL)
- d->control_changed(node->hndl[i]);
- }
- }
- node->control_changed = false;
+ if (d->control_changed)
+ d->control_changed(node->hndl[i]);
}
+ node->control_changed = false;
}
static int sync_volume(struct graph *graph, struct volume *vol)
@@ -859,7 +826,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;
@@ -1725,10 +1696,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) {
@@ -2376,7 +2347,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);
diff --git a/spa/plugins/filter-graph/meson.build b/spa/plugins/filter-graph/meson.build
index 20b90f4c4..94ee0bd25 100644
--- a/spa/plugins/filter-graph/meson.build
+++ b/spa/plugins/filter-graph/meson.build
@@ -18,16 +18,16 @@ if have_sse
simd_cargs += ['-DHAVE_SSE']
simd_dependencies += filter_graph_sse
endif
-if have_avx2 and have_fma
- filter_graph_avx2_fma = static_library('filter_graph_avx2_fma',
+if have_avx2
+ filter_graph_avx2 = static_library('filter_graph_avx2',
['audio-dsp-avx2.c' ],
include_directories : [configinc],
- c_args : [avx2_args, fma_args, '-O3', '-DHAVE_AVX2', '-DHAVE_FMA'],
+ c_args : [avx2_args, fma_args,'-O3', '-DHAVE_AVX2'],
dependencies : [ spa_dep ],
install : false
)
- simd_cargs += ['-DHAVE_AVX2', '-DHAVE_FMA']
- simd_dependencies += filter_graph_avx2_fma
+ simd_cargs += ['-DHAVE_AVX2']
+ simd_dependencies += filter_graph_avx2
endif
if have_neon
filter_graph_neon = static_library('filter_graph_neon',
diff --git a/spa/plugins/filter-graph/pffft.c b/spa/plugins/filter-graph/pffft.c
index 1a50d09e7..6ec105c02 100644
--- a/spa/plugins/filter-graph/pffft.c
+++ b/spa/plugins/filter-graph/pffft.c
@@ -1419,8 +1419,6 @@ static PFFFT_Setup *new_setup_simd(int N, pffft_transform_t transform)
/* unfortunately, the fft size must be a multiple of 16 for complex FFTs
and 32 for real FFTs -- a lot of stuff would need to be rewritten to
handle other cases (or maybe just switch to a scalar fft, I don't know..) */
- if (s == NULL)
- return NULL;
if (transform == PFFFT_REAL) {
assert((N % (2 * SIMD_SZ * SIMD_SZ)) == 0 && N > 0);
}
@@ -1433,10 +1431,6 @@ static PFFFT_Setup *new_setup_simd(int N, pffft_transform_t transform)
/* nb of complex simd vectors */
s->Ncvec = (transform == PFFFT_REAL ? N / 2 : N) / SIMD_SZ;
s->data = (v4sf *) pffft_aligned_malloc(2 * s->Ncvec * sizeof(v4sf));
- if (s->data == NULL) {
- free(s);
- return NULL;
- }
s->e = (float *)s->data;
s->twiddle =
(float *)(s->data + (2 * s->Ncvec * (SIMD_SZ - 1)) / SIMD_SZ);
diff --git a/spa/plugins/filter-graph/plugin_builtin.c b/spa/plugins/filter-graph/plugin_builtin.c
index 628c7aec5..3bcde30c9 100644
--- a/spa/plugins/filter-graph/plugin_builtin.c
+++ b/spa/plugins/filter-graph/plugin_builtin.c
@@ -21,7 +21,6 @@
#include
#include
#include
-#include
#include
#include
@@ -202,42 +201,42 @@ static struct spa_fga_port mixer_ports[] = {
{ .index = 9,
.name = "Gain 1",
.flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL,
- .def = 1.0f, .min = -10.0f, .max = 10.0f
+ .def = 1.0f, .min = 0.0f, .max = 10.0f
},
{ .index = 10,
.name = "Gain 2",
.flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL,
- .def = 1.0f, .min = -10.0f, .max = 10.0f
+ .def = 1.0f, .min = 0.0f, .max = 10.0f
},
{ .index = 11,
.name = "Gain 3",
.flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL,
- .def = 1.0f, .min = -10.0f, .max = 10.0f
+ .def = 1.0f, .min = 0.0f, .max = 10.0f
},
{ .index = 12,
.name = "Gain 4",
.flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL,
- .def = 1.0f, .min = -10.0f, .max = 10.0f
+ .def = 1.0f, .min = 0.0f, .max = 10.0f
},
{ .index = 13,
.name = "Gain 5",
.flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL,
- .def = 1.0f, .min = -10.0f, .max = 10.0f
+ .def = 1.0f, .min = 0.0f, .max = 10.0f
},
{ .index = 14,
.name = "Gain 6",
.flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL,
- .def = 1.0f, .min = -10.0f, .max = 10.0f
+ .def = 1.0f, .min = 0.0f, .max = 10.0f
},
{ .index = 15,
.name = "Gain 7",
.flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL,
- .def = 1.0f, .min = -10.0f, .max = 10.0f
+ .def = 1.0f, .min = 0.0f, .max = 10.0f
},
{ .index = 16,
.name = "Gain 8",
.flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL,
- .def = 1.0f, .min = -10.0f, .max = 10.0f
+ .def = 1.0f, .min = 0.0f, .max = 10.0f
},
};
@@ -543,12 +542,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 +562,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 +574,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 +588,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 +602,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 +616,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 +630,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 +644,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 +658,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 +673,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,20 +687,19 @@ 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,
};
-/** convolver */
+/** convolve */
struct convolver_impl {
struct plugin *plugin;
struct spa_log *log;
struct spa_fga_dsp *dsp;
unsigned long rate;
- float *port[10];
+ float *port[3];
float latency;
struct convolver *conv;
@@ -796,76 +782,51 @@ static int finfo_open(const char *filename, struct finfo *info, int rate)
return 0;
}
-struct impulse {
- float gain;
- float delay;
- char *filenames[MAX_RATES];
- int offset;
- int length;
- int channel;
- int resample_quality;
- int latency;
- unsigned long rate;
- float *samples;
- int n_samples;
-};
-
-#define IMPULSE_INIT(ch) (struct impulse) { 1.0f, 0.0f, { NULL, }, 0, 0, ch, RESAMPLE_DEFAULT_QUALITY, }
-
-static void impulse_clear(struct impulse *ir)
-{
- uint32_t i;
- for (i = 0; i < MAX_RATES; i++)
- if (ir->filenames[i])
- free(ir->filenames[i]);
- free(ir->samples);
- spa_zero(*ir);
-}
-
-static int finfo_read_samples(struct plugin *pl, struct finfo *info, struct impulse *ir)
+static float *finfo_read_samples(struct plugin *pl, struct finfo *info, float gain, int delay,
+ int offset, int length, int channel, long unsigned *rate, int *n_samples, int *latency)
{
float *samples, v;
- int i, n, h, delay = (int)(ir->delay * info->rate);
+ int i, n, h;
- if (ir->length <= 0)
- ir->length = info->def_frames;
+ if (length <= 0)
+ length = info->def_frames;
else
- ir->length = SPA_MIN(ir->length, info->max_frames);
+ length = SPA_MIN(length, info->max_frames);
- ir->length -= SPA_MIN(ir->offset, ir->length);
+ length -= SPA_MIN(offset, length);
- n = delay + ir->length;
+ n = delay + length;
if (n == 0)
- return -EINVAL;
+ return NULL;
samples = calloc(n * info->channels, sizeof(float));
if (samples == NULL)
- return -errno;
+ return NULL;
- ir->channel = ir->channel % info->channels;
+ channel = channel % info->channels;
switch (info->type) {
case TYPE_SNDFILE:
#ifdef HAVE_SNDFILE
- if (ir->offset > 0)
- sf_seek(info->fs, ir->offset, SEEK_SET);
- sf_readf_float(info->fs, samples + (delay * info->channels), ir->length);
+ if (offset > 0)
+ sf_seek(info->fs, offset, SEEK_SET);
+ sf_readf_float(info->fs, samples + (delay * info->channels), length);
for (i = 0; i < n; i++)
- samples[i] = samples[info->channels * i + ir->channel] * ir->gain;
+ samples[i] = samples[info->channels * i + channel] * gain;
#endif
break;
case TYPE_HILBERT:
- ir->gain *= 2 / (float)M_PI;
- h = ir->length / 2;
+ gain *= 2 / (float)M_PI;
+ h = length / 2;
for (i = 1; i < h; i += 2) {
- v = (ir->gain / i) * (0.43f + 0.57f * cosf(i * (float)M_PI / h));
+ v = (gain / i) * (0.43f + 0.57f * cosf(i * (float)M_PI / h));
samples[delay + h + i] = -v;
samples[delay + h - i] = v;
}
- spa_log_info(pl->log, "created hilbert function length %d", ir->length);
+ spa_log_info(pl->log, "created hilbert function length %d", length);
break;
case TYPE_DIRAC:
- samples[delay] = ir->gain;
+ samples[delay] = gain;
spa_log_info(pl->log, "created dirac function");
break;
case TYPE_IR:
@@ -873,23 +834,22 @@ static int finfo_read_samples(struct plugin *pl, struct finfo *info, struct impu
struct spa_json it[1];
float v;
if (spa_json_begin_array_relax(&it[0], info->filename+4, strlen(info->filename+4)) <= 0)
- return -EINVAL;
+ return NULL;
if (spa_json_get_int(&it[0], &h) <= 0)
- return -EINVAL;
+ return NULL;
info->rate = h;
i = 0;
while (spa_json_get_float(&it[0], &v) > 0) {
- samples[delay + i] = v * ir->gain;
+ samples[delay + i] = v * gain;
i++;
}
break;
}
}
- ir->samples = samples;
- ir->n_samples = n;
- ir->latency = (int) (n * info->latency);
- ir->rate = info->rate;
- return 0;
+ *n_samples = n;
+ *rate = info->rate;
+ *latency = (int) (n * info->latency);
+ return samples;
}
@@ -901,44 +861,49 @@ static void finfo_close(struct finfo *info)
#endif
}
-static int read_closest(struct plugin *pl, struct impulse *ir, int rate)
+static float *read_closest(struct plugin *pl, char **filenames, float gain, float delay_sec, int offset,
+ int length, int channel, long unsigned *rate, int *n_samples, int *latency)
{
struct finfo finfo[MAX_RATES];
- int res = -ENOENT, diff = INT_MAX;
+ int res, diff = INT_MAX;
uint32_t best = SPA_ID_INVALID, i;
+ float *samples = NULL;
spa_zero(finfo);
- for (i = 0; i < MAX_RATES && ir->filenames[i] && ir->filenames[i][0]; i++) {
- if ((res = finfo_open(ir->filenames[i], &finfo[i], rate)) < 0)
+ for (i = 0; i < MAX_RATES && filenames[i] && filenames[i][0]; i++) {
+ res = finfo_open(filenames[i], &finfo[i], *rate);
+ if (res < 0)
continue;
- if (labs((long)finfo[i].rate - (long)rate) < diff) {
+ if (labs((long)finfo[i].rate - (long)*rate) < diff) {
best = i;
- diff = labs((long)finfo[i].rate - (long)rate);
+ diff = labs((long)finfo[i].rate - (long)*rate);
spa_log_debug(pl->log, "new closest match: %d", finfo[i].rate);
}
}
if (best != SPA_ID_INVALID) {
- spa_log_info(pl->log, "loading best rate:%u %s", finfo[best].rate, ir->filenames[best]);
- res = finfo_read_samples(pl, &finfo[best], ir);
+ spa_log_info(pl->log, "loading best rate:%u %s", finfo[best].rate, filenames[best]);
+ samples = finfo_read_samples(pl, &finfo[best], gain,
+ (int) (delay_sec * finfo[best].rate), offset, length,
+ channel, rate, n_samples, latency);
} else {
char buf[PATH_MAX];
spa_log_error(pl->log, "Can't open any sample file (CWD %s):",
getcwd(buf, sizeof(buf)));
- for (i = 0; i < MAX_RATES && ir->filenames[i] && ir->filenames[i][0]; i++) {
- res = finfo_open(ir->filenames[i], &finfo[i], rate);
+ for (i = 0; i < MAX_RATES && filenames[i] && filenames[i][0]; i++) {
+ res = finfo_open(filenames[i], &finfo[i], *rate);
if (res < 0)
- spa_log_error(pl->log, " failed file %s: %s", ir->filenames[i], finfo[i].error);
+ spa_log_error(pl->log, " failed file %s: %s", filenames[i], finfo[i].error);
else
- spa_log_warn(pl->log, " unexpectedly opened file %s", ir->filenames[i]);
+ spa_log_warn(pl->log, " unexpectedly opened file %s", filenames[i]);
}
}
for (i = 0; i < MAX_RATES; i++)
finfo_close(&finfo[i]);
- return res;
+ return samples;
}
static float *resample_buffer(struct plugin *pl, float *samples, int *n_samples,
@@ -1018,119 +983,22 @@ error:
#endif
}
-static int convolver_read_impulse(struct plugin *pl, struct spa_json *obj,
- unsigned long SampleRate, struct impulse *ir)
-{
- int len, res = -EINVAL;
- uint32_t i = 0;
- char key[256];
- const char *val;
- struct spa_json it[2];
- unsigned long rate;
-
- while ((len = spa_json_object_next(obj, key, sizeof(key), &val)) > 0) {
- if (spa_streq(key, "gain")) {
- if (spa_json_parse_float(val, len, &ir->gain) <= 0) {
- spa_log_error(pl->log, "convolver:gain requires a number");
- goto error;
- }
- }
- else if (spa_streq(key, "delay")) {
- int delay_i;
- if (spa_json_parse_int(val, len, &delay_i) > 0) {
- ir->delay = delay_i / (float)SampleRate;
- } else if (spa_json_parse_float(val, len, &ir->delay) <= 0) {
- spa_log_error(pl->log, "convolver:delay requires a number");
- goto error;
- }
- }
- else if (spa_streq(key, "filename")) {
- if (spa_json_is_array(val, len)) {
- spa_json_enter(obj, &it[0]);
- while ((len = spa_json_next(&it[0], &val)) > 0 &&
- i < SPA_N_ELEMENTS(ir->filenames)) {
- ir->filenames[i] = malloc(len+1);
- if (ir->filenames[i] == NULL)
- goto error_errno;
- spa_json_parse_stringn(val, len, ir->filenames[i], len+1);
- i++;
- }
- }
- else {
- ir->filenames[0] = malloc(len+1);
- if (ir->filenames[0] == NULL)
- goto error_errno;
- spa_json_parse_stringn(val, len, ir->filenames[0], len+1);
- }
- }
- else if (spa_streq(key, "offset")) {
- if (spa_json_parse_int(val, len, &ir->offset) <= 0) {
- spa_log_error(pl->log, "convolver:offset requires a number");
- goto error;
- }
- }
- else if (spa_streq(key, "length")) {
- if (spa_json_parse_int(val, len, &ir->length) <= 0) {
- spa_log_error(pl->log, "convolver:length requires a number");
- goto error;
- }
- }
- else if (spa_streq(key, "channel")) {
- if (spa_json_parse_int(val, len, &ir->channel) <= 0) {
- spa_log_error(pl->log, "convolver:channel requires a number");
- goto error;
- }
- }
- else if (spa_streq(key, "resample_quality")) {
- if (spa_json_parse_int(val, len, &ir->resample_quality) <= 0) {
- spa_log_error(pl->log, "convolver:resample_quality requires a number");
- goto error;
- }
- }
- else {
- spa_log_warn(pl->log, "convolver: ignoring config key: '%s'", key);
- }
- }
- if (ir->filenames[0] == NULL) {
- spa_log_error(pl->log, "convolver:filename was not given");
- goto error;
- }
-
- if (ir->delay < 0.0f)
- ir->delay = 0.0f;
- if (ir->offset < 0)
- ir->offset = 0;
-
- rate = SampleRate;
- if ((res = read_closest(pl, ir, rate)) < 0)
- goto error;
- if (rate != ir->rate)
- ir->samples = resample_buffer(pl, ir->samples, &ir->n_samples,
- ir->rate, rate, ir->resample_quality);
- if (ir->samples == NULL)
- goto error_errno;
-
- return res;
-
-error_errno:
- res = -errno;
-error:
- impulse_clear(ir);
- return res;
-}
-
static void * convolver_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 convolver_impl *impl = NULL;
- int res, len;
+ struct convolver_impl *impl;
+ float *samples;
+ int offset = 0, length = 0, channel = index, n_samples = 0, len;
+ uint32_t i = 0;
struct spa_json it[2];
const char *val;
char key[256];
+ char *filenames[MAX_RATES] = { 0 };
int blocksize = 0, tailsize = 0;
- float latency = -1.0f;
- struct impulse ir = IMPULSE_INIT(index);
+ int resample_quality = RESAMPLE_DEFAULT_QUALITY, def_latency;
+ float gain = 1.0f, delay = 0.0f, latency = -1.0f;
+ unsigned long rate;
errno = EINVAL;
if (config == NULL) {
@@ -1156,26 +1024,107 @@ static void * convolver_instantiate(const struct spa_fga_plugin *plugin, const s
return NULL;
}
}
+ else if (spa_streq(key, "gain")) {
+ if (spa_json_parse_float(val, len, &gain) <= 0) {
+ spa_log_error(pl->log, "convolver:gain requires a number");
+ return NULL;
+ }
+ }
+ else if (spa_streq(key, "delay")) {
+ int delay_i;
+ if (spa_json_parse_int(val, len, &delay_i) > 0) {
+ delay = delay_i / (float)SampleRate;
+ } else if (spa_json_parse_float(val, len, &delay) <= 0) {
+ spa_log_error(pl->log, "convolver:delay requires a number");
+ return NULL;
+ }
+ }
+ else if (spa_streq(key, "filename")) {
+ if (spa_json_is_array(val, len)) {
+ spa_json_enter(&it[0], &it[1]);
+ while ((len = spa_json_next(&it[1], &val)) > 0 &&
+ i < SPA_N_ELEMENTS(filenames)) {
+ filenames[i] = malloc(len+1);
+ if (filenames[i] == NULL)
+ return NULL;
+ spa_json_parse_stringn(val, len, filenames[i], len+1);
+ i++;
+ }
+ }
+ else {
+ filenames[0] = malloc(len+1);
+ if (filenames[0] == NULL)
+ return NULL;
+ spa_json_parse_stringn(val, len, filenames[0], len+1);
+ }
+ }
+ else if (spa_streq(key, "offset")) {
+ if (spa_json_parse_int(val, len, &offset) <= 0) {
+ spa_log_error(pl->log, "convolver:offset requires a number");
+ return NULL;
+ }
+ }
+ else if (spa_streq(key, "length")) {
+ if (spa_json_parse_int(val, len, &length) <= 0) {
+ spa_log_error(pl->log, "convolver:length requires a number");
+ return NULL;
+ }
+ }
+ else if (spa_streq(key, "channel")) {
+ if (spa_json_parse_int(val, len, &channel) <= 0) {
+ spa_log_error(pl->log, "convolver:channel requires a number");
+ return NULL;
+ }
+ }
+ else if (spa_streq(key, "resample_quality")) {
+ if (spa_json_parse_int(val, len, &resample_quality) <= 0) {
+ spa_log_error(pl->log, "convolver:resample_quality requires a number");
+ return NULL;
+ }
+ }
else if (spa_streq(key, "latency")) {
if (spa_json_parse_float(val, len, &latency) <= 0) {
spa_log_error(pl->log, "convolver:latency requires a number");
return NULL;
}
}
+ else {
+ spa_log_warn(pl->log, "convolver: ignoring config key: '%s'", key);
+ }
}
- spa_json_begin_object(&it[0], config, strlen(config));
- if ((res = convolver_read_impulse(pl, &it[0], SampleRate, &ir)) < 0) {
- errno = -res;
+ if (filenames[0] == NULL) {
+ spa_log_error(pl->log, "convolver:filename was not given");
+ return NULL;
+ }
+
+ if (delay < 0.0f)
+ delay = 0.0f;
+ if (offset < 0)
+ offset = 0;
+
+ rate = SampleRate;
+ samples = read_closest(pl, filenames, gain, delay, offset,
+ length, channel, &rate, &n_samples, &def_latency);
+ if (samples != NULL && rate != SampleRate)
+ samples = resample_buffer(pl, samples, &n_samples,
+ rate, SampleRate, resample_quality);
+
+ for (i = 0; i < MAX_RATES; i++)
+ if (filenames[i])
+ free(filenames[i]);
+
+ if (samples == NULL) {
+ errno = ENOENT;
return NULL;
}
if (blocksize <= 0)
- blocksize = SPA_CLAMP(ir.n_samples, 64, 256);
+ blocksize = SPA_CLAMP(n_samples, 64, 256);
if (tailsize <= 0)
tailsize = SPA_CLAMP(4096, blocksize, 32768);
- spa_log_info(pl->log, "using n_samples:%u %d:%d blocksize delay:%f def-latency:%d", ir.n_samples,
- blocksize, tailsize, ir.delay, ir.latency);
+ spa_log_info(pl->log, "using n_samples:%u %d:%d blocksize delay:%f def-latency:%d", n_samples,
+ blocksize, tailsize, delay, def_latency);
impl = calloc(1, sizeof(*impl));
if (impl == NULL)
@@ -1185,20 +1134,21 @@ static void * convolver_instantiate(const struct spa_fga_plugin *plugin, const s
impl->log = pl->log;
impl->dsp = pl->dsp;
impl->rate = SampleRate;
- if (latency < 0.0f)
- impl->latency = ir.latency;
- else
- impl->latency = latency * impl->rate;
- impl->conv = convolver_new(impl->dsp, blocksize, tailsize, ir.samples, ir.n_samples);
+ impl->conv = convolver_new(impl->dsp, blocksize, tailsize, samples, n_samples);
if (impl->conv == NULL)
goto error;
- impulse_clear(&ir);
+ if (latency < 0.0f)
+ impl->latency = def_latency;
+ else
+ impl->latency = latency * impl->rate;
+
+ free(samples);
return impl;
error:
- impulse_clear(&ir);
+ free(samples);
free(impl);
return NULL;
}
@@ -1271,188 +1221,6 @@ static const struct spa_fga_descriptor convolve_desc = {
.cleanup = convolver_cleanup,
};
-/** convolver2 */
-static void * convolver2_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 convolver_impl *impl = NULL;
- int i, len, res, max_samples = 0;
- struct spa_json it[3];
- const char *val;
- char key[256];
- int blocksize = 0, tailsize = 0;
- float latency = -1.0f;
- struct impulse ir[8];
- struct convolver_ir cir[8];
- int n_ir = 0;
-
- errno = EINVAL;
- if (config == NULL) {
- spa_log_error(pl->log, "convolver: requires a config section");
- return NULL;
- }
-
- if (spa_json_begin_object(&it[0], config, strlen(config)) <= 0) {
- spa_log_error(pl->log, "convolver:config must be an object");
- return NULL;
- }
-
- while ((len = spa_json_object_next(&it[0], key, sizeof(key), &val)) > 0) {
- if (spa_streq(key, "blocksize")) {
- if (spa_json_parse_int(val, len, &blocksize) <= 0) {
- spa_log_error(pl->log, "convolver2:blocksize requires a number");
- return NULL;
- }
- }
- else if (spa_streq(key, "tailsize")) {
- if (spa_json_parse_int(val, len, &tailsize) <= 0) {
- spa_log_error(pl->log, "convolver2:tailsize requires a number");
- return NULL;
- }
- }
- else if (spa_streq(key, "latency")) {
- if (spa_json_parse_float(val, len, &latency) <= 0) {
- spa_log_error(pl->log, "convolver2:latency requires a number");
- return NULL;
- }
- }
- else if (spa_streq(key, "impulses")) {
- if (!spa_json_is_array(val, len)) {
- spa_log_error(pl->log, "convolver2:impulses require an array");
- return NULL;
- }
- spa_json_enter(&it[0], &it[1]);
- while (spa_json_enter_object(&it[1], &it[2]) > 0) {
- ir[n_ir] = IMPULSE_INIT(n_ir);
- if ((res = convolver_read_impulse(pl, &it[2], SampleRate, &ir[n_ir])) < 0)
- return NULL;
-
- max_samples = SPA_MAX(max_samples, ir[n_ir].n_samples);
- cir[n_ir].ir = ir[n_ir].samples;
- cir[n_ir].len = ir[n_ir].n_samples;
- n_ir++;
- }
- }
- else {
- spa_log_warn(pl->log, "convolver: ignoring config key: '%s'", key);
- }
- }
- if (n_ir == 0) {
- spa_log_error(pl->log, "convolver2:no impulses given");
- goto error;
- }
-
- if (blocksize <= 0)
- blocksize = SPA_CLAMP(max_samples, 64, 256);
- if (tailsize <= 0)
- tailsize = SPA_CLAMP(4096, blocksize, 32768);
-
- spa_log_info(pl->log, "using max_samples:%u %d:%d blocksize", max_samples,
- blocksize, tailsize);
-
- impl = calloc(1, sizeof(*impl));
- if (impl == NULL)
- goto error;
-
- impl->plugin = pl;
- impl->log = pl->log;
- impl->dsp = pl->dsp;
- impl->rate = SampleRate;
- if (latency < 0.0f)
- impl->latency = ir[0].latency;
- else
- impl->latency = latency * impl->rate;
-
- impl->conv = convolver_new_many(impl->dsp, blocksize, tailsize, cir, n_ir);
- if (impl->conv == NULL)
- goto error;
-
-
- return impl;
-error:
- for (i = 0; i < n_ir; i++)
- impulse_clear(&ir[i]);
- free(impl);
- return NULL;
-}
-
-static void convolver2_run(void * Instance, unsigned long SampleCount)
-{
- struct convolver_impl *impl = Instance;
- if (impl->port[0] != NULL)
- convolver_run_many(impl->conv, impl->port[0], &impl->port[2], SampleCount);
- if (impl->port[1] != NULL)
- impl->port[1][0] = impl->latency;
-}
-
-static void convolver2_activate(void * Instance)
-{
- struct convolver_impl *impl = Instance;
- if (impl->port[1] != NULL)
- impl->port[1][0] = impl->latency;
-}
-
-static struct spa_fga_port convolver2_ports[] = {
- { .index = 0,
- .name = "In",
- .flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_AUDIO,
- },
- { .index = 1,
- .name = "latency",
- .hint = SPA_FGA_HINT_LATENCY,
- .flags = SPA_FGA_PORT_OUTPUT | SPA_FGA_PORT_CONTROL,
- },
- { .index = 2,
- .name = "Out 1",
- .flags = SPA_FGA_PORT_OUTPUT | SPA_FGA_PORT_AUDIO,
- },
- { .index = 3,
- .name = "Out 2",
- .flags = SPA_FGA_PORT_OUTPUT | SPA_FGA_PORT_AUDIO,
- },
- { .index = 4,
- .name = "Out 3",
- .flags = SPA_FGA_PORT_OUTPUT | SPA_FGA_PORT_AUDIO,
- },
- { .index = 5,
- .name = "Out 4",
- .flags = SPA_FGA_PORT_OUTPUT | SPA_FGA_PORT_AUDIO,
- },
- { .index = 6,
- .name = "Out 5",
- .flags = SPA_FGA_PORT_OUTPUT | SPA_FGA_PORT_AUDIO,
- },
- { .index = 7,
- .name = "Out 6",
- .flags = SPA_FGA_PORT_OUTPUT | SPA_FGA_PORT_AUDIO,
- },
- { .index = 8,
- .name = "Out 7",
- .flags = SPA_FGA_PORT_OUTPUT | SPA_FGA_PORT_AUDIO,
- },
- { .index = 9,
- .name = "Out 8",
- .flags = SPA_FGA_PORT_OUTPUT | SPA_FGA_PORT_AUDIO,
- },
-};
-
-
-static const struct spa_fga_descriptor convolver2_desc = {
- .name = "convolver2",
- .flags = SPA_FGA_DESCRIPTOR_SUPPORTS_NULL_DATA,
-
- .n_ports = SPA_N_ELEMENTS(convolver2_ports),
- .ports = convolver2_ports,
-
- .instantiate = convolver2_instantiate,
- .connect_port = convolver_connect_port,
- .activate = convolver2_activate,
- .deactivate = convolver_deactivate,
- .run = convolver2_run,
- .cleanup = convolver_cleanup,
-};
-
/** delay */
struct delay_impl {
struct plugin *plugin;
@@ -1685,7 +1453,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",
@@ -1743,7 +1510,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",
@@ -1811,7 +1577,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
},
};
@@ -1861,7 +1626,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",
@@ -1919,7 +1683,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",
@@ -2709,12 +2472,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",
@@ -2723,7 +2484,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
},
};
@@ -2883,7 +2643,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",
@@ -3230,7 +2989,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",
@@ -3471,7 +3230,6 @@ static struct spa_fga_port null_ports[] = {
{ .index = 1,
.name = "Control",
.flags = SPA_FGA_PORT_INPUT | SPA_FGA_PORT_CONTROL,
- .def = 0.0f, .min = -FLT_MAX, .max = FLT_MAX
},
};
@@ -3557,8 +3315,6 @@ static const struct spa_fga_descriptor * builtin_descriptor(unsigned long Index)
return &busy_desc;
case 32:
return &null_desc;
- case 33:
- return &convolver2_desc;
}
return NULL;
}
diff --git a/spa/plugins/filter-graph/plugin_ebur128.c b/spa/plugins/filter-graph/plugin_ebur128.c
index 02fbcbe53..fb79de590 100644
--- a/spa/plugins/filter-graph/plugin_ebur128.c
+++ b/spa/plugins/filter-graph/plugin_ebur128.c
@@ -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",
diff --git a/spa/plugins/filter-graph/plugin_ffmpeg.c b/spa/plugins/filter-graph/plugin_ffmpeg.c
index 86001c0fd..4e4b9f4a0 100644
--- a/spa/plugins/filter-graph/plugin_ffmpeg.c
+++ b/spa/plugins/filter-graph/plugin_ffmpeg.c
@@ -243,7 +243,7 @@ static void ffmpeg_run(void *instance, unsigned long SampleCount)
delay);
for (j = 0; j < desc->layout[c].nb_channels; j++)
- spa_memcpy(i->data[d++], i->frame->data[j], SampleCount * sizeof(float));
+ memcpy(i->data[d++], i->frame->data[j], SampleCount * sizeof(float));
av_frame_unref(i->frame);
}
diff --git a/spa/plugins/filter-graph/plugin_ladspa.c b/spa/plugins/filter-graph/plugin_ladspa.c
index 54315861b..1aebafe35 100644
--- a/spa/plugins/filter-graph/plugin_ladspa.c
+++ b/spa/plugins/filter-graph/plugin_ladspa.c
@@ -233,49 +233,43 @@ static inline const char *split_walk(const char *str, const char *delimiter, siz
return s;
}
-static void make_search_paths(const char **path, const char **search_dirs)
-{
- const char *p;
-
- while ((p = strstr(*path, "../")) != NULL)
- *path = p + 3;
-
- *search_dirs = getenv("LADSPA_PATH");
- if (!*search_dirs)
- *search_dirs = "/usr/lib64/ladspa:/usr/lib/ladspa:" LIBDIR;
-}
-
-static int load_ladspa_plugin(struct plugin *impl, const char *path, const char *search_dirs)
+static int load_ladspa_plugin(struct plugin *impl, const char *path)
{
int res = -ENOENT;
- const char *p, *state = NULL;
- char filename[PATH_MAX];
- size_t len;
- /*
- * set the errno for the case when `ladspa_handle_load_by_path()`
- * is never called, which can only happen if the supplied
- * LADSPA_PATH contains too long paths
- */
- res = -ENAMETOOLONG;
+ if (path[0] != '/') {
+ const char *search_dirs, *p, *state = NULL;
+ char filename[PATH_MAX];
+ size_t len;
- while ((p = split_walk(search_dirs, ":", &len, &state))) {
- int namelen;
+ search_dirs = getenv("LADSPA_PATH");
+ if (!search_dirs)
+ search_dirs = "/usr/lib64/ladspa:/usr/lib/ladspa:" LIBDIR;
- if (len == 0 || len >= sizeof(filename))
- continue;
+ /*
+ * set the errno for the case when `ladspa_handle_load_by_path()`
+ * is never called, which can only happen if the supplied
+ * LADSPA_PATH contains too long paths
+ */
+ res = -ENAMETOOLONG;
+
+ while ((p = split_walk(search_dirs, ":", &len, &state))) {
+ int namelen;
+
+ if (len >= sizeof(filename))
+ continue;
- if (strncmp(path, p, len) == 0 && (path[len-1] == '/' || path[len] == '/'))
- namelen = snprintf(filename, sizeof(filename), "%s", path);
- else
namelen = snprintf(filename, sizeof(filename), "%.*s/%s.so", (int) len, p, path);
+ if (namelen < 0 || (size_t) namelen >= sizeof(filename))
+ continue;
- if (namelen < 0 || (size_t) namelen >= sizeof(filename))
- continue;
-
- res = ladspa_handle_load_by_path(impl, filename);
- if (res >= 0)
- break;
+ res = ladspa_handle_load_by_path(impl, filename);
+ if (res >= 0)
+ break;
+ }
+ }
+ else {
+ res = ladspa_handle_load_by_path(impl, path);
}
return res;
}
@@ -323,7 +317,7 @@ impl_init(const struct spa_handle_factory *factory,
struct plugin *impl;
uint32_t i;
int res;
- const char *path = NULL, *search_dirs;
+ const char *path = NULL;
handle->get_interface = impl_get_interface;
handle->clear = impl_clear;
@@ -341,11 +335,9 @@ impl_init(const struct spa_handle_factory *factory,
if (path == NULL)
return -EINVAL;
- make_search_paths(&path, &search_dirs);
-
- if ((res = load_ladspa_plugin(impl, path, search_dirs)) < 0) {
- spa_log_error(impl->log, "failed to load plugin '%s' in '%s': %s",
- path, search_dirs, spa_strerror(res));
+ if ((res = load_ladspa_plugin(impl, path)) < 0) {
+ spa_log_error(impl->log, "failed to load plugin '%s': %s",
+ path, spa_strerror(res));
return res;
}
diff --git a/spa/plugins/filter-graph/plugin_onnx.c b/spa/plugins/filter-graph/plugin_onnx.c
index 13fccee56..3ef12e963 100644
--- a/spa/plugins/filter-graph/plugin_onnx.c
+++ b/spa/plugins/filter-graph/plugin_onnx.c
@@ -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++;
diff --git a/spa/plugins/filter-graph/plugin_sofa.c b/spa/plugins/filter-graph/plugin_sofa.c
index 6e9330096..2e3a1ea3b 100644
--- a/spa/plugins/filter-graph/plugin_sofa.c
+++ b/spa/plugins/filter-graph/plugin_sofa.c
@@ -34,11 +34,11 @@ struct spatializer_impl {
int n_samples, blocksize, tailsize;
float gain;
float *tmp[2];
- float latency;
struct MYSOFA_EASY *sofa;
unsigned int interpolate:1;
- struct convolver *conv[3];
+ struct convolver *l_conv[3];
+ struct convolver *r_conv[3];
};
static void * spatializer_instantiate(const struct spa_fga_plugin *plugin, const struct spa_fga_descriptor * Descriptor,
@@ -73,7 +73,6 @@ static void * spatializer_instantiate(const struct spa_fga_plugin *plugin, const
impl->dsp = pl->dsp;
impl->log = pl->log;
impl->gain = 1.0f;
- impl->latency = 0.0f;
while ((len = spa_json_object_next(&it[0], key, sizeof(key), &val)) > 0) {
if (spa_streq(key, "blocksize")) {
@@ -104,16 +103,6 @@ static void * spatializer_instantiate(const struct spa_fga_plugin *plugin, const
goto error;
}
}
- else if (spa_streq(key, "latency")) {
- if (spa_json_parse_float(val, len, &impl->latency) <= 0) {
- spa_log_error(impl->log, "spatializer:latency requires a number");
- errno = EINVAL;
- goto error;
- }
- }
- else {
- spa_log_warn(pl->log, "spatializer: ignoring config key: '%s'", key);
- }
}
if (!filename[0]) {
spa_log_error(impl->log, "spatializer:filename was not given");
@@ -212,7 +201,6 @@ static void * spatializer_instantiate(const struct spa_fga_plugin *plugin, const
impl->tmp[0] = calloc(impl->plugin->quantum_limit, sizeof(float));
impl->tmp[1] = calloc(impl->plugin->quantum_limit, sizeof(float));
impl->rate = SampleRate;
-
return impl;
error:
if (impl->sofa)
@@ -227,12 +215,14 @@ do_switch(struct spa_loop *loop, bool async, uint32_t seq, const void *data,
{
struct spatializer_impl *impl = user_data;
- if (impl->conv[0] == NULL) {
- SPA_SWAP(impl->conv[0], impl->conv[2]);
+ if (impl->l_conv[0] == NULL) {
+ SPA_SWAP(impl->l_conv[0], impl->l_conv[2]);
+ SPA_SWAP(impl->r_conv[0], impl->r_conv[2]);
} else {
- SPA_SWAP(impl->conv[1], impl->conv[2]);
+ SPA_SWAP(impl->l_conv[1], impl->l_conv[2]);
+ SPA_SWAP(impl->r_conv[1], impl->r_conv[2]);
}
- impl->interpolate = impl->conv[0] && impl->conv[1];
+ impl->interpolate = impl->l_conv[0] && impl->l_conv[1];
return 0;
}
@@ -245,7 +235,6 @@ static void spatializer_reload(void * Instance)
float left_delay;
float right_delay;
float coords[3];
- struct convolver_ir ir[2];
for (uint8_t i = 0; i < 3; i++)
coords[i] = impl->port[3 + i][0];
@@ -268,8 +257,10 @@ static void spatializer_reload(void * Instance)
if ((left_delay != 0.0f || right_delay != 0.0f) && (!isnan(left_delay) || !isnan(right_delay)))
spa_log_warn(impl->log, "delay dropped l: %f, r: %f", left_delay, right_delay);
- if (impl->conv[2])
- convolver_free(impl->conv[2]);
+ if (impl->l_conv[2])
+ convolver_free(impl->l_conv[2]);
+ 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++) {
@@ -277,25 +268,24 @@ static void spatializer_reload(void * Instance)
right_ir[i] *= impl->gain;
}
}
- ir[0].ir = left_ir;
- ir[0].len = impl->n_samples;
- ir[1].ir = right_ir;
- ir[1].len = impl->n_samples;
- impl->conv[2] = convolver_new_many(impl->dsp, impl->blocksize, impl->tailsize, ir, 2);
+ 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,
+ right_ir, impl->n_samples);
free(left_ir);
free(right_ir);
- if (impl->conv[2] == NULL) {
- spa_log_error(impl->log, "reloading convolver failed");
+ if (impl->l_conv[2] == NULL || impl->r_conv[2] == NULL) {
+ spa_log_error(impl->log, "reloading left or right convolver failed");
return;
}
spa_loop_locked(impl->plugin->data_loop, do_switch, 1, NULL, 0, impl);
}
struct free_data {
- void *item[1];
+ void *item[2];
};
static int
@@ -305,6 +295,8 @@ do_free(struct spa_loop *loop, bool async, uint32_t seq, const void *data,
const struct free_data *fd = data;
if (fd->item[0])
convolver_free(fd->item[0]);
+ if (fd->item[1])
+ convolver_free(fd->item[1]);
return 0;
}
@@ -317,24 +309,29 @@ static void spatializer_run(void * Instance, unsigned long SampleCount)
struct free_data free_data;
float *l = impl->tmp[0], *r = impl->tmp[1];
- convolver_run_many(impl->conv[0], impl->port[2], &impl->port[0], len);
- convolver_run_many(impl->conv[1], impl->port[2], impl->tmp, len);
+ convolver_run(impl->l_conv[0], impl->port[2], impl->port[0], len);
+ convolver_run(impl->l_conv[1], impl->port[2], l, len);
+ convolver_run(impl->r_conv[0], impl->port[2], impl->port[1], len);
+ convolver_run(impl->r_conv[1], impl->port[2], r, len);
for (uint32_t i = 0; i < SampleCount; i++) {
float t = (float)i / SampleCount;
impl->port[0][i] = impl->port[0][i] * (1.0f - t) + l[i] * t;
impl->port[1][i] = impl->port[1][i] * (1.0f - t) + r[i] * t;
}
- free_data.item[0] = impl->conv[0];
- impl->conv[0] = impl->conv[1];
- impl->conv[1] = NULL;
+ free_data.item[0] = impl->l_conv[0];
+ free_data.item[1] = impl->r_conv[0];
+ impl->l_conv[0] = impl->l_conv[1];
+ impl->r_conv[0] = impl->r_conv[1];
+ impl->l_conv[1] = impl->r_conv[1] = NULL;
impl->interpolate = false;
spa_loop_invoke(impl->plugin->main_loop, do_free, 1, &free_data, sizeof(free_data), false, impl);
- } else if (impl->conv[0]) {
- convolver_run_many(impl->conv[0], impl->port[2], &impl->port[0], SampleCount);
+ } else if (impl->l_conv[0] && impl->r_conv[0]) {
+ convolver_run(impl->l_conv[0], impl->port[2], impl->port[0], SampleCount);
+ convolver_run(impl->r_conv[0], impl->port[2], impl->port[1], SampleCount);
}
- impl->port[6][0] = impl->latency;
+ impl->port[6][0] = impl->n_samples;
}
static void spatializer_connect_port(void * Instance, unsigned long Port,
@@ -349,8 +346,10 @@ static void spatializer_cleanup(void * Instance)
struct spatializer_impl *impl = Instance;
for (uint8_t i = 0; i < 3; i++) {
- if (impl->conv[i])
- convolver_free(impl->conv[i]);
+ if (impl->l_conv[i])
+ convolver_free(impl->l_conv[i]);
+ if (impl->r_conv[i])
+ convolver_free(impl->r_conv[i]);
}
if (impl->sofa)
mysofa_close_cached(impl->sofa);
@@ -368,14 +367,16 @@ static void spatializer_control_changed(void * Instance)
static void spatializer_activate(void * Instance)
{
struct spatializer_impl *impl = Instance;
- impl->port[6][0] = impl->latency;
+ impl->port[6][0] = impl->n_samples;
}
static void spatializer_deactivate(void * Instance)
{
struct spatializer_impl *impl = Instance;
- if (impl->conv[0])
- convolver_reset(impl->conv[0]);
+ if (impl->l_conv[0])
+ convolver_reset(impl->l_conv[0]);
+ if (impl->r_conv[0])
+ convolver_reset(impl->r_conv[0]);
impl->interpolate = false;
}
diff --git a/spa/plugins/libcamera/libcamera-device.cpp b/spa/plugins/libcamera/libcamera-device.cpp
index 6517860fc..2d6532f82 100644
--- a/spa/plugins/libcamera/libcamera-device.cpp
+++ b/spa/plugins/libcamera/libcamera-device.cpp
@@ -5,7 +5,6 @@
/* SPDX-License-Identifier: MIT */
#include
-#include
#include
#include
@@ -26,6 +25,7 @@
#include
#include
+#include
using namespace libcamera;
@@ -50,7 +50,7 @@ struct impl {
std::string device_id);
};
-std::span cameraDevice(const Camera& camera)
+const libcamera::Span cameraDevice(const Camera& camera)
{
if (auto devices = camera.properties().get(properties::SystemDevices))
return devices.value();
diff --git a/spa/plugins/meson.build b/spa/plugins/meson.build
index f774c1036..42aec7ed3 100644
--- a/spa/plugins/meson.build
+++ b/spa/plugins/meson.build
@@ -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()
diff --git a/spa/plugins/support/cpu-x86.c b/spa/plugins/support/cpu-x86.c
index 0fb866671..c1c53855d 100644
--- a/spa/plugins/support/cpu-x86.c
+++ b/spa/plugins/support/cpu-x86.c
@@ -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);
diff --git a/spa/plugins/support/logger.c b/spa/plugins/support/logger.c
index 7d0b14c1f..6ea5f31b5 100644
--- a/spa/plugins/support/logger.c
+++ b/spa/plugins/support/logger.c
@@ -2,16 +2,12 @@
/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
/* SPDX-License-Identifier: MIT */
-#include "config.h"
-
#include
-#include
#include
#include
#include
#include
#include
-#include
#include
#include
@@ -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;
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()]",
+ 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
diff --git a/spa/plugins/support/loop.c b/spa/plugins/support/loop.c
index 5e35f6dcd..e5e49849f 100644
--- a/spa/plugins/support/loop.c
+++ b/spa/plugins/support/loop.c
@@ -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;
diff --git a/spa/plugins/support/node-driver.c b/spa/plugins/support/node-driver.c
index f0585a711..fa9cf3426 100644
--- a/spa/plugins/support/node-driver.c
+++ b/spa/plugins/support/node-driver.c
@@ -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);
diff --git a/spa/plugins/support/null-audio-sink.c b/spa/plugins/support/null-audio-sink.c
index 610adf9ce..b804023b3 100644
--- a/spa/plugins/support/null-audio-sink.c
+++ b/spa/plugins/support/null-audio-sink.c
@@ -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);
diff --git a/spa/plugins/support/system.c b/spa/plugins/support/system.c
index cd9e1c6eb..767e0b43d 100644
--- a/spa/plugins/support/system.c
+++ b/spa/plugins/support/system.c
@@ -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;
}
diff --git a/spa/plugins/test/fakesink.c b/spa/plugins/test/fakesink.c
index 31667a1de..71550300c 100644
--- a/spa/plugins/test/fakesink.c
+++ b/spa/plugins/test/fakesink.c
@@ -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 (enabled) {
- 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;
+ if (this->callbacks.funcs || this->props.live) {
+ if (enabled) {
+ if (this->props.live) {
+ uint64_t next_time = this->start_time + this->elapsed_time;
+ 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 (res != -EAGAIN)
- spa_log_error(this->log, "%p: timerfd error: %s",
- this, spa_strerror(res));
+ 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);
- this->start_time = SPA_TIMESPEC_TO_NSEC(&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,8 +651,10 @@ static int impl_node_process(void *object)
io->buffer_id = SPA_ID_INVALID;
io->status = SPA_STATUS_OK;
}
-
- return SPA_STATUS_OK;
+ if (this->callbacks.funcs == NULL)
+ return consume_buffer(this);
+ else
+ return SPA_STATUS_OK;
}
static const struct spa_node_methods impl_node = {
@@ -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);
diff --git a/spa/plugins/test/fakesrc.c b/spa/plugins/test/fakesrc.c
index db28d9c3c..28b37dab4 100644
--- a/spa/plugins/test/fakesrc.c
+++ b/spa/plugins/test/fakesrc.c
@@ -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 (enabled) {
- 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;
+ if (this->callbacks.funcs || this->props.live) {
+ if (enabled) {
+ if (this->props.live) {
+ uint64_t next_time = this->start_time + this->elapsed_time;
+ 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 (res != -EAGAIN)
- spa_log_error(this->log, "%p: timerfd error: %s",
- this, spa_strerror(res));
+ 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);
- this->start_time = SPA_TIMESPEC_TO_NSEC(&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,7 +682,10 @@ static int impl_node_process(void *object)
io->buffer_id = SPA_ID_INVALID;
}
- return SPA_STATUS_OK;
+ if (this->callbacks.funcs == NULL)
+ return make_buffer(this);
+ else
+ return SPA_STATUS_OK;
}
static const struct spa_node_methods impl_node = {
@@ -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);
diff --git a/spa/plugins/videoconvert/videoadapter.c b/spa/plugins/videoconvert/videoadapter.c
index fe50413aa..e324b49de 100644
--- a/spa/plugins/videoconvert/videoadapter.c
+++ b/spa/plugins/videoconvert/videoadapter.c
@@ -1779,9 +1779,6 @@ impl_node_port_reuse_buffer(void *object, uint32_t port_id, uint32_t buffer_id)
spa_return_val_if_fail(this != NULL, -EINVAL);
- if (SPA_DIRECTION_OUTPUT != this->direction)
- port_id++;
-
return spa_node_port_reuse_buffer(this->target, port_id, buffer_id);
}
diff --git a/spa/plugins/videotestsrc/videotestsrc.c b/spa/plugins/videotestsrc/videotestsrc.c
index a8d7059c8..db5c90113 100644
--- a/spa/plugins/videotestsrc/videotestsrc.c
+++ b/spa/plugins/videotestsrc/videotestsrc.c
@@ -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 (enabled) {
- 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;
+ if (this->async || this->props.live) {
+ if (enabled) {
+ if (this->props.live) {
+ uint64_t next_time = this->start_time + this->elapsed_time;
+ 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);
- this->start_time = SPA_TIMESPEC_TO_NSEC(&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,7 +795,10 @@ static int impl_node_process(void *object)
io->buffer_id = SPA_ID_INVALID;
}
- return SPA_STATUS_OK;
+ if (!this->props.live)
+ return make_buffer(this);
+ else
+ return SPA_STATUS_OK;
}
static const struct spa_node_methods impl_node = {
@@ -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);
diff --git a/spa/plugins/vulkan/vulkan-blit-utils.c b/spa/plugins/vulkan/vulkan-blit-utils.c
index e0bd6cfe5..f8a60497e 100644
--- a/spa/plugins/vulkan/vulkan-blit-utils.c
+++ b/spa/plugins/vulkan/vulkan-blit-utils.c
@@ -12,10 +12,8 @@
#include
#include
#include
-#ifdef __linux__
+#if !defined(__FreeBSD__) && !defined(__MidnightBSD__)
#include
-#else
-#include
#endif
#include
#include
diff --git a/spa/plugins/vulkan/vulkan-compute-source.c b/spa/plugins/vulkan/vulkan-compute-source.c
index aa6f4a60f..1daf3b47c 100644
--- a/spa/plugins/vulkan/vulkan-compute-source.c
+++ b/spa/plugins/vulkan/vulkan-compute-source.c
@@ -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 (enabled) {
- 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;
+ if (this->async || this->props.live) {
+ if (enabled) {
+ if (this->props.live) {
+ uint64_t next_time = this->start_time + this->elapsed_time;
+ 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 (res != -EAGAIN)
- spa_log_error(this->log, "%p: timerfd error: %s",
- this, spa_strerror(res));
+ 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);
- this->start_time = SPA_TIMESPEC_TO_NSEC(&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,7 +874,10 @@ static int impl_node_process(void *object)
io->buffer_id = SPA_ID_INVALID;
}
- return SPA_STATUS_OK;
+ if (!this->props.live)
+ return make_buffer(this);
+ else
+ return SPA_STATUS_OK;
}
static const struct spa_node_methods impl_node = {
@@ -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);
diff --git a/spa/plugins/vulkan/vulkan-compute-utils.c b/spa/plugins/vulkan/vulkan-compute-utils.c
index 6c0ff279e..49705bee8 100644
--- a/spa/plugins/vulkan/vulkan-compute-utils.c
+++ b/spa/plugins/vulkan/vulkan-compute-utils.c
@@ -11,10 +11,8 @@
#include
#include
#include
-#ifdef __linux__
+#if !defined(__FreeBSD__) && !defined(__MidnightBSD__)
#include
-#else
-#include
#endif
#include
#include
@@ -147,7 +145,7 @@ static int updateDescriptors(struct vulkan_compute_state *s)
.descriptorType = i == 0 ?
VK_DESCRIPTOR_TYPE_STORAGE_IMAGE :
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
- .pImageInfo = &descriptorImageInfo[descriptorSetLen],
+ .pImageInfo = &descriptorImageInfo[i],
};
descriptorSetLen++;
}
diff --git a/spa/plugins/vulkan/vulkan-utils.c b/spa/plugins/vulkan/vulkan-utils.c
index 88a230dd6..6a0f693dc 100644
--- a/spa/plugins/vulkan/vulkan-utils.c
+++ b/spa/plugins/vulkan/vulkan-utils.c
@@ -11,10 +11,8 @@
#include
#include
#include
-#ifdef __linux__
+#if !defined(__FreeBSD__) && !defined(__MidnightBSD__)
#include
-#else
-#include
#endif
#include
#include
diff --git a/spa/tests/benchmark-aec.c b/spa/tests/benchmark-aec.c
index 37d4a8375..3ac0fc62e 100644
--- a/spa/tests/benchmark-aec.c
+++ b/spa/tests/benchmark-aec.c
@@ -6,6 +6,7 @@
#include
#include
+#include
#include
#include
#include
diff --git a/spa/tools/spa-json-dump.c b/spa/tools/spa-json-dump.c
index ed81330d4..ee3b42da7 100644
--- a/spa/tools/spa-json-dump.c
+++ b/spa/tools/spa-json-dump.c
@@ -15,28 +15,27 @@
#include
#include
-#include
#include
#define DEFAULT_INDENT 2
struct data {
const char *filename;
-
- FILE *out;
- struct spa_json_builder builder;
+ FILE *file;
void *data;
size_t size;
+
+ int indent;
+ bool simple_string;
+ const char *comma;
+ const char *key_sep;
};
-#define OPTIONS "hNC:Ri:s"
+#define OPTIONS "hi:s"
static const struct option long_options[] = {
{ "help", no_argument, NULL, 'h'},
- { "no-colors", no_argument, NULL, 'N' },
- { "color", optional_argument, NULL, 'C' },
- { "raw", no_argument, NULL, 'R' },
{ "indent", required_argument, NULL, 'i' },
{ "spa", no_argument, NULL, 's' },
@@ -54,21 +53,72 @@ static void show_usage(struct data *d, const char *name, bool is_error)
" -h, --help Show this help\n"
"\n");
fprintf(fp,
- " -N, --no-colors disable color output\n"
- " -C, --color[=WHEN] whether to enable color support. WHEN is `never`, `always`, or `auto`\n"
- " -R, --raw force raw output\n"
" -i --indent set indent (default %d)\n"
" -s --spa use simplified SPA JSON\n"
"\n",
DEFAULT_INDENT);
}
-static int dump(struct data *d, struct spa_json *it, const char *key, const char *value, int len)
+#define REJECT "\"\\'=:,{}[]()#"
+
+static bool is_simple_string(const char *val, int len)
{
- struct spa_json_builder *b = &d->builder;
+ int i;
+ for (i = 0; i < len; i++) {
+ if (val[i] < 0x20 || strchr(REJECT, val[i]) != NULL)
+ return false;
+ }
+ return true;
+}
+
+static void encode_string(struct data *d, const char *val, int len)
+{
+ FILE *f = d->file;
+ int i;
+ if (d->simple_string && is_simple_string(val, len)) {
+ fprintf(f, "%.*s", len, val);
+ return;
+ }
+ fprintf(f, "\"");
+ for (i = 0; i < len; i++) {
+ char v = val[i];
+ switch (v) {
+ case '\n':
+ fprintf(f, "\\n");
+ break;
+ case '\r':
+ fprintf(f, "\\r");
+ break;
+ case '\b':
+ fprintf(f, "\\b");
+ break;
+ case '\t':
+ fprintf(f, "\\t");
+ break;
+ case '\f':
+ fprintf(f, "\\f");
+ break;
+ case '\\': case '"':
+ fprintf(f, "\\%c", v);
+ break;
+ default:
+ if (v > 0 && v < 0x20)
+ fprintf(f, "\\u%04x", v);
+ else
+ fprintf(f, "%c", v);
+ break;
+ }
+ }
+ fprintf(f, "\"");
+}
+
+static int dump(struct data *d, int indent, struct spa_json *it, const char *value, int len)
+{
+ FILE *file = d->file;
struct spa_json sub;
bool toplevel = false;
- int res;
+ int count = 0, res;
+ char key[1024];
if (!value) {
toplevel = true;
@@ -77,22 +127,29 @@ static int dump(struct data *d, struct spa_json *it, const char *key, const char
}
if (spa_json_is_array(value, len)) {
- spa_json_builder_object_push(b, key, "[");
+ fprintf(file, "[");
spa_json_enter(it, &sub);
while ((len = spa_json_next(&sub, &value)) > 0) {
- if ((res = dump(d, &sub, NULL, value, len)) < 0)
+ fprintf(file, "%s\n%*s", count++ > 0 ? d->comma : "",
+ indent+d->indent, "");
+ if ((res = dump(d, indent+d->indent, &sub, value, len)) < 0)
return res;
}
- spa_json_builder_pop(b, "]");
+ fprintf(file, "%s%*s]", count > 0 ? "\n" : "",
+ count > 0 ? indent : 0, "");
} else if (spa_json_is_object(value, len)) {
- char k[1024];
- spa_json_builder_object_push(b, key, "{");
+ fprintf(file, "{");
if (!toplevel)
spa_json_enter(it, &sub);
else
sub = *it;
- while ((len = spa_json_object_next(&sub, k, sizeof(k), &value)) > 0) {
- res = dump(d, &sub, k, value, len);
+ while ((len = spa_json_object_next(&sub, key, sizeof(key), &value)) > 0) {
+ fprintf(file, "%s\n%*s",
+ count++ > 0 ? d->comma : "",
+ indent+d->indent, "");
+ encode_string(d, key, strlen(key));
+ fprintf(file, "%s ", d->key_sep);
+ res = dump(d, indent+d->indent, &sub, value, len);
if (res < 0) {
if (toplevel)
*it = sub;
@@ -101,10 +158,18 @@ static int dump(struct data *d, struct spa_json *it, const char *key, const char
}
if (toplevel)
*it = sub;
- spa_json_builder_pop(b, "}");
+ fprintf(file, "%s%*s}", count > 0 ? "\n" : "",
+ count > 0 ? indent : 0, "");
+ } else if (spa_json_is_string(value, len) ||
+ spa_json_is_null(value, len) ||
+ spa_json_is_bool(value, len) ||
+ spa_json_is_int(value, len) ||
+ spa_json_is_float(value, len)) {
+ fprintf(file, "%.*s", len, value);
} else {
- spa_json_builder_add_simple(b, key, INT_MAX, 0, value, len);
+ encode_string(d, value, len);
}
+
if (spa_json_get_error(it, NULL, NULL))
return -EINVAL;
@@ -127,12 +192,12 @@ static int process_json(struct data *d)
len = 0;
}
- res = dump(d, &it, NULL, value, len);
+ res = dump(d, 0, &it, value, len);
if (spa_json_next(&it, &value) < 0)
res = -EINVAL;
- fprintf(d->builder.f, "\n");
- fflush(d->builder.f);
+ fprintf(d->file, "\n");
+ fflush(d->file);
if (res < 0) {
struct spa_error_location loc;
@@ -192,50 +257,30 @@ int main(int argc, char *argv[])
int c;
int longopt_index = 0;
int fd, res, exit_code = EXIT_FAILURE;
- int flags = 0, indent = -1;
struct data d;
struct stat sbuf;
- bool raw = false, colors = false;
spa_zero(d);
+ d.file = stdout;
d.filename = "-";
- d.out = stdout;
-
- if (getenv("NO_COLOR") == NULL && isatty(fileno(d.out)))
- colors = true;
- setlinebuf(d.out);
+ d.simple_string = false;
+ d.comma = ",";
+ d.key_sep = ":";
+ d.indent = DEFAULT_INDENT;
while ((c = getopt_long(argc, argv, OPTIONS, long_options, &longopt_index)) != -1) {
switch (c) {
case 'h' :
show_usage(&d, argv[0], false);
return 0;
- case 'N' :
- colors = false;
- break;
- case 'C' :
- if (optarg == NULL || !strcmp(optarg, "auto"))
- break; /* nothing to do, tty detection was done
- before parsing options */
- else if (!strcmp(optarg, "never"))
- colors = false;
- else if (!strcmp(optarg, "always"))
- colors = true;
- else {
- fprintf(stderr, "Unknown color: %s\n", optarg);
- show_usage(&d, argv[0], true);
- return -1;
- }
- break;
- case 'R':
- raw = true;
- break;
case 'i':
- indent = atoi(optarg);
+ d.indent = atoi(optarg);
break;
case 's':
- flags |= SPA_JSON_BUILDER_FLAG_SIMPLE;
+ d.simple_string = true;
+ d.comma = "";
+ d.key_sep = " =";
break;
default:
show_usage(&d, argv[0], true);
@@ -263,15 +308,6 @@ int main(int argc, char *argv[])
}
d.size = sbuf.st_size;
- if (!raw)
- flags |= SPA_JSON_BUILDER_FLAG_PRETTY;
- if (colors)
- flags |= SPA_JSON_BUILDER_FLAG_COLOR;
-
- spa_json_builder_file(&d.builder, d.out, flags);
- if (indent >= 0)
- d.builder.indent = indent;
-
res = process_json(&d);
if (res < 0)
exit_code = EXIT_FAILURE;
diff --git a/src/daemon/client.conf.in b/src/daemon/client.conf.in
index e0baeda92..46874af93 100644
--- a/src/daemon/client.conf.in
+++ b/src/daemon/client.conf.in
@@ -101,9 +101,6 @@ stream.properties = {
#channelmix.lfe-cutoff = 150
#channelmix.fc-cutoff = 12000
#channelmix.rear-delay = 12.0
- #channelmix.center-level = 0.707106781
- #channelmix.surround-level = 0.707106781
- #channelmix.lfe-level = 0.5
#channelmix.stereo-widen = 0.0
#channelmix.hilbert-taps = 0
#dither.noise = 0
diff --git a/src/daemon/filter-chain/sink-virtual-surround-7.1-hesuvi.conf b/src/daemon/filter-chain/sink-virtual-surround-7.1-hesuvi.conf
index 34a07dbcc..3630c23a8 100644
--- a/src/daemon/filter-chain/sink-virtual-surround-7.1-hesuvi.conf
+++ b/src/daemon/filter-chain/sink-virtual-surround-7.1-hesuvi.conf
@@ -13,105 +13,78 @@ context.modules = [
media.name = "Virtual Surround Sink"
filter.graph = {
nodes = [
+ # duplicate inputs
+ { type = builtin label = copy name = copyFL }
+ { type = builtin label = copy name = copyFR }
+ { type = builtin label = copy name = copyFC }
+ { type = builtin label = copy name = copyRL }
+ { type = builtin label = copy name = copyRR }
+ { type = builtin label = copy name = copySL }
+ { type = builtin label = copy name = copySR }
+ { type = builtin label = copy name = copyLFE }
# apply hrir - HeSuVi 14-channel WAV (not the *-.wav variants) (note: */44/* in HeSuVi are the same, but resampled to 44100)
- { type = builtin label = convolver2 name = convFL
- config = {
- impulses = [
- { filename = "/home/wim/src/pipewire/hrir_hesuvi/hesuvi.wav" channel = 0 } # L
- { filename = "/home/wim/src/pipewire/hrir_hesuvi/hesuvi.wav" channel = 1 } # R
- ]
- }
- }
- { type = builtin label = convolver2 name = convFR
- config = {
- impulses = [
- { filename = "/home/wim/src/pipewire/hrir_hesuvi/hesuvi.wav" channel = 8 } # L
- { filename = "/home/wim/src/pipewire/hrir_hesuvi/hesuvi.wav" channel = 7 } # R
- ]
- }
- }
- { type = builtin label = convolver2 name = convFC
- config = {
- impulses = [
- { filename = "/home/wim/src/pipewire/hrir_hesuvi/hesuvi.wav" channel = 6 gain = 2.0} # L
- { filename = "/home/wim/src/pipewire/hrir_hesuvi/hesuvi.wav" channel = 13 gain = 2.0} # R
- ]
- }
- }
- { type = builtin label = convolver2 name = convLFE
- config = {
- impulses = [
- { filename = "/home/wim/src/pipewire/hrir_hesuvi/hesuvi.wav" channel = 6 } # L
- { filename = "/home/wim/src/pipewire/hrir_hesuvi/hesuvi.wav" channel = 13 } # R
- ]
- }
- }
- { type = builtin label = convolver2 name = convSL
- config = {
- impulses = [
- { filename = "/home/wim/src/pipewire/hrir_hesuvi/hesuvi.wav" channel = 2 } # L
- { filename = "/home/wim/src/pipewire/hrir_hesuvi/hesuvi.wav" channel = 3 } # R
- ]
- }
- }
- { type = builtin label = convolver2 name = convSR
- config = {
- impulses = [
- { filename = "/home/wim/src/pipewire/hrir_hesuvi/hesuvi.wav" channel = 10 } # L
- { filename = "/home/wim/src/pipewire/hrir_hesuvi/hesuvi.wav" channel = 9 } # R
- ]
- }
- }
- { type = builtin label = convolver2 name = convRL
- config = {
- impulses = [
- { filename = "/home/wim/src/pipewire/hrir_hesuvi/hesuvi.wav" channel = 4 } # L
- { filename = "/home/wim/src/pipewire/hrir_hesuvi/hesuvi.wav" channel = 5 } # R
- ]
- }
- }
- { type = builtin label = convolver2 name = convRR
- config = {
- impulses = [
- { filename = "/home/wim/src/pipewire/hrir_hesuvi/hesuvi.wav" channel = 12 } # L
- { filename = "/home/wim/src/pipewire/hrir_hesuvi/hesuvi.wav" channel = 11 } # R
- ]
- }
- }
- { type = builtin label = mixer name = mixL }
+ { type = builtin label = convolver name = convFL_L config = { filename = "hrir_hesuvi/hrir.wav" channel = 0 } }
+ { type = builtin label = convolver name = convFL_R config = { filename = "hrir_hesuvi/hrir.wav" channel = 1 } }
+ { type = builtin label = convolver name = convSL_L config = { filename = "hrir_hesuvi/hrir.wav" channel = 2 } }
+ { type = builtin label = convolver name = convSL_R config = { filename = "hrir_hesuvi/hrir.wav" channel = 3 } }
+ { type = builtin label = convolver name = convRL_L config = { filename = "hrir_hesuvi/hrir.wav" channel = 4 } }
+ { type = builtin label = convolver name = convRL_R config = { filename = "hrir_hesuvi/hrir.wav" channel = 5 } }
+ { type = builtin label = convolver name = convFC_L config = { filename = "hrir_hesuvi/hrir.wav" channel = 6 } }
+ { type = builtin label = convolver name = convFR_R config = { filename = "hrir_hesuvi/hrir.wav" channel = 7 } }
+ { type = builtin label = convolver name = convFR_L config = { filename = "hrir_hesuvi/hrir.wav" channel = 8 } }
+ { type = builtin label = convolver name = convSR_R config = { filename = "hrir_hesuvi/hrir.wav" channel = 9 } }
+ { type = builtin label = convolver name = convSR_L config = { filename = "hrir_hesuvi/hrir.wav" channel = 10 } }
+ { type = builtin label = convolver name = convRR_R config = { filename = "hrir_hesuvi/hrir.wav" channel = 11 } }
+ { type = builtin label = convolver name = convRR_L config = { filename = "hrir_hesuvi/hrir.wav" channel = 12 } }
+ { type = builtin label = convolver name = convFC_R config = { filename = "hrir_hesuvi/hrir.wav" channel = 13 } }
+
+ # treat LFE as FC
+ { type = builtin label = convolver name = convLFE_L config = { filename = "hrir_hesuvi/hrir.wav" channel = 6 } }
+ { type = builtin label = convolver name = convLFE_R config = { filename = "hrir_hesuvi/hrir.wav" channel = 13 } }
+
+ # stereo output
+ { type = builtin label = mixer name = mixL }
{ type = builtin label = mixer name = mixR }
]
links = [
+ # input
+ { output = "copyFL:Out" input="convFL_L:In" }
+ { output = "copyFL:Out" input="convFL_R:In" }
+ { output = "copySL:Out" input="convSL_L:In" }
+ { output = "copySL:Out" input="convSL_R:In" }
+ { output = "copyRL:Out" input="convRL_L:In" }
+ { output = "copyRL:Out" input="convRL_R:In" }
+ { output = "copyFC:Out" input="convFC_L:In" }
+ { output = "copyFR:Out" input="convFR_R:In" }
+ { output = "copyFR:Out" input="convFR_L:In" }
+ { output = "copySR:Out" input="convSR_R:In" }
+ { output = "copySR:Out" input="convSR_L:In" }
+ { output = "copyRR:Out" input="convRR_R:In" }
+ { output = "copyRR:Out" input="convRR_L:In" }
+ { output = "copyFC:Out" input="convFC_R:In" }
+ { output = "copyLFE:Out" input="convLFE_L:In" }
+ { output = "copyLFE:Out" input="convLFE_R:In" }
+
# output
- { output = "convFL:Out 1" input="mixL:In 1" }
- { output = "convFL:Out 2" input="mixR:In 1" }
-
- { output = "convSL:Out 1" input="mixL:In 2" }
- { output = "convSL:Out 2" input="mixR:In 2" }
-
- { output = "convRL:Out 1" input="mixL:In 3" }
- { output = "convRL:Out 2" input="mixR:In 3" }
-
- { output = "convFC:Out 1" input="mixL:In 4" }
- { output = "convFC:Out 2" input="mixR:In 4" }
-
- { output = "convFR:Out 1" input="mixL:In 5" }
- { output = "convFR:Out 2" input="mixR:In 5" }
-
- { output = "convSR:Out 1" input="mixL:In 6" }
- { output = "convSR:Out 2" input="mixR:In 6" }
-
- { output = "convRR:Out 1" input="mixL:In 7" }
- { output = "convRR:Out 2" input="mixR:In 7" }
-
- { output = "convLFE:Out 1" input="mixL:In 8" }
- { output = "convLFE:Out 2" input="mixR:In 8" }
+ { output = "convFL_L:Out" input="mixL:In 1" }
+ { output = "convFL_R:Out" input="mixR:In 1" }
+ { output = "convSL_L:Out" input="mixL:In 2" }
+ { output = "convSL_R:Out" input="mixR:In 2" }
+ { output = "convRL_L:Out" input="mixL:In 3" }
+ { output = "convRL_R:Out" input="mixR:In 3" }
+ { output = "convFC_L:Out" input="mixL:In 4" }
+ { output = "convFC_R:Out" input="mixR:In 4" }
+ { output = "convFR_R:Out" input="mixR:In 5" }
+ { output = "convFR_L:Out" input="mixL:In 5" }
+ { output = "convSR_R:Out" input="mixR:In 6" }
+ { output = "convSR_L:Out" input="mixL:In 6" }
+ { output = "convRR_R:Out" input="mixR:In 7" }
+ { output = "convRR_L:Out" input="mixL:In 7" }
+ { output = "convLFE_R:Out" input="mixR:In 8" }
+ { output = "convLFE_L:Out" input="mixL:In 8" }
]
- inputs = [ "convFL:In" "convFR:In"
- "convFC:In" "convLFE:In"
- "convRL:In" "convRR:In"
- "convSL:In" "convSR:In" ]
+ inputs = [ "copyFL:In" "copyFR:In" "copyFC:In" "copyLFE:In" "copyRL:In" "copyRR:In", "copySL:In", "copySR:In" ]
outputs = [ "mixL:Out" "mixR:Out" ]
}
capture.props = {
diff --git a/src/daemon/filter-chain/source-rnnoise.conf b/src/daemon/filter-chain/source-rnnoise.conf
index 83142dd29..f3c2c71be 100644
--- a/src/daemon/filter-chain/source-rnnoise.conf
+++ b/src/daemon/filter-chain/source-rnnoise.conf
@@ -21,6 +21,7 @@ context.modules = [
# listed in the environment variable LADSPA_PATH or
# /usr/lib64/ladspa, /usr/lib/ladspa or the system library directory
# as a fallback.
+ # You might want to use an absolute path here to avoid problems.
plugin = "librnnoise_ladspa"
label = noise_suppressor_stereo
control = {
diff --git a/src/daemon/minimal.conf.in b/src/daemon/minimal.conf.in
index 7ab93e92b..82647e9ca 100644
--- a/src/daemon/minimal.conf.in
+++ b/src/daemon/minimal.conf.in
@@ -100,10 +100,6 @@ context.modules = [
}
flags = [ ifexists nofail ]
}
- # the graph scheduler
- { name = libpipewire-module-scheduler-v1
- condition = [ { module.scheduler-v1 = !false } ]
- }
# The native communication protocol.
{ name = libpipewire-module-protocol-native }
@@ -332,9 +328,6 @@ context.objects = [
#channelmix.fc-cutoff = 12000
#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
#channelmix.disable = false
#dither.noise = 0
diff --git a/src/daemon/pipewire-avb.conf.in b/src/daemon/pipewire-avb.conf.in
index e43015780..da158f212 100644
--- a/src/daemon/pipewire-avb.conf.in
+++ b/src/daemon/pipewire-avb.conf.in
@@ -60,9 +60,6 @@ stream.properties = {
#channelmix.fc-cutoff = 6000
#channelmix.rear-delay = 12.0
#channelmix.stereo-widen = 0.1
- #channelmix.center-level = 0.707106781
- #channelmix.surround-level = 0.707106781
- #channelmix.lfe-level = 0.5
#channelmix.hilbert-taps = 0
}
diff --git a/src/daemon/pipewire-pulse.conf.in b/src/daemon/pipewire-pulse.conf.in
index db646db0b..8c21e37df 100644
--- a/src/daemon/pipewire-pulse.conf.in
+++ b/src/daemon/pipewire-pulse.conf.in
@@ -88,9 +88,6 @@ stream.properties = {
#channelmix.fc-cutoff = 12000
#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
}
diff --git a/src/daemon/pipewire.conf.in b/src/daemon/pipewire.conf.in
index a9142cede..c3eb7120f 100644
--- a/src/daemon/pipewire.conf.in
+++ b/src/daemon/pipewire.conf.in
@@ -121,10 +121,6 @@ context.modules = [
flags = [ ifexists nofail ]
condition = [ { module.rt = !false } ]
}
- # the graph scheduler
- { name = libpipewire-module-scheduler-v1
- condition = [ { module.scheduler-v1 = !false } ]
- }
# The native communication protocol.
{ name = libpipewire-module-protocol-native
diff --git a/src/examples/audio-dsp-filter.c b/src/examples/audio-dsp-filter.c
index 589646d61..8a43147a6 100644
--- a/src/examples/audio-dsp-filter.c
+++ b/src/examples/audio-dsp-filter.c
@@ -108,7 +108,6 @@ int main(int argc, char *argv[])
PW_KEY_MEDIA_TYPE, "Audio",
PW_KEY_MEDIA_CATEGORY, "Filter",
PW_KEY_MEDIA_ROLE, "DSP",
- PW_KEY_NODE_PASSIVE, "follow",
NULL),
&filter_events,
&data);
diff --git a/src/examples/audio-dsp-src.c b/src/examples/audio-dsp-src.c
index 0ef4a0e53..135d2e27e 100644
--- a/src/examples/audio-dsp-src.c
+++ b/src/examples/audio-dsp-src.c
@@ -18,6 +18,7 @@
#define M_PI_M2f (float)(M_PI+M_PI)
+#define DEFAULT_RATE 44100
#define DEFAULT_FREQ 440
#define DEFAULT_VOLUME 0.7f
@@ -60,9 +61,7 @@ static void on_process(void *userdata, struct spa_io_position *position)
return;
for (i = 0; i < n_samples; i++) {
- out_port->accumulator += M_PI_M2f * DEFAULT_FREQ *
- position->clock.rate.num / position->clock.rate.denom;
-
+ out_port->accumulator += M_PI_M2f * DEFAULT_FREQ / DEFAULT_RATE;
if (out_port->accumulator >= M_PI_M2f)
out_port->accumulator -= M_PI_M2f;
diff --git a/src/examples/video-src-alloc.c b/src/examples/video-src-alloc.c
index c89ce8d78..add9597ed 100644
--- a/src/examples/video-src-alloc.c
+++ b/src/examples/video-src-alloc.c
@@ -192,11 +192,7 @@ static void on_stream_state_changed(void *_data, enum pw_stream_state old, enum
interval.tv_sec = 0;
interval.tv_nsec = 40 * SPA_NSEC_PER_MSEC;
- printf("driving:%d lazy:%d\n",
- pw_stream_is_driving(data->stream),
- pw_stream_is_lazy(data->stream));
-
- if (pw_stream_is_driving(data->stream) != pw_stream_is_lazy(data->stream))
+ if (pw_stream_is_driving(data->stream))
pw_loop_update_timer(pw_thread_loop_get_loop(data->loop),
data->timer, &timeout, &interval, false);
break;
@@ -394,7 +390,6 @@ int main(int argc, char *argv[])
"video-src-alloc",
pw_properties_new(
PW_KEY_MEDIA_CLASS, "Video/Source",
- PW_KEY_NODE_SUPPORTS_REQUEST, "1",
NULL),
&stream_events,
&data);
diff --git a/src/examples/video-src-fixate.c b/src/examples/video-src-fixate.c
index b16d810ad..6d08074de 100644
--- a/src/examples/video-src-fixate.c
+++ b/src/examples/video-src-fixate.c
@@ -18,11 +18,7 @@
#include
#include
#include
-#ifdef __linux__
#include
-#else
-#include
-#endif
#include
#include
diff --git a/src/gst/gstpipewiresink.c b/src/gst/gstpipewiresink.c
index 99235b118..58a6cd8db 100644
--- a/src/gst/gstpipewiresink.c
+++ b/src/gst/gstpipewiresink.c
@@ -655,7 +655,7 @@ do_send_buffer (GstPipeWireSink *pwsink, GstBuffer *buffer)
data->crop->region.position.x = meta->x;
data->crop->region.position.y = meta->y;
data->crop->region.size.width = meta->width;
- data->crop->region.size.height = meta->height;
+ data->crop->region.size.height = meta->width;
}
}
data->b->size = 0;
diff --git a/src/gst/gstpipewiresrc.c b/src/gst/gstpipewiresrc.c
index 3c57028b4..6ca9599d6 100644
--- a/src/gst/gstpipewiresrc.c
+++ b/src/gst/gstpipewiresrc.c
@@ -839,17 +839,6 @@ static GstBuffer *dequeue_buffer(GstPipeWireSrc *pwsrc)
video_size += d->chunk->size;
}
-
- /* If the buffer number is smaller than the plane number,
- * update the stride and offset for the remaining planes.
- */
- if (n_datas && n_datas < n_planes) {
- for (i = n_datas; i < n_planes; i++) {
- meta->stride[i] = gst_video_format_info_extrapolate_stride (info->finfo, i, b->buffer->datas[0].chunk->stride);
- meta->offset[i] = meta->offset[i-1] +
- meta->stride[i-1] * GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info->finfo, i-1, GST_VIDEO_INFO_HEIGHT(info));
- }
- }
}
if (b->buffer->n_datas != gst_buffer_n_memory(data->buf)) {
@@ -1085,6 +1074,10 @@ wait_negotiated (GstPipeWireSrc *this)
GST_DEBUG_OBJECT (this, "waiting for NEGOTIATED, now %s", pw_stream_state_as_string (state));
if (state == PW_STREAM_STATE_ERROR)
break;
+ if (this->flushing) {
+ state = PW_STREAM_STATE_ERROR;
+ break;
+ }
if (this->negotiated)
break;
diff --git a/src/modules/meson.build b/src/modules/meson.build
index 11b29a117..59f46ae13 100644
--- a/src/modules/meson.build
+++ b/src/modules/meson.build
@@ -46,7 +46,6 @@ module_sources = [
'module-vban-recv.c',
'module-vban-send.c',
'module-session-manager.c',
- 'module-scheduler-v1.c',
'module-zeroconf-discover.c',
'module-roc-source.c',
'module-roc-sink.c',
@@ -296,17 +295,6 @@ pipewire_module_protocol_native = shared_library('pipewire-module-protocol-nativ
dependencies : pipewire_module_protocol_deps,
)
-zeroconf_sources = []
-zeroconf_deps = []
-if avahi_dep.found()
- zeroconf_sources += [
- 'zeroconf-utils/zeroconf.c',
- 'zeroconf-utils/avahi-poll.c',
- ]
- zeroconf_deps += avahi_dep
- cdata.set('HAVE_AVAHI', true)
-endif
-
pipewire_module_protocol_pulse_deps = pipewire_module_protocol_deps
pipewire_module_protocol_pulse_sources = [
@@ -383,9 +371,10 @@ endif
if avahi_dep.found()
pipewire_module_protocol_pulse_sources += [
'module-protocol-pulse/modules/module-zeroconf-publish.c',
+ 'module-zeroconf-discover/avahi-poll.c',
]
- pipewire_module_protocol_pulse_sources += zeroconf_sources
- pipewire_module_protocol_pulse_deps += zeroconf_deps
+ pipewire_module_protocol_pulse_deps += avahi_dep
+ cdata.set('HAVE_AVAHI', true)
endif
if gsettings_gio_dep.found()
@@ -543,15 +532,6 @@ pipewire_module_adapter = shared_library('pipewire-module-adapter',
dependencies : [mathlib, dl_lib, rt_lib, pipewire_dep],
)
-pipewire_module_scheduler_v1 = shared_library('pipewire-module-scheduler-v1',
- [ 'module-scheduler-v1.c' ],
- include_directories : [configinc],
- install : true,
- install_dir : modules_install_dir,
- install_rpath: modules_install_dir,
- dependencies : [mathlib, dl_lib, rt_lib, pipewire_dep],
-)
-
pipewire_module_session_manager = shared_library('pipewire-module-session-manager',
[ 'module-session-manager.c',
'module-session-manager/client-endpoint/client-endpoint.c',
@@ -579,12 +559,12 @@ if build_module_zeroconf_discover
pipewire_module_zeroconf_discover = shared_library('pipewire-module-zeroconf-discover',
[ 'module-zeroconf-discover.c',
'module-protocol-pulse/format.c',
- zeroconf_sources ],
+ 'module-zeroconf-discover/avahi-poll.c' ],
include_directories : [configinc],
install : true,
install_dir : modules_install_dir,
install_rpath: modules_install_dir,
- dependencies : [mathlib, dl_lib, rt_lib, pipewire_dep, zeroconf_deps],
+ dependencies : [mathlib, dl_lib, rt_lib, pipewire_dep, avahi_dep],
)
endif
summary({'zeroconf-discover': build_module_zeroconf_discover}, bool_yn: true, section: 'Optional Modules')
@@ -609,12 +589,12 @@ build_module_raop_discover = avahi_dep.found()
if build_module_raop_discover
pipewire_module_raop_discover = shared_library('pipewire-module-raop-discover',
[ 'module-raop-discover.c',
- zeroconf_sources ],
+ 'module-zeroconf-discover/avahi-poll.c' ],
include_directories : [configinc],
install : true,
install_dir : modules_install_dir,
install_rpath: modules_install_dir,
- dependencies : [mathlib, dl_lib, rt_lib, pipewire_dep, zeroconf_deps],
+ dependencies : [mathlib, dl_lib, rt_lib, pipewire_dep, avahi_dep],
)
endif
summary({'raop-discover (needs Avahi)': build_module_raop_discover}, bool_yn: true, section: 'Optional Modules')
@@ -623,12 +603,12 @@ build_module_snapcast_discover = avahi_dep.found()
if build_module_snapcast_discover
pipewire_module_snapcast_discover = shared_library('pipewire-module-snapcast-discover',
[ 'module-snapcast-discover.c',
- zeroconf_sources ],
+ 'module-zeroconf-discover/avahi-poll.c' ],
include_directories : [configinc],
install : true,
install_dir : modules_install_dir,
install_rpath: modules_install_dir,
- dependencies : [mathlib, dl_lib, rt_lib, pipewire_dep, zeroconf_deps],
+ dependencies : [mathlib, dl_lib, rt_lib, pipewire_dep, avahi_dep],
)
endif
summary({'snapcast-discover (needs Avahi)': build_module_snapcast_discover}, bool_yn: true, section: 'Optional Modules')
@@ -671,13 +651,13 @@ pipewire_module_rtp_sink = shared_library('pipewire-module-rtp-sink',
build_module_rtp_session = avahi_dep.found()
if build_module_rtp_session
pipewire_module_rtp_session = shared_library('pipewire-module-rtp-session',
- [ 'module-rtp-session.c',
- zeroconf_sources ],
+ [ 'module-zeroconf-discover/avahi-poll.c',
+ 'module-rtp-session.c' ],
include_directories : [configinc],
install : true,
install_dir : modules_install_dir,
install_rpath: modules_install_dir,
- dependencies : [pipewire_module_rtp_common_dep, zeroconf_deps],
+ dependencies : [pipewire_module_rtp_common_dep, avahi_dep],
)
endif
@@ -710,35 +690,6 @@ pipewire_module_vban_recv = shared_library('pipewire-module-vban-recv',
dependencies : [mathlib, dl_lib, rt_lib, pipewire_dep],
)
-pipewire_module_sendspin_sources = []
-pipewire_module_sendspin_deps = [ mathlib, dl_lib, rt_lib, pipewire_dep ]
-
-if avahi_dep.found()
- pipewire_module_sendspin_sources += zeroconf_sources
- pipewire_module_sendspin_deps += zeroconf_deps
-endif
-
-pipewire_module_sendspin_recv = shared_library('pipewire-module-sendspin-recv',
- [ 'module-sendspin-recv.c',
- 'module-sendspin/websocket.c',
- pipewire_module_sendspin_sources ],
- include_directories : [configinc],
- install : true,
- install_dir : modules_install_dir,
- install_rpath: modules_install_dir,
- dependencies : pipewire_module_sendspin_deps,
-)
-pipewire_module_sendspin_send = shared_library('pipewire-module-sendspin-send',
- [ 'module-sendspin-send.c',
- 'module-sendspin/websocket.c',
- pipewire_module_sendspin_sources ],
- include_directories : [configinc],
- install : true,
- install_dir : modules_install_dir,
- install_rpath: modules_install_dir,
- dependencies : pipewire_module_sendspin_deps,
-)
-
build_module_roc = roc_dep.found()
if build_module_roc
pipewire_module_roc_sink = shared_library('pipewire-module-roc-sink',
diff --git a/src/modules/module-adapter.c b/src/modules/module-adapter.c
index 3325602ac..9f5474a08 100644
--- a/src/modules/module-adapter.c
+++ b/src/modules/module-adapter.c
@@ -184,7 +184,7 @@ static void *create_object(void *_data,
if (properties == NULL)
goto error_properties;
- pw_properties_setf(properties, PW_KEY_FACTORY_ID, "%u",
+ pw_properties_setf(properties, PW_KEY_FACTORY_ID, "%d",
pw_impl_factory_get_info(d->factory)->id);
linger = pw_properties_get_bool(properties, PW_KEY_OBJECT_LINGER, false);
@@ -196,7 +196,7 @@ static void *create_object(void *_data,
client = resource ? pw_resource_get_client(resource): NULL;
if (client && !linger) {
- pw_properties_setf(properties, PW_KEY_CLIENT_ID, "%u",
+ pw_properties_setf(properties, PW_KEY_CLIENT_ID, "%d",
pw_impl_client_get_info(client)->id);
}
@@ -343,7 +343,7 @@ static void module_registered(void *data)
char id[16];
int res;
- snprintf(id, sizeof(id), "%u", pw_impl_module_get_info(module)->id);
+ snprintf(id, sizeof(id), "%d", pw_impl_module_get_info(module)->id);
items[0] = SPA_DICT_ITEM_INIT(PW_KEY_MODULE_ID, id);
pw_impl_factory_update_properties(factory, &SPA_DICT_INIT(items, 1));
diff --git a/src/modules/module-avb/acmp.c b/src/modules/module-avb/acmp.c
index 73a84ba89..eacfb6133 100644
--- a/src/modules/module-avb/acmp.c
+++ b/src/modules/module-avb/acmp.c
@@ -174,14 +174,13 @@ static int handle_connect_tx_command(struct acmp *acmp, uint64_t now, const void
return 0;
memcpy(buf, m, len);
- AVB_PACKET_ACMP_SET_MESSAGE_TYPE(reply, AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE);
-
stream = find_stream(server, SPA_DIRECTION_OUTPUT, ntohs(reply->talker_unique_id));
if (stream == NULL) {
status = AVB_ACMP_STATUS_TALKER_NO_STREAM_INDEX;
goto done;
}
+ AVB_PACKET_ACMP_SET_MESSAGE_TYPE(reply, AVB_ACMP_MESSAGE_TYPE_CONNECT_TX_RESPONSE);
reply->stream_id = htobe64(stream->id);
stream_activate(stream, ntohs(reply->talker_unique_id), now);
@@ -252,14 +251,14 @@ static int handle_disconnect_tx_command(struct acmp *acmp, uint64_t now, const v
return 0;
memcpy(buf, m, len);
- AVB_PACKET_ACMP_SET_MESSAGE_TYPE(reply, AVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_RESPONSE);
-
stream = find_stream(server, SPA_DIRECTION_OUTPUT, ntohs(reply->talker_unique_id));
if (stream == NULL) {
status = AVB_ACMP_STATUS_TALKER_NO_STREAM_INDEX;
goto done;
}
+ AVB_PACKET_ACMP_SET_MESSAGE_TYPE(reply, AVB_ACMP_MESSAGE_TYPE_DISCONNECT_TX_RESPONSE);
+
stream_deactivate(stream, now);
done:
diff --git a/src/modules/module-avb/aecp-aem-cmds-resps/cmd-lock-entity.c b/src/modules/module-avb/aecp-aem-cmds-resps/cmd-lock-entity.c
index 4b271b7fc..0149d633b 100644
--- a/src/modules/module-avb/aecp-aem-cmds-resps/cmd-lock-entity.c
+++ b/src/modules/module-avb/aecp-aem-cmds-resps/cmd-lock-entity.c
@@ -71,41 +71,6 @@ static int handle_unsol_lock_entity_milanv12(struct aecp *aecp, struct descripto
}
-void handle_cmd_lock_entity_expired_milan_v12(struct aecp *aecp, int64_t now)
-{
- struct server *server = aecp->server;
- struct descriptor *desc;
- struct aecp_aem_entity_milan_state *entity_state;
- struct aecp_aem_lock_state *lock;
-
- desc = server_find_descriptor(server, AVB_AEM_DESC_ENTITY, 0);
- if (desc == NULL)
- return;
-
- entity_state = desc->ptr;
- lock = &entity_state->state.lock_state;
-
- if (!lock->is_locked)
- return;
-
- if (lock->base_info.expire_timeout >= now)
- return;
-
- pw_log_info("entity lock held by %" PRIx64 " expired after %lus, releasing",
- lock->locked_id, AECP_AEM_LOCK_ENTITY_EXPIRE_TIMEOUT_SECOND);
-
- lock->is_locked = false;
- lock->locked_id = 0;
- /*
- * No specific triggering controller (this is a timeout, not a command).
- * Setting controller_entity_id to 0 combined with internal=true ensures
- * reply_unsol_send notifies ALL registered controllers, including the
- * one whose lock just expired.
- */
- lock->base_info.controller_entity_id = 0;
- handle_unsol_lock_common(aecp, lock, true);
-}
-
/* LOCK_ENTITY */
/* Milan v1.2, Sec. 5.4.2.2; IEEE 1722.1-2021, Sec. 7.4.2*/
int handle_cmd_lock_entity_milan_v12(struct aecp *aecp, int64_t now, const void *m, int len)
@@ -134,7 +99,7 @@ int handle_cmd_lock_entity_milan_v12(struct aecp *aecp, int64_t now, const void
desc = server_find_descriptor(server, desc_type, desc_id);
if (desc == NULL)
- return reply_status(aecp, AVB_AECP_AEM_STATUS_NO_SUCH_DESCRIPTOR, m, len);
+ return reply_status(aecp, AVB_AECP_AEM_STATUS_NO_SUCH_DESCRIPTOR, p, len);
entity_state = desc->ptr;
lock = &entity_state->state.lock_state;
@@ -183,7 +148,7 @@ int handle_cmd_lock_entity_milan_v12(struct aecp *aecp, int64_t now, const void
// If the lock is taken again by device
if (ctrler_id == lock->locked_id) {
lock->base_info.expire_timeout +=
- AECP_AEM_LOCK_ENTITY_EXPIRE_TIMEOUT_SECOND * SPA_NSEC_PER_SEC;
+ AECP_AEM_LOCK_ENTITY_EXPIRE_TIMEOUT_SECOND;
lock->is_locked = true;
} else {
diff --git a/src/modules/module-avb/aecp-aem-cmds-resps/cmd-lock-entity.h b/src/modules/module-avb/aecp-aem-cmds-resps/cmd-lock-entity.h
index c83bc464d..dee877a7f 100644
--- a/src/modules/module-avb/aecp-aem-cmds-resps/cmd-lock-entity.h
+++ b/src/modules/module-avb/aecp-aem-cmds-resps/cmd-lock-entity.h
@@ -12,15 +12,6 @@
#include
-/**
- * @brief Checks whether the Milan entity lock has expired and releases it.
- *
- * Called once per second from the AECP periodic handler. If the lock is
- * active and its timeout (set at lock time) is earlier than @p now, the
- * lock is cleared.
- */
-void handle_cmd_lock_entity_expired_milan_v12(struct aecp *aecp, int64_t now);
-
/**
* @brief Command handling will generate the response for the lock command
*/
diff --git a/src/modules/module-avb/aecp-aem.c b/src/modules/module-avb/aecp-aem.c
index 78b3eb818..fccf6b178 100644
--- a/src/modules/module-avb/aecp-aem.c
+++ b/src/modules/module-avb/aecp-aem.c
@@ -5,7 +5,6 @@
#include "aecp-aem.h"
#include "aecp-aem-descriptors.h"
-#include "aecp-aem-state.h"
#include "aecp-aem-cmds-resps/cmd-resp-helpers.h"
#include "utils.h"
@@ -28,8 +27,7 @@ static int handle_acquire_entity_avb_legacy(struct aecp *aecp, int64_t now,
const void *m, int len)
{
struct server *server = aecp->server;
- const struct avb_ethernet_header *h = m;
- const struct avb_packet_aecp_aem *p = SPA_PTROFF(h, sizeof(*h), void);
+ const struct avb_packet_aecp_aem *p = m;
const struct avb_packet_aecp_aem_acquire *ae;
const struct descriptor *desc;
uint16_t desc_type, desc_id;
@@ -55,8 +53,7 @@ static int handle_lock_entity_avb_legacy(struct aecp *aecp, int64_t now,
const void *m, int len)
{
struct server *server = aecp->server;
- const struct avb_ethernet_header *h = m;
- const struct avb_packet_aecp_aem *p = SPA_PTROFF(h, sizeof(*h), void);
+ const struct avb_packet_aecp_aem *p = m;
const struct avb_packet_aecp_aem_acquire *ae;
const struct descriptor *desc;
uint16_t desc_type, desc_id;
@@ -371,44 +368,6 @@ static const struct {
},
};
-/**
- * \brief Stub that queries the AECP entity lock state.
- *
- * Returns true when the entity is currently locked by a *different* controller
- * than the one sending the command, meaning the command must be rejected with
- * ENTITY_LOCKED. Returns false in all other cases (not locked, lock expired,
- * or requester is the lock owner).
- *
- * Only Milan V1.2 entities maintain a lock state; legacy AVB entities always
- * return false (unlocked).
- */
-static bool check_locked(struct aecp *aecp, int64_t now,
- const struct avb_packet_aecp_aem *p)
-{
- struct server *server = aecp->server;
- const struct descriptor *desc;
- const struct aecp_aem_entity_milan_state *entity_state;
- const struct aecp_aem_lock_state *lock;
-
- if (server->avb_mode != AVB_MODE_MILAN_V12)
- return false;
-
- desc = server_find_descriptor(server, AVB_AEM_DESC_ENTITY, 0);
- if (desc == NULL)
- return false;
-
- entity_state = desc->ptr;
- lock = &entity_state->state.lock_state;
-
- /* A lock that has expired is treated as if the entity is unlocked. */
- if (lock->base_info.expire_timeout < now)
- return false;
-
- /* Locked by a different controller → reject. */
- return lock->is_locked &&
- (lock->locked_id != htobe64(p->aecp.controller_guid));
-}
-
int avb_aecp_aem_handle_command(struct aecp *aecp, const void *m, int len)
{
const struct avb_ethernet_header *h = m;
@@ -441,30 +400,9 @@ int avb_aecp_aem_handle_command(struct aecp *aecp, const void *m, int len)
now = SPA_TIMESPEC_TO_NSEC(&ts_now);
- /*
- * For write (non-readonly) commands, check whether the entity is locked
- * by a different controller before dispatching the handler. Readonly
- * commands are always allowed regardless of lock state.
- */
- if (!info->is_readonly && check_locked(aecp, now, p)) {
- pw_log_info("aem command %s rejected: entity locked",
- cmd_names[cmd_type]);
- return reply_entity_locked(aecp, m, len);
- }
-
return info->handle_command(aecp, now, m, len);
}
-void avb_aecp_aem_periodic(struct aecp *aecp, int64_t now)
-{
- struct server *server = aecp->server;
-
- if (server->avb_mode != AVB_MODE_MILAN_V12)
- return;
-
- handle_cmd_lock_entity_expired_milan_v12(aecp, now);
-}
-
int avb_aecp_aem_handle_response(struct aecp *aecp, const void *m, int len)
{
return 0;
diff --git a/src/modules/module-avb/aecp-aem.h b/src/modules/module-avb/aecp-aem.h
index e4e120452..507d0f868 100644
--- a/src/modules/module-avb/aecp-aem.h
+++ b/src/modules/module-avb/aecp-aem.h
@@ -249,6 +249,5 @@ struct avb_packet_aecp_aem {
int avb_aecp_aem_handle_command(struct aecp *aecp, const void *m, int len);
int avb_aecp_aem_handle_response(struct aecp *aecp, const void *m, int len);
-void avb_aecp_aem_periodic(struct aecp *aecp, int64_t now);
#endif /* AVB_AEM_H */
diff --git a/src/modules/module-avb/aecp.c b/src/modules/module-avb/aecp.c
index 6a15f87a9..6e6a1ba43 100644
--- a/src/modules/module-avb/aecp.c
+++ b/src/modules/module-avb/aecp.c
@@ -86,12 +86,6 @@ static int aecp_message(void *data, uint64_t now, const void *message, int len)
return info->handle(aecp, message, len);
}
-static void aecp_periodic(void *data, uint64_t now)
-{
- struct aecp *aecp = data;
- avb_aecp_aem_periodic(aecp, (int64_t)now);
-}
-
static void aecp_destroy(void *data)
{
struct aecp *aecp = data;
@@ -130,7 +124,6 @@ static const struct server_events server_events = {
AVB_VERSION_SERVER_EVENTS,
.destroy = aecp_destroy,
.message = aecp_message,
- .periodic = aecp_periodic,
.command = aecp_command
};
diff --git a/src/modules/module-avb/avb-transport-loopback.h b/src/modules/module-avb/avb-transport-loopback.h
deleted file mode 100644
index 18508b99a..000000000
--- a/src/modules/module-avb/avb-transport-loopback.h
+++ /dev/null
@@ -1,184 +0,0 @@
-/* AVB support */
-/* SPDX-FileCopyrightText: Copyright © 2026 PipeWire contributors */
-/* SPDX-License-Identifier: MIT */
-
-#ifndef AVB_TRANSPORT_LOOPBACK_H
-#define AVB_TRANSPORT_LOOPBACK_H
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "internal.h"
-#include "packets.h"
-
-#define AVB_LOOPBACK_MAX_PACKETS 64
-#define AVB_LOOPBACK_MAX_PACKET_SIZE 2048
-
-struct avb_loopback_packet {
- uint8_t dest[6];
- uint16_t type;
- size_t size;
- uint8_t data[AVB_LOOPBACK_MAX_PACKET_SIZE];
-};
-
-struct avb_loopback_transport {
- struct avb_loopback_packet packets[AVB_LOOPBACK_MAX_PACKETS];
- int packet_count;
- int packet_read;
-};
-
-static inline int avb_loopback_setup(struct server *server)
-{
- struct avb_loopback_transport *t;
- static const uint8_t test_mac[6] = { 0x02, 0x00, 0x00, 0x00, 0x00, 0x01 };
-
- t = calloc(1, sizeof(*t));
- if (t == NULL)
- return -errno;
-
- server->transport_data = t;
-
- memcpy(server->mac_addr, test_mac, 6);
- server->ifindex = 1;
- server->entity_id = (uint64_t)server->mac_addr[0] << 56 |
- (uint64_t)server->mac_addr[1] << 48 |
- (uint64_t)server->mac_addr[2] << 40 |
- (uint64_t)0xff << 32 |
- (uint64_t)0xfe << 24 |
- (uint64_t)server->mac_addr[3] << 16 |
- (uint64_t)server->mac_addr[4] << 8 |
- (uint64_t)server->mac_addr[5];
-
- return 0;
-}
-
-static inline int avb_loopback_send_packet(struct server *server,
- const uint8_t dest[6], uint16_t type, void *data, size_t size)
-{
- struct avb_loopback_transport *t = server->transport_data;
- struct avb_loopback_packet *pkt;
- struct avb_ethernet_header *hdr = (struct avb_ethernet_header*)data;
-
- if (t->packet_count >= AVB_LOOPBACK_MAX_PACKETS)
- return -ENOSPC;
- if (size > AVB_LOOPBACK_MAX_PACKET_SIZE)
- return -EMSGSIZE;
-
- /* Fill in the ethernet header like the raw transport does */
- memcpy(hdr->dest, dest, 6);
- memcpy(hdr->src, server->mac_addr, 6);
- hdr->type = htons(type);
-
- pkt = &t->packets[t->packet_count % AVB_LOOPBACK_MAX_PACKETS];
- memcpy(pkt->dest, dest, 6);
- pkt->type = type;
- pkt->size = size;
- memcpy(pkt->data, data, size);
- t->packet_count++;
-
- return 0;
-}
-
-/**
- * Return a dummy fd for protocol handlers that create their own sockets.
- * Uses eventfd so pw_loop_add_io() has a valid fd to work with.
- */
-static inline int avb_loopback_make_socket(struct server *server,
- uint16_t type, const uint8_t mac[6])
-{
- int fd;
-
- fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
- if (fd < 0)
- return -errno;
-
- return fd;
-}
-
-static inline void avb_loopback_destroy(struct server *server)
-{
- free(server->transport_data);
- server->transport_data = NULL;
-}
-
-/**
- * Create a dummy stream socket using eventfd.
- * No AF_PACKET, no ioctls, no privileges needed.
- */
-static inline int avb_loopback_stream_setup_socket(struct server *server,
- struct stream *stream)
-{
- int fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
- if (fd < 0)
- return -errno;
-
- spa_zero(stream->sock_addr);
- stream->sock_addr.sll_family = AF_PACKET;
- stream->sock_addr.sll_halen = ETH_ALEN;
-
- return fd;
-}
-
-/**
- * No-op stream send — pretend the send succeeded.
- * Audio data is consumed from the ringbuffer but goes nowhere.
- */
-static inline ssize_t avb_loopback_stream_send(struct server *server,
- struct stream *stream, struct msghdr *msg, int flags)
-{
- ssize_t total = 0;
- for (size_t i = 0; i < msg->msg_iovlen; i++)
- total += msg->msg_iov[i].iov_len;
- return total;
-}
-
-static const struct avb_transport_ops avb_transport_loopback = {
- .setup = avb_loopback_setup,
- .send_packet = avb_loopback_send_packet,
- .make_socket = avb_loopback_make_socket,
- .destroy = avb_loopback_destroy,
- .stream_setup_socket = avb_loopback_stream_setup_socket,
- .stream_send = avb_loopback_stream_send,
-};
-
-/** Get the number of captured sent packets */
-static inline int avb_loopback_get_packet_count(struct server *server)
-{
- struct avb_loopback_transport *t = server->transport_data;
- return t->packet_count - t->packet_read;
-}
-
-/** Read the next captured sent packet, returns packet size or -1 */
-static inline int avb_loopback_get_packet(struct server *server,
- void *buf, size_t bufsize)
-{
- struct avb_loopback_transport *t = server->transport_data;
- struct avb_loopback_packet *pkt;
-
- if (t->packet_read >= t->packet_count)
- return -1;
-
- pkt = &t->packets[t->packet_read % AVB_LOOPBACK_MAX_PACKETS];
- t->packet_read++;
-
- if (pkt->size > bufsize)
- return -1;
-
- memcpy(buf, pkt->data, pkt->size);
- return pkt->size;
-}
-
-/** Clear all captured packets */
-static inline void avb_loopback_clear_packets(struct server *server)
-{
- struct avb_loopback_transport *t = server->transport_data;
- t->packet_count = 0;
- t->packet_read = 0;
-}
-
-#endif /* AVB_TRANSPORT_LOOPBACK_H */
diff --git a/src/modules/module-avb/avdecc.c b/src/modules/module-avb/avdecc.c
index 8729d6421..7cd7e8e7a 100644
--- a/src/modules/module-avb/avdecc.c
+++ b/src/modules/module-avb/avdecc.c
@@ -84,7 +84,7 @@ static void on_socket_data(void *data, int fd, uint32_t mask)
}
}
-static int raw_send_packet(struct server *server, const uint8_t dest[6],
+int avb_server_send_packet(struct server *server, const uint8_t dest[6],
uint16_t type, void *data, size_t size)
{
struct avb_ethernet_header *hdr = (struct avb_ethernet_header*)data;
@@ -101,12 +101,6 @@ static int raw_send_packet(struct server *server, const uint8_t dest[6],
return res;
}
-int avb_server_send_packet(struct server *server, const uint8_t dest[6],
- uint16_t type, void *data, size_t size)
-{
- return server->transport->send_packet(server, dest, type, data, size);
-}
-
static int load_filter(int fd, uint16_t eth, const uint8_t dest[6], const uint8_t mac[6])
{
struct sock_fprog filter;
@@ -142,7 +136,7 @@ static int load_filter(int fd, uint16_t eth, const uint8_t dest[6], const uint8_
return 0;
}
-static int raw_make_socket(struct server *server, uint16_t type, const uint8_t mac[6])
+int avb_server_make_socket(struct server *server, uint16_t type, const uint8_t mac[6])
{
int fd, res;
struct ifreq req;
@@ -215,20 +209,13 @@ error_close:
return res;
}
-int avb_server_make_socket(struct server *server, uint16_t type, const uint8_t mac[6])
-{
- if (server->transport && server->transport->make_socket)
- return server->transport->make_socket(server, type, mac);
- return raw_make_socket(server, type, mac);
-}
-
-static int raw_transport_setup(struct server *server)
+static int setup_socket(struct server *server)
{
struct impl *impl = server->impl;
int fd, res;
static const uint8_t bmac[6] = AVB_BROADCAST_MAC;
- fd = raw_make_socket(server, AVB_TSN_ETH, bmac);
+ fd = avb_server_make_socket(server, AVB_TSN_ETH, bmac);
if (fd < 0)
return fd;
@@ -257,119 +244,6 @@ error_no_source:
return res;
}
-static int raw_stream_setup_socket(struct server *server, struct stream *stream)
-{
- int fd, res;
- char buf[128];
- struct ifreq req;
-
- fd = socket(AF_PACKET, SOCK_RAW | SOCK_NONBLOCK, htons(ETH_P_ALL));
- if (fd < 0) {
- pw_log_error("socket() failed: %m");
- return -errno;
- }
-
- spa_zero(req);
- snprintf(req.ifr_name, sizeof(req.ifr_name), "%s", server->ifname);
- res = ioctl(fd, SIOCGIFINDEX, &req);
- if (res < 0) {
- pw_log_error("SIOCGIFINDEX %s failed: %m", server->ifname);
- res = -errno;
- goto error_close;
- }
-
- spa_zero(stream->sock_addr);
- stream->sock_addr.sll_family = AF_PACKET;
- stream->sock_addr.sll_protocol = htons(ETH_P_TSN);
- stream->sock_addr.sll_ifindex = req.ifr_ifindex;
-
- if (stream->direction == SPA_DIRECTION_OUTPUT) {
- struct sock_txtime txtime_cfg;
-
- res = setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &stream->prio,
- sizeof(stream->prio));
- if (res < 0) {
- pw_log_error("setsockopt(SO_PRIORITY %d) failed: %m", stream->prio);
- res = -errno;
- goto error_close;
- }
-
- txtime_cfg.clockid = CLOCK_TAI;
- txtime_cfg.flags = 0;
- res = setsockopt(fd, SOL_SOCKET, SO_TXTIME, &txtime_cfg,
- sizeof(txtime_cfg));
- if (res < 0) {
- pw_log_error("setsockopt(SO_TXTIME) failed: %m");
- res = -errno;
- goto error_close;
- }
- } else {
- struct packet_mreq mreq;
-
- res = bind(fd, (struct sockaddr *) &stream->sock_addr, sizeof(stream->sock_addr));
- if (res < 0) {
- pw_log_error("bind() failed: %m");
- res = -errno;
- goto error_close;
- }
-
- spa_zero(mreq);
- mreq.mr_ifindex = req.ifr_ifindex;
- mreq.mr_type = PACKET_MR_MULTICAST;
- mreq.mr_alen = ETH_ALEN;
- memcpy(&mreq.mr_address, stream->addr, ETH_ALEN);
- res = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
- &mreq, sizeof(struct packet_mreq));
-
- pw_log_info("join %s", avb_utils_format_addr(buf, 128, stream->addr));
-
- if (res < 0) {
- pw_log_error("setsockopt(ADD_MEMBERSHIP) failed: %m");
- res = -errno;
- goto error_close;
- }
- }
- return fd;
-
-error_close:
- close(fd);
- return res;
-}
-
-static ssize_t raw_stream_send(struct server *server, struct stream *stream,
- struct msghdr *msg, int flags)
-{
- return sendmsg(stream->source->fd, msg, flags);
-}
-
-int avb_server_stream_setup_socket(struct server *server, struct stream *stream)
-{
- return server->transport->stream_setup_socket(server, stream);
-}
-
-ssize_t avb_server_stream_send(struct server *server, struct stream *stream,
- struct msghdr *msg, int flags)
-{
- return server->transport->stream_send(server, stream, msg, flags);
-}
-
-static void raw_transport_destroy(struct server *server)
-{
- struct impl *impl = server->impl;
- if (server->source)
- pw_loop_destroy_source(impl->loop, server->source);
- server->source = NULL;
-}
-
-const struct avb_transport_ops avb_transport_raw = {
- .setup = raw_transport_setup,
- .send_packet = raw_send_packet,
- .make_socket = raw_make_socket,
- .destroy = raw_transport_destroy,
- .stream_setup_socket = raw_stream_setup_socket,
- .stream_send = raw_stream_send,
-};
-
struct server *avdecc_server_new(struct impl *impl, struct spa_dict *props)
{
struct server *server;
@@ -392,14 +266,10 @@ struct server *avdecc_server_new(struct impl *impl, struct spa_dict *props)
spa_hook_list_init(&server->listener_list);
spa_list_init(&server->descriptors);
- spa_list_init(&server->streams);
server->debug_messages = false;
- if (server->transport == NULL)
- server->transport = &avb_transport_raw;
-
- if ((res = server->transport->setup(server)) < 0)
+ if ((res = setup_socket(server)) < 0)
goto error_free;
@@ -445,10 +315,12 @@ void avdecc_server_add_listener(struct server *server, struct spa_hook *listener
void avdecc_server_free(struct server *server)
{
+ struct impl *impl = server->impl;
+
server_destroy_descriptors(server);
spa_list_remove(&server->link);
- if (server->transport)
- server->transport->destroy(server);
+ if (server->source)
+ pw_loop_destroy_source(impl->loop, server->source);
pw_timer_queue_cancel(&server->timer);
spa_hook_list_clean(&server->listener_list);
free(server->ifname);
diff --git a/src/modules/module-avb/descriptors.c b/src/modules/module-avb/descriptors.c
index 1781ef8af..c55e6f2d6 100644
--- a/src/modules/module-avb/descriptors.c
+++ b/src/modules/module-avb/descriptors.c
@@ -29,7 +29,7 @@ static void init_descriptor_legacy_avb(struct server *server)
&(struct avb_aem_desc_locale)
{
.locale_identifier = "en-EN",
- .number_of_strings = htons(3),
+ .number_of_strings = htons(1),
.base_strings = htons(0)
});
@@ -43,6 +43,7 @@ static void init_descriptor_legacy_avb(struct server *server)
AVB_ADP_ENTITY_CAPABILITY_AEM_SUPPORTED |
AVB_ADP_ENTITY_CAPABILITY_CLASS_A_SUPPORTED |
AVB_ADP_ENTITY_CAPABILITY_GPTP_SUPPORTED |
+ AVB_ADP_ENTITY_CAPABILITY_AEM_IDENTIFY_CONTROL_INDEX_VALID |
AVB_ADP_ENTITY_CAPABILITY_AEM_INTERFACE_INDEX_VALID),
.talker_stream_sources = htons(8),
diff --git a/src/modules/module-avb/es-builder.c b/src/modules/module-avb/es-builder.c
index 2611e73e6..adcc6b930 100644
--- a/src/modules/module-avb/es-builder.c
+++ b/src/modules/module-avb/es-builder.c
@@ -18,7 +18,7 @@
*/
/** The callback type used for the different entity descriptor */
-typedef struct descriptor *(*es_builder_cb_t) (struct server *server, uint16_t type,
+typedef void* (*es_builder_cb_t) (struct server *server, uint16_t type,
uint16_t index, size_t size, void *ptr);
/** Structure holding all necessary cb
@@ -36,33 +36,33 @@ struct es_builder_st {
* \brief The Entity keeps track of multiple things, the locks the current
* configuration use for instance. That tragets the Milan V1.2 mode only
*/
-static struct descriptor *es_builder_desc_entity_milan_v12(struct server *server,
+static void *es_builder_desc_entity_milan_v12(struct server *server,
uint16_t type, uint16_t index, size_t size, void *ptr)
{
struct aecp_aem_entity_milan_state entity_state = {0};
- struct descriptor *desc;
+ void *ptr_alloc;
struct aecp_aem_entity_state *state =
(struct aecp_aem_entity_state *) &entity_state;
memcpy(&state->desc, ptr, size);
- desc = server_add_descriptor(server, type, index, sizeof(entity_state),
+ ptr_alloc = server_add_descriptor(server, type, index, sizeof(entity_state),
&entity_state);
- if (!desc) {
- pw_log_error("Error during allocation\n");
+ if (!ptr_alloc) {
+ pw_log_error("Error durring allocation\n");
spa_assert(0);
}
- return desc;
+ return ptr_alloc;
}
/**
* \brief A generic function to avoid code duplicate for the streams */
-static struct descriptor *es_buidler_desc_stream_general_prepare(struct server *server,
- uint16_t type, uint16_t index, size_t size, void *ptr)
+static void *es_buidler_desc_stream_general_prepare(struct server *server,
+ uint16_t type, uint16_t index, size_t size, void *ptr)
{
- struct descriptor *desc;
+ void *ptr_alloc;
struct stream *stream;
enum spa_direction direction;
@@ -72,14 +72,14 @@ static struct descriptor *es_buidler_desc_stream_general_prepare(struct server *
struct aecp_aem_stream_input_state stream_input = { 0 };
memcpy(&stream_input.desc, ptr, size);
- desc = server_add_descriptor(server, type, index,
+ ptr_alloc = server_add_descriptor(server, type, index,
sizeof(stream_input), &stream_input);
- if (!desc) {
+ if (!ptr_alloc) {
pw_log_error("Allocation failed\n");
return NULL;
}
- pstream_input = desc->ptr;
+ pstream_input = ptr_alloc;
stream = &pstream_input->stream;
direction = SPA_DIRECTION_INPUT;
break;
@@ -88,14 +88,14 @@ static struct descriptor *es_buidler_desc_stream_general_prepare(struct server *
struct aecp_aem_stream_output_state stream_output = { 0 };
memcpy(&stream_output.desc, ptr, size);
- desc = server_add_descriptor(server, type, index,
+ ptr_alloc = server_add_descriptor(server, type, index,
sizeof(stream_output), &stream_output);
- if (!desc) {
+ if (!ptr_alloc) {
pw_log_error("Allocation failed\n");
return NULL;
}
- pstream_output = desc->ptr;
+ pstream_output = ptr_alloc;
stream = &pstream_output->stream;
direction = SPA_DIRECTION_OUTPUT;
@@ -105,17 +105,15 @@ static struct descriptor *es_buidler_desc_stream_general_prepare(struct server *
return NULL;
}
- /**
- * In this place the stream register interanlly SRP / MVRP state machines
- */
if (!server_create_stream(server, stream, direction, index)) {
pw_log_error("Could not create/initialize a stream");
return NULL;
}
- return desc;
+ return ptr_alloc;
}
+
// Assign a ID to an specific builder
#define HELPER_ES_BUIDLER(type, callback) \
[type] = { .build_descriptor_cb = callback }
@@ -163,7 +161,8 @@ void es_builder_add_descriptor(struct server *server, uint16_t type,
uint16_t index, size_t size, void *ptr_aem)
{
const struct es_builder_st *es_builder;
- struct descriptor *desc;
+ void *desc_ptr;
+ struct descriptor *d;
enum avb_mode avb_mode;
bool std_processing = false;
@@ -196,9 +195,9 @@ void es_builder_add_descriptor(struct server *server, uint16_t type,
spa_assert(0);
}
} else {
- desc = es_builder[type].build_descriptor_cb(server, type,
+ desc_ptr = es_builder[type].build_descriptor_cb(server, type,
index, size, ptr_aem);
- if (!desc) {
+ if (!desc_ptr) {
pw_log_error("Could not allocate specific descriptr "
"%u at index %u the avb aem type\n",
type, index);
@@ -206,6 +205,7 @@ void es_builder_add_descriptor(struct server *server, uint16_t type,
spa_assert(0);
}
- desc->size = size;
+ d = (struct descriptor *) desc_ptr;
+ d->size = size;
}
}
diff --git a/src/modules/module-avb/internal.h b/src/modules/module-avb/internal.h
index bb4961674..82ced2f21 100644
--- a/src/modules/module-avb/internal.h
+++ b/src/modules/module-avb/internal.h
@@ -5,8 +5,6 @@
#ifndef AVB_INTERNAL_H
#define AVB_INTERNAL_H
-#include
-
#include
#ifdef __cplusplus
@@ -19,22 +17,6 @@ struct avb_mrp;
#define AVB_TSN_ETH 0x22f0
#define AVB_BROADCAST_MAC { 0x91, 0xe0, 0xf0, 0x01, 0x00, 0x00 };
-struct stream;
-
-struct avb_transport_ops {
- int (*setup)(struct server *server);
- int (*send_packet)(struct server *server, const uint8_t dest[6],
- uint16_t type, void *data, size_t size);
- int (*make_socket)(struct server *server, uint16_t type,
- const uint8_t mac[6]);
- void (*destroy)(struct server *server);
-
- /* stream data plane ops */
- int (*stream_setup_socket)(struct server *server, struct stream *stream);
- ssize_t (*stream_send)(struct server *server, struct stream *stream,
- struct msghdr *msg, int flags);
-};
-
struct impl {
struct pw_loop *loop;
struct pw_timer_queue *timer_queue;
@@ -95,16 +77,12 @@ struct server {
uint64_t entity_id;
int ifindex;
- const struct avb_transport_ops *transport;
- void *transport_data;
-
struct spa_source *source;
struct pw_timer timer;
struct spa_hook_list listener_list;
struct spa_list descriptors;
- struct spa_list streams;
unsigned debug_messages:1;
@@ -124,6 +102,7 @@ static inline void server_destroy_descriptors(struct server *server)
struct descriptor *d, *t;
spa_list_for_each_safe(d, t, &server->descriptors, link) {
+ free(d->ptr);
spa_list_remove(&d->link);
free(d);
}
@@ -166,17 +145,11 @@ void avdecc_server_free(struct server *server);
void avdecc_server_add_listener(struct server *server, struct spa_hook *listener,
const struct server_events *events, void *data);
-extern const struct avb_transport_ops avb_transport_raw;
-
int avb_server_make_socket(struct server *server, uint16_t type, const uint8_t mac[6]);
int avb_server_send_packet(struct server *server, const uint8_t dest[6],
uint16_t type, void *data, size_t size);
-int avb_server_stream_setup_socket(struct server *server, struct stream *stream);
-ssize_t avb_server_stream_send(struct server *server, struct stream *stream,
- struct msghdr *msg, int flags);
-
struct aecp {
struct server *server;
struct spa_hook server_listener;
diff --git a/src/modules/module-avb/mrp.c b/src/modules/module-avb/mrp.c
index c6505d41b..73d5275ca 100644
--- a/src/modules/module-avb/mrp.c
+++ b/src/modules/module-avb/mrp.c
@@ -302,8 +302,6 @@ const char *avb_mrp_notify_name(uint8_t notify)
const char *avb_mrp_send_name(uint8_t send)
{
switch(send) {
- case 0:
- return "none";
case AVB_MRP_SEND_NEW:
return "new";
case AVB_MRP_SEND_JOININ:
diff --git a/src/modules/module-avb/mrp.h b/src/modules/module-avb/mrp.h
index 399343267..78683412c 100644
--- a/src/modules/module-avb/mrp.h
+++ b/src/modules/module-avb/mrp.h
@@ -88,13 +88,13 @@ struct avb_packet_mrp_footer {
#define AVB_MRP_ATTRIBUTE_EVENT_LV 5
#define AVB_MRP_ATTRIBUTE_EVENT_LVA 6
-#define AVB_MRP_SEND_NEW 1
-#define AVB_MRP_SEND_JOININ 2
-#define AVB_MRP_SEND_IN 3
-#define AVB_MRP_SEND_JOINMT 4
-#define AVB_MRP_SEND_MT 5
-#define AVB_MRP_SEND_LV 6
-#define AVB_MRP_SEND_LVA 7
+#define AVB_MRP_SEND_NEW 0
+#define AVB_MRP_SEND_JOININ 1
+#define AVB_MRP_SEND_IN 2
+#define AVB_MRP_SEND_JOINMT 3
+#define AVB_MRP_SEND_MT 4
+#define AVB_MRP_SEND_LV 5
+#define AVB_MRP_SEND_LVA 6
#define AVB_MRP_NOTIFY_NEW 1
#define AVB_MRP_NOTIFY_JOIN 2
diff --git a/src/modules/module-avb/msrp.c b/src/modules/module-avb/msrp.c
index 611ddd537..92d1e65b4 100644
--- a/src/modules/module-avb/msrp.c
+++ b/src/modules/module-avb/msrp.c
@@ -91,7 +91,7 @@ static int encode_talker(struct msrp *msrp, struct attr *a, void *m)
*t = a->attr.attr.talker;
ev = SPA_PTROFF(t, sizeof(*t), uint8_t);
- *ev = (a->attr.mrp->pending_send - 1) * 6 * 6;
+ *ev = a->attr.mrp->pending_send * 6 * 6;
f = SPA_PTROFF(ev, sizeof(*ev), struct avb_packet_mrp_footer);
f->end_mark = 0;
@@ -170,7 +170,7 @@ static int encode_listener(struct msrp *msrp, struct attr *a, void *m)
*l = a->attr.attr.listener;
ev = SPA_PTROFF(l, sizeof(*l), uint8_t);
- *ev = (a->attr.mrp->pending_send - 1) * 6 * 6;
+ *ev = a->attr.mrp->pending_send * 6 * 6;
ev = SPA_PTROFF(ev, sizeof(*ev), uint8_t);
*ev = a->attr.param * 4 * 4 * 4;
@@ -226,7 +226,7 @@ static int encode_domain(struct msrp *msrp, struct attr *a, void *m)
*d = a->attr.attr.domain;
ev = SPA_PTROFF(d, sizeof(*d), uint8_t);
- *ev = (a->attr.mrp->pending_send - 1) * 36;
+ *ev = a->attr.mrp->pending_send * 36;
f = SPA_PTROFF(ev, sizeof(*ev), struct avb_packet_mrp_footer);
f->end_mark = 0;
@@ -332,8 +332,7 @@ static void msrp_notify(void *data, uint64_t now, uint8_t notify)
{
struct attr *a = data;
struct msrp *msrp = a->msrp;
- if (dispatch[a->attr.type].notify)
- dispatch[a->attr.type].notify(msrp, now, a, notify);
+ return dispatch[a->attr.type].notify(msrp, now, a, notify);
}
static const struct avb_mrp_attribute_events mrp_attr_events = {
diff --git a/src/modules/module-avb/mvrp.c b/src/modules/module-avb/mvrp.c
index e2e501a9e..20862c2ae 100644
--- a/src/modules/module-avb/mvrp.c
+++ b/src/modules/module-avb/mvrp.c
@@ -84,7 +84,7 @@ static int encode_vid(struct mvrp *mvrp, struct attr *a, void *m)
*d = a->attr.attr.vid;
ev = SPA_PTROFF(d, sizeof(*d), uint8_t);
- *ev = (a->attr.mrp->pending_send - 1) * 36;
+ *ev = a->attr.mrp->pending_send * 36;
f = SPA_PTROFF(ev, sizeof(*ev), struct avb_packet_mrp_footer);
f->end_mark = 0;
@@ -171,8 +171,7 @@ static void mvrp_notify(void *data, uint64_t now, uint8_t notify)
{
struct attr *a = data;
struct mvrp *mvrp = a->mvrp;
- if (dispatch[a->attr.type].notify)
- dispatch[a->attr.type].notify(mvrp, now, a, notify);
+ return dispatch[a->attr.type].notify(mvrp, now, a, notify);
}
static const struct avb_mrp_attribute_events mrp_attr_events = {
diff --git a/src/modules/module-avb/stream.c b/src/modules/module-avb/stream.c
index 26a3a795b..f7101bdf0 100644
--- a/src/modules/module-avb/stream.c
+++ b/src/modules/module-avb/stream.c
@@ -116,10 +116,9 @@ static int flush_write(struct stream *stream, uint64_t current_time)
p->timestamp = ptime;
p->dbc = dbc;
- n = avb_server_stream_send(stream->server, stream,
- &stream->msg, MSG_NOSIGNAL);
+ n = sendmsg(stream->source->fd, &stream->msg, MSG_NOSIGNAL);
if (n < 0 || n != (ssize_t)stream->pdu_size) {
- pw_log_error("stream send failed %zd != %zd: %m",
+ pw_log_error("sendmsg() failed %zd != %zd: %m",
n, stream->pdu_size);
}
txtime += stream->pdu_period;
@@ -332,8 +331,6 @@ struct stream *server_create_stream(struct server *server, struct stream *stream
stream->talker_attr->attr.talker.rank = AVB_MSRP_RANK_DEFAULT;
stream->talker_attr->attr.talker.accumulated_latency = htonl(95);
- spa_list_append(&server->streams, &stream->link);
-
return stream;
error_free_stream:
@@ -351,7 +348,82 @@ void stream_destroy(struct stream *stream)
static int setup_socket(struct stream *stream)
{
- return avb_server_stream_setup_socket(stream->server, stream);
+ struct server *server = stream->server;
+ int fd, res;
+ char buf[128];
+ struct ifreq req;
+
+ fd = socket(AF_PACKET, SOCK_RAW | SOCK_NONBLOCK, htons(ETH_P_ALL));
+ if (fd < 0) {
+ pw_log_error("socket() failed: %m");
+ return -errno;
+ }
+
+ spa_zero(req);
+ snprintf(req.ifr_name, sizeof(req.ifr_name), "%s", server->ifname);
+ res = ioctl(fd, SIOCGIFINDEX, &req);
+ if (res < 0) {
+ pw_log_error("SIOCGIFINDEX %s failed: %m", server->ifname);
+ res = -errno;
+ goto error_close;
+ }
+
+ spa_zero(stream->sock_addr);
+ stream->sock_addr.sll_family = AF_PACKET;
+ stream->sock_addr.sll_protocol = htons(ETH_P_TSN);
+ stream->sock_addr.sll_ifindex = req.ifr_ifindex;
+
+ if (stream->direction == SPA_DIRECTION_OUTPUT) {
+ struct sock_txtime txtime_cfg;
+
+ res = setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &stream->prio,
+ sizeof(stream->prio));
+ if (res < 0) {
+ pw_log_error("setsockopt(SO_PRIORITY %d) failed: %m", stream->prio);
+ res = -errno;
+ goto error_close;
+ }
+
+ txtime_cfg.clockid = CLOCK_TAI;
+ txtime_cfg.flags = 0;
+ res = setsockopt(fd, SOL_SOCKET, SO_TXTIME, &txtime_cfg,
+ sizeof(txtime_cfg));
+ if (res < 0) {
+ pw_log_error("setsockopt(SO_TXTIME) failed: %m");
+ res = -errno;
+ goto error_close;
+ }
+ } else {
+ struct packet_mreq mreq;
+
+ res = bind(fd, (struct sockaddr *) &stream->sock_addr, sizeof(stream->sock_addr));
+ if (res < 0) {
+ pw_log_error("bind() failed: %m");
+ res = -errno;
+ goto error_close;
+ }
+
+ spa_zero(mreq);
+ mreq.mr_ifindex = req.ifr_ifindex;
+ mreq.mr_type = PACKET_MR_MULTICAST;
+ mreq.mr_alen = ETH_ALEN;
+ memcpy(&mreq.mr_address, stream->addr, ETH_ALEN);
+ res = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
+ &mreq, sizeof(struct packet_mreq));
+
+ pw_log_info("join %s", avb_utils_format_addr(buf, 128, stream->addr));
+
+ if (res < 0) {
+ pw_log_error("setsockopt(ADD_MEMBERSHIP) failed: %m");
+ res = -errno;
+ goto error_close;
+ }
+ }
+ return fd;
+
+error_close:
+ close(fd);
+ return res;
}
static void handle_iec61883_packet(struct stream *stream,
@@ -476,24 +548,3 @@ int stream_deactivate(struct stream *stream, uint64_t now)
}
return 0;
}
-
-int stream_activate_virtual(struct stream *stream, uint16_t index)
-{
- struct server *server = stream->server;
- int fd;
-
- if (stream->source == NULL) {
- fd = setup_socket(stream);
- if (fd < 0)
- return fd;
-
- stream->source = pw_loop_add_io(server->impl->loop, fd,
- SPA_IO_IN, true, on_socket_data, stream);
- if (stream->source == NULL) {
- close(fd);
- return -errno;
- }
- }
- pw_stream_set_active(stream->stream, true);
- return 0;
-}
diff --git a/src/modules/module-avb/stream.h b/src/modules/module-avb/stream.h
index 4cc02ddd3..f650cc216 100644
--- a/src/modules/module-avb/stream.h
+++ b/src/modules/module-avb/stream.h
@@ -78,6 +78,5 @@ void stream_destroy(struct stream *stream);
int stream_activate(struct stream *stream, uint16_t index, uint64_t now);
int stream_deactivate(struct stream *stream, uint64_t now);
-int stream_activate_virtual(struct stream *stream, uint16_t index);
#endif /* AVB_STREAM_H */
diff --git a/src/modules/module-client-device.c b/src/modules/module-client-device.c
index 658276eb9..c02a4058f 100644
--- a/src/modules/module-client-device.c
+++ b/src/modules/module-client-device.c
@@ -135,9 +135,9 @@ static void *create_object(void *_data,
goto error_properties;
}
- pw_properties_setf(properties, PW_KEY_FACTORY_ID, "%u",
+ pw_properties_setf(properties, PW_KEY_FACTORY_ID, "%d",
pw_global_get_id(pw_impl_factory_get_global(factory)));
- pw_properties_setf(properties, PW_KEY_CLIENT_ID, "%u",
+ pw_properties_setf(properties, PW_KEY_CLIENT_ID, "%d",
pw_global_get_id(pw_impl_client_get_global(client)));
result = pw_client_device_new(device_resource, properties);
diff --git a/src/modules/module-client-device/resource-device.c b/src/modules/module-client-device/resource-device.c
index 8b3ddea99..ca00bfef9 100644
--- a/src/modules/module-client-device/resource-device.c
+++ b/src/modules/module-client-device/resource-device.c
@@ -108,7 +108,7 @@ struct pw_impl_device *pw_client_device_new(struct pw_resource *resource,
if (properties == NULL)
return NULL;
- pw_properties_setf(properties, PW_KEY_CLIENT_ID, "%u",
+ pw_properties_setf(properties, PW_KEY_CLIENT_ID, "%d",
pw_impl_client_get_info(client)->id);
device = pw_context_create_device(context, properties, sizeof(struct impl));
diff --git a/src/modules/module-client-node/client-node.c b/src/modules/module-client-node/client-node.c
index 1e104429c..9740e1c89 100644
--- a/src/modules/module-client-node/client-node.c
+++ b/src/modules/module-client-node/client-node.c
@@ -92,6 +92,7 @@ struct impl {
struct spa_node node;
+ struct spa_log *log;
struct spa_loop *data_loop;
struct spa_system *data_system;
@@ -282,7 +283,7 @@ static int clear_buffers(struct impl *impl, struct mix *mix)
for (i = 0; i < mix->n_buffers; i++) {
struct buffer *b = &mix->buffers[i];
- pw_log_debug("%p: clear buffer %d", impl, i);
+ spa_log_debug(impl->log, "%p: clear buffer %d", impl, i);
clear_buffer(impl, &b->buffer);
pw_memblock_unref(b->mem);
}
@@ -299,7 +300,7 @@ static void free_mix(struct port *p, struct mix *mix)
if (mix->n_buffers) {
/* this shouldn't happen */
- pw_log_warn("%p: mix port-id:%u freeing leaked buffers", impl, mix->mix_id - 1u);
+ spa_log_warn(impl->log, "%p: mix port-id:%u freeing leaked buffers", impl, mix->mix_id - 1u);
}
clear_buffers(impl, mix);
@@ -330,13 +331,11 @@ static int impl_node_enum_params(void *object, int seq,
struct spa_pod_dynamic_builder b;
struct spa_result_node_params result;
uint32_t count = 0;
+ bool found = false;
spa_return_val_if_fail(impl != NULL, -EINVAL);
spa_return_val_if_fail(num != 0, -EINVAL);
- if (!pw_param_info_find(impl->this.node->info.params, impl->this.node->info.n_params, id))
- return -ENOENT;
-
result.id = id;
result.next = 0;
@@ -352,6 +351,8 @@ static int impl_node_enum_params(void *object, int seq,
if (param == NULL || !spa_pod_is_object_id(param, id))
continue;
+ found = true;
+
if (result.index < start)
continue;
@@ -366,8 +367,7 @@ static int impl_node_enum_params(void *object, int seq,
if (count == num)
break;
}
-
- return 0;
+ return found ? 0 : -ENOENT;
}
static int impl_node_set_param(void *object, uint32_t id, uint32_t flags,
@@ -509,7 +509,7 @@ do_update_port(struct impl *impl,
const struct spa_port_info *info)
{
if (change_mask & PW_CLIENT_NODE_PORT_UPDATE_PARAMS) {
- pw_log_debug("%p: port %u update %d params", impl, port->id, n_params);
+ spa_log_debug(impl->log, "%p: port %u update %d params", impl, port->id, n_params);
update_params(&port->params, n_params, params);
}
@@ -543,7 +543,7 @@ static int mix_clear_cb(void *item, void *data)
static void
clear_port(struct impl *impl, struct port *port)
{
- pw_log_debug("%p: clear port %p", impl, port);
+ spa_log_debug(impl->log, "%p: clear port %p", impl, port);
do_update_port(impl, port,
PW_CLIENT_NODE_PORT_UPDATE_PARAMS |
@@ -599,6 +599,7 @@ node_port_enum_params(struct impl *impl, int seq,
struct spa_pod_dynamic_builder b;
struct spa_result_node_params result;
uint32_t count = 0;
+ bool found = false;
spa_return_val_if_fail(impl != NULL, -EINVAL);
spa_return_val_if_fail(num != 0, -EINVAL);
@@ -609,9 +610,6 @@ node_port_enum_params(struct impl *impl, int seq,
pw_log_debug("%p: seq:%d port %d.%d id:%u start:%u num:%u n_params:%d",
impl, seq, direction, port_id, id, start, num, port->params.n_params);
- if (!pw_param_info_find(port->port->info.params, port->port->info.n_params, id))
- return -ENOENT;
-
result.id = id;
result.next = 0;
@@ -627,6 +625,8 @@ node_port_enum_params(struct impl *impl, int seq,
if (param == NULL || !spa_pod_is_object_id(param, id))
continue;
+ found = true;
+
if (result.index < start)
continue;
@@ -641,7 +641,7 @@ node_port_enum_params(struct impl *impl, int seq,
if (count == num)
break;
}
- return 0;
+ return found ? 0 : -ENOENT;
}
static int
@@ -782,7 +782,7 @@ do_port_use_buffers(struct impl *impl,
if (n_buffers > MAX_BUFFERS)
return -ENOSPC;
- pw_log_debug("%p: %s port %d.%d use buffers %p %u flags:%08x", impl,
+ spa_log_debug(impl->log, "%p: %s port %d.%d use buffers %p %u flags:%08x", impl,
direction == SPA_DIRECTION_INPUT ? "input" : "output",
port_id, mix_id, buffers, n_buffers, flags);
@@ -852,7 +852,7 @@ do_port_use_buffers(struct impl *impl,
mb[i].mem_id = m->id;
mb[i].offset = SPA_PTRDIFF(baseptr, mem->map->ptr);
mb[i].size = SPA_PTRDIFF(endptr, baseptr);
- pw_log_debug("%p: buffer %d %d %d %d", impl, i, mb[i].mem_id,
+ spa_log_debug(impl->log, "%p: buffer %d %d %d %d", impl, i, mb[i].mem_id,
mb[i].offset, mb[i].size);
b->buffer.n_metas = SPA_MIN(buffers[i]->n_metas, MAX_METAS);
@@ -885,7 +885,7 @@ do_port_use_buffers(struct impl *impl,
if (d->flags & SPA_DATA_FLAG_WRITABLE)
flags |= PW_MEMBLOCK_FLAG_WRITABLE;
- pw_log_debug("mem %d type:%d fd:%d", j, d->type, (int)d->fd);
+ spa_log_debug(impl->log, "mem %d type:%d fd:%d", j, d->type, (int)d->fd);
m = pw_mempool_import(impl->client_pool,
flags, d->type, d->fd);
if (m == NULL)
@@ -896,14 +896,14 @@ do_port_use_buffers(struct impl *impl,
break;
}
case SPA_DATA_MemPtr:
- pw_log_debug("mem %d %zd", j, SPA_PTRDIFF(d->data, baseptr));
+ spa_log_debug(impl->log, "mem %d %zd", j, SPA_PTRDIFF(d->data, baseptr));
b->datas[j].data = SPA_INT_TO_PTR(SPA_PTRDIFF(d->data, baseptr));
SPA_FLAG_CLEAR(b->datas[j].flags, SPA_DATA_FLAG_MAPPABLE);
break;
default:
b->datas[j].type = SPA_ID_INVALID;
b->datas[j].data = NULL;
- pw_log_error("invalid memory type %d", d->type);
+ spa_log_error(impl->log, "invalid memory type %d", d->type);
break;
}
}
@@ -939,7 +939,7 @@ impl_node_port_reuse_buffer(void *object, uint32_t port_id, uint32_t buffer_id)
spa_return_val_if_fail(impl != NULL, -EINVAL);
spa_return_val_if_fail(CHECK_PORT(impl, SPA_DIRECTION_OUTPUT, port_id), -EINVAL);
- pw_log_trace_fp("reuse buffer %d", buffer_id);
+ spa_log_trace_fp(impl->log, "reuse buffer %d", buffer_id);
return -ENOTSUP;
}
@@ -952,7 +952,7 @@ static int impl_node_process(void *object)
/* this should not be called, we call the exported node
* directly */
- pw_log_warn("exported node activation");
+ spa_log_warn(impl->log, "exported node activation");
spa_system_clock_gettime(impl->data_system, CLOCK_MONOTONIC, &ts);
n->rt.target.activation->status = PW_NODE_ACTIVATION_TRIGGERED;
n->rt.target.activation->signal_time = SPA_TIMESPEC_TO_NSEC(&ts);
@@ -1013,7 +1013,7 @@ client_node_port_update(void *data,
struct port *port;
bool remove;
- pw_log_debug("%p: got port update change:%08x params:%d",
+ spa_log_debug(impl->log, "%p: got port update change:%08x params:%d",
impl, change_mask, n_params);
remove = (change_mask == 0);
@@ -1051,7 +1051,7 @@ client_node_port_update(void *data,
static int client_node_set_active(void *data, bool active)
{
struct impl *impl = data;
- pw_log_debug("%p: active:%d", impl, active);
+ spa_log_debug(impl->log, "%p: active:%d", impl, active);
return pw_impl_node_set_active(impl->this.node, active);
}
@@ -1074,7 +1074,7 @@ static int client_node_port_buffers(void *data,
struct mix *mix;
uint32_t i, j;
- pw_log_debug("%p: %s port %d.%d buffers %p %u", impl,
+ spa_log_debug(impl->log, "%p: %s port %d.%d buffers %p %u", impl,
direction == SPA_DIRECTION_INPUT ? "input" : "output",
port_id, mix_id, buffers, n_buffers);
@@ -1102,7 +1102,7 @@ static int client_node_port_buffers(void *data,
oldbuf = b->outbuf;
newbuf = buffers[i];
- pw_log_debug("buffer %d n_datas:%d", i, newbuf->n_datas);
+ spa_log_debug(impl->log, "buffer %d n_datas:%d", i, newbuf->n_datas);
for (j = 0; j < b->buffer.n_datas; j++) {
struct spa_chunk *oldchunk = oldbuf->datas[j].chunk;
@@ -1111,7 +1111,7 @@ static int client_node_port_buffers(void *data,
if (d->type == SPA_DATA_MemFd &&
!SPA_FLAG_IS_SET(flags, SPA_DATA_FLAG_MAPPABLE)) {
- pw_log_debug("buffer:%d data:%d has non mappable MemFd, "
+ spa_log_debug(impl->log, "buffer:%d data:%d has non mappable MemFd, "
"fixing to ensure backwards compatibility.",
i, j);
flags |= SPA_DATA_FLAG_MAPPABLE;
@@ -1126,7 +1126,7 @@ static int client_node_port_buffers(void *data,
b->datas[j].flags = flags;
b->datas[j].fd = d->fd;
- pw_log_debug(" data %d type:%d fl:%08x fd:%d, offs:%d max:%d",
+ spa_log_debug(impl->log, " data %d type:%d fl:%08x fd:%d, offs:%d max:%d",
j, d->type, flags, (int) d->fd, d->mapoffset,
d->maxsize);
}
@@ -1153,7 +1153,7 @@ static void node_on_data_fd_events(struct spa_source *source)
struct impl *impl = source->data;
if (SPA_UNLIKELY(source->rmask & (SPA_IO_ERR | SPA_IO_HUP))) {
- pw_log_warn("%p: got error", impl);
+ spa_log_warn(impl->log, "%p: got error", impl);
return;
}
if (SPA_LIKELY(source->rmask & SPA_IO_IN)) {
@@ -1170,10 +1170,10 @@ static void node_on_data_fd_events(struct spa_source *source)
if (impl->resource && impl->resource->version < 5) {
struct pw_node_activation *a = node->rt.target.activation;
int status = a->state[0].status;
- pw_log_trace_fp("%p: got ready %d", impl, status);
+ spa_log_trace_fp(impl->log, "%p: got ready %d", impl, status);
spa_node_call_ready(&impl->callbacks, status);
} else {
- pw_log_trace_fp("%p: got complete", impl);
+ spa_log_trace_fp(impl->log, "%p: got complete", impl);
pw_impl_node_rt_emit_complete(node);
}
}
@@ -1764,7 +1764,7 @@ struct pw_impl_client_node *pw_impl_client_node_new(struct pw_resource *resource
goto error_exit_free;
}
- pw_properties_setf(properties, PW_KEY_CLIENT_ID, "%u", client->global->id);
+ pw_properties_setf(properties, PW_KEY_CLIENT_ID, "%d", client->global->id);
this = &impl->this;
@@ -1774,6 +1774,7 @@ struct pw_impl_client_node *pw_impl_client_node_new(struct pw_resource *resource
pw_log_debug("%p: new", &impl->node);
impl_init(impl, NULL);
+ impl->log = pw_log_get();
impl->resource = resource;
impl->client = client;
impl->client_pool = pw_impl_client_get_mempool(client);
diff --git a/src/modules/module-echo-cancel.c b/src/modules/module-echo-cancel.c
index cc118565b..390563db2 100644
--- a/src/modules/module-echo-cancel.c
+++ b/src/modules/module-echo-cancel.c
@@ -1179,24 +1179,15 @@ static int setup_streams(struct impl *impl)
spa_pod_dynamic_builder_clean(&b);
- impl->rec_ringsize = (size_t)sizeof(float) * impl->max_buffer_size * impl->rec_info.rate / 1000;
- impl->play_ringsize = (size_t)sizeof(float) * ((size_t)impl->max_buffer_size * impl->play_info.rate / 1000 + impl->buffer_delay);
- impl->out_ringsize = (size_t)sizeof(float) * impl->max_buffer_size * impl->out_info.rate / 1000;
- for (i = 0; i < impl->rec_info.channels; i++) {
+ impl->rec_ringsize = sizeof(float) * impl->max_buffer_size * impl->rec_info.rate / 1000;
+ impl->play_ringsize = sizeof(float) * ((impl->max_buffer_size * impl->play_info.rate / 1000) + impl->buffer_delay);
+ impl->out_ringsize = sizeof(float) * impl->max_buffer_size * impl->out_info.rate / 1000;
+ for (i = 0; i < impl->rec_info.channels; i++)
impl->rec_buffer[i] = malloc(impl->rec_ringsize);
- if (impl->rec_buffer[i] == NULL)
- return -errno;
- }
- for (i = 0; i < impl->play_info.channels; i++) {
+ for (i = 0; i < impl->play_info.channels; i++)
impl->play_buffer[i] = malloc(impl->play_ringsize);
- if (impl->play_buffer[i] == NULL)
- return -errno;
- }
- for (i = 0; i < impl->out_info.channels; i++) {
+ for (i = 0; i < impl->out_info.channels; i++)
impl->out_buffer[i] = malloc(impl->out_ringsize);
- if (impl->out_buffer[i] == NULL)
- return -errno;
- }
reset_buffers(impl);
diff --git a/src/modules/module-ffado-driver.c b/src/modules/module-ffado-driver.c
index c98b0efcd..05b9218ce 100644
--- a/src/modules/module-ffado-driver.c
+++ b/src/modules/module-ffado-driver.c
@@ -345,26 +345,34 @@ static void midi_to_ffado(struct port *p, float *src, uint32_t n_samples)
p->event_pos = 0;
while (spa_pod_parser_get_control_body(&parser, &c, &c_body) >= 0) {
- uint32_t j, size = c.value.size;
- const uint8_t *data = c_body;
+ uint8_t data[16];
+ int j, size;
+ size_t c_size = c.value.size;
+ uint64_t state = 0;
- if (c.type != SPA_CONTROL_Midi)
+ if (c.type != SPA_CONTROL_UMP)
continue;
if (index < c.offset)
index = SPA_ROUND_UP_N(c.offset, 8);
- for (j = 0; j < size; j++) {
- if (index >= n_samples) {
- /* keep events that don't fit for the next cycle */
- if (p->event_pos < sizeof(p->event_buffer))
- p->event_buffer[p->event_pos++] = data[j];
+ while (c_size > 0) {
+ size = spa_ump_to_midi((const uint32_t**)&c_body, &c_size, data, sizeof(data), &state);
+ if (size <= 0)
+ break;
+
+ for (j = 0; j < size; j++) {
+ if (index >= n_samples) {
+ /* keep events that don't fit for the next cycle */
+ if (p->event_pos < sizeof(p->event_buffer))
+ p->event_buffer[p->event_pos++] = data[j];
+ else
+ unhandled++;
+ }
else
- unhandled++;
+ dst[index] = 0x01000000 | (uint32_t) data[j];
+ index += 8;
}
- else
- dst[index] = 0x01000000 | (uint32_t) data[j];
- index += 8;
}
}
if (unhandled > 0)
@@ -489,8 +497,16 @@ static void ffado_to_midi(struct port *p, float *dst, uint32_t *src, uint32_t si
continue;
if (process_byte(p, i, data & 0xff, &frame, &bytes, &size)) {
- spa_pod_builder_control(&b, frame, SPA_CONTROL_Midi);
- spa_pod_builder_bytes(&b, bytes, size);
+ uint64_t state = 0;
+ while (size > 0) {
+ uint32_t ev[4];
+ int ev_size = spa_ump_from_midi(&bytes, &size, ev, sizeof(ev), 0, &state);
+ if (ev_size <= 0)
+ break;
+
+ spa_pod_builder_control(&b, frame, SPA_CONTROL_UMP);
+ spa_pod_builder_bytes(&b, ev, ev_size);
+ }
}
}
spa_pod_builder_pop(&b, &f);
diff --git a/src/modules/module-filter-chain.c b/src/modules/module-filter-chain.c
index 5b9dd9815..64a92c5ac 100644
--- a/src/modules/module-filter-chain.c
+++ b/src/modules/module-filter-chain.c
@@ -128,7 +128,7 @@ extern struct spa_handle_factory spa_filter_graph_factory;
* # an example ladspa plugin
* type = ladspa
* name = pitch
- * plugin = "ladspa-rubberband"
+ * plugin = "/usr/lib64/ladspa/ladspa-rubberband.so"
* label = "rubberband-r3-pitchshifter-mono"
* control = {
* # controls are using the ladspa port names as seen in analyseplugin
@@ -368,11 +368,6 @@ extern struct spa_handle_factory spa_filter_graph_factory;
* The convolver has an input port "In" and an output port "Out". It requires a config
* section in the node declaration in this format:
*
- * When multiple impulses are applied to one input, use the convolver2, which is more
- * performant.
- *
- * Check the documentation for Convolver2 for the parameter meanings.
- *
*\code{.unparsed}
* filter.graph = {
* nodes = [
@@ -397,54 +392,16 @@ extern struct spa_handle_factory spa_filter_graph_factory;
* }
* ...
* }
- *
- * ### Convolver2
- *
- * The convolver2 can be used to apply one or more impulse responses to a signal.
- * It is usually used for reverbs or virtual surround. The convolver2 is implemented
- * with a fast FFT implementation.
- *
- * The convolver2 has an input port "In" and 8 output ports "Out 1" to "Out 8". It
- * requires a config section in the node declaration in this format:
- *
- *\code{.unparsed}
- * filter.graph = {
- * nodes = [
- * {
- * type = builtin
- * name = ...
- * label = convolver2
- * config = {
- * blocksize = ...
- * tailsize = ...
- * impulses = [
- * {
- * gain = ...
- * delay = ...
- * filename = ...
- * offset = ...
- * length = ...
- * channel = ...
- * resample_quality = ...
- * }
- * ...
- * ]
- * latency = ...
- * }
- * ...
- * }
- *
*\endcode
*
* - `blocksize` specifies the size of the blocks to use in the FFT. It is a value
* between 64 and 256. When not specified, this value is
* computed automatically from the number of samples in the file.
* - `tailsize` specifies the size of the tail blocks to use in the FFT.
- * - `impulses` An array of objects with the IRs for the outputs "Out 1" to "Out 8".
- * - `gain` the overall gain to apply to the IR file. Default 1.0
+ * - `gain` the overall gain to apply to the IR file.
* - `delay` The extra delay to add to the IR. A float number will be interpreted as seconds,
* and integer as samples. Using the delay in seconds is independent of the graph
- * and IR rate and is recommended. Default 0
+ * and IR rate and is recommended.
* - `filename` The IR to load or create. Possible values are:
* - `/hilbert` creates a [hilbert function](https://en.wikipedia.org/wiki/Hilbert_transform)
* that can be used to phase shift the signal by +/-90 degrees. The
@@ -463,7 +420,7 @@ extern struct spa_handle_factory spa_filter_graph_factory;
* - `resample_quality` The resample quality in case the IR does not match the graph
* samplerate.
* - `latency` The extra latency in seconds to report. When left unspecified (or < 0.0)
- * the default IR latency will be used, depending on the filename argument.
+ * the default IR latency will be used, the the filename argument.
*
* ### Delay
*
@@ -761,7 +718,6 @@ extern struct spa_handle_factory spa_filter_graph_factory;
* tailsize = ...
* filename = ...
* gain = ...
- * latency = ...
* }
* control = {
* "Azimuth" = ...
@@ -781,8 +737,7 @@ extern struct spa_handle_factory spa_filter_graph_factory;
* - `tailsize` specifies the size of the tail blocks to use in the FFT.
* - `filename` The SOFA file to load. SOFA files usually end in the .sofa extension
* and contain the HRTF for the various spatial positions.
- * - `gain` the overall gain to apply to the IR file, default 1.0.
- * - `latency` the latency introduced by the filter, default 0
+ * - `gain` the overall gain to apply to the IR file.
*
* - `Azimuth` controls the azimuth, this is the direction the sound is coming from
* in degrees between 0 and 360. 0 is straight ahead. 90 is left, 180
@@ -1582,7 +1537,8 @@ static void param_changed(struct impl *impl, uint32_t id, const struct spa_pod *
spa_zero(info);
if (param == NULL) {
pw_log_info("module %p: filter deactivate", impl);
- deactivate_graph(impl);
+ if (direction == SPA_DIRECTION_OUTPUT)
+ deactivate_graph(impl);
impl->rate = 0;
} else {
if ((res = spa_format_audio_raw_parse(param, &info)) < 0)
@@ -1695,7 +1651,7 @@ static const struct pw_stream_events out_stream_events = {
static int setup_streams(struct impl *impl)
{
- int res = 0;
+ int res;
uint32_t i, n_params, *offs, flags;
struct pw_array offsets;
const struct spa_pod **params = NULL;
@@ -1746,19 +1702,6 @@ static int setup_streams(struct impl *impl)
spa_process_latency_build(&b.b,
SPA_PARAM_ProcessLatency, &impl->process_latency);
-
- if (impl->capture || impl->playback) {
- if ((offs = pw_array_add(&offsets, sizeof(uint32_t))) != NULL)
- *offs = b.b.state.offset;
-
- if (impl->capture)
- spa_format_audio_raw_build(&b.b,
- SPA_PARAM_EnumFormat, &impl->capture_info);
- else
- spa_format_audio_raw_build(&b.b,
- SPA_PARAM_EnumFormat, &impl->playback_info);
- }
-
n_params = pw_array_get_len(&offsets, uint32_t);
if (n_params == 0) {
res = -ENOMEM;
@@ -1774,6 +1717,8 @@ static int setup_streams(struct impl *impl)
params[i] = spa_pod_builder_deref(&b.b, offs[i]);
if (impl->capture) {
+ params[n_params++] = spa_format_audio_raw_build(&b.b,
+ SPA_PARAM_EnumFormat, &impl->capture_info);
flags = PW_STREAM_FLAG_AUTOCONNECT |
PW_STREAM_FLAG_MAP_BUFFERS |
PW_STREAM_FLAG_RT_PROCESS;
@@ -1794,9 +1739,8 @@ static int setup_streams(struct impl *impl)
spa_pod_dynamic_builder_init(&b, NULL, 0, 4096);
}
if (impl->playback) {
- if (n_params == 0)
- params[n_params++] = spa_format_audio_raw_build(&b.b,
- SPA_PARAM_EnumFormat, &impl->playback_info);
+ params[n_params++] = spa_format_audio_raw_build(&b.b,
+ SPA_PARAM_EnumFormat, &impl->playback_info);
flags = PW_STREAM_FLAG_AUTOCONNECT |
PW_STREAM_FLAG_MAP_BUFFERS |
diff --git a/src/modules/module-jack-tunnel.c b/src/modules/module-jack-tunnel.c
index bee37da4f..0c0cee034 100644
--- a/src/modules/module-jack-tunnel.c
+++ b/src/modules/module-jack-tunnel.c
@@ -50,6 +50,7 @@
*
* - `jack.library`: the libjack to load, by default libjack.so.0 is searched in
* LIBJACK_PATH directories and then some standard library paths.
+ * Can be an absolute path.
* - `jack.server`: the name of the JACK server to tunnel to.
* - `jack.client-name`: the name of the JACK client.
* - `jack.connect`: if jack ports should be connected automatically. Can also be
@@ -242,16 +243,13 @@ static inline void do_volume(float *dst, const float *src, struct volume *vol, u
}
}
-static inline bool fix_midi_event(const uint8_t *data, size_t size, uint8_t dst[3])
+static inline void fix_midi_event(uint8_t *data, size_t size)
{
/* fixup NoteOn with vel 0 */
if (size > 2 && (data[0] & 0xF0) == 0x90 && data[2] == 0x00) {
- dst[0] = 0x80 + (data[0] & 0x0F);
- dst[1] = data[1];
- dst[2] = 0x40;
- return true;
+ data[0] = 0x80 + (data[0] & 0x0F);
+ data[2] = 0x40;
}
- return false;
}
static void midi_to_jack(struct impl *impl, float *dst, float *src, uint32_t n_samples)
@@ -262,6 +260,9 @@ static void midi_to_jack(struct impl *impl, float *dst, float *src, uint32_t n_s
struct spa_pod_control c;
const void *seq_body, *c_body;
int res;
+ bool in_sysex = false;
+ uint8_t tmp[n_samples * 4];
+ size_t tmp_size = 0;
jack.midi_clear_buffer(dst);
if (src == NULL)
@@ -273,20 +274,36 @@ static void midi_to_jack(struct impl *impl, float *dst, float *src, uint32_t n_s
return;
while (spa_pod_parser_get_control_body(&parser, &c, &c_body) >= 0) {
- uint32_t size = c.value.size;
- const uint8_t *data = c_body;
- uint8_t tmp[3];
+ int size;
+ size_t c_size = c.value.size;
+ uint64_t state = 0;
- if (c.type != SPA_CONTROL_Midi)
+ if (c.type != SPA_CONTROL_UMP)
continue;
- if (impl->fix_midi && fix_midi_event(data, size, tmp)) {
- data = tmp;
- size = 3;
+ while (c_size > 0) {
+ size = spa_ump_to_midi((const uint32_t**)&c_body, &c_size,
+ &tmp[tmp_size], sizeof(tmp) - tmp_size, &state);
+ if (size <= 0)
+ break;
+
+ if (impl->fix_midi)
+ fix_midi_event(&tmp[tmp_size], size);
+
+ if (!in_sysex && tmp[tmp_size] == 0xf0)
+ in_sysex = true;
+
+ tmp_size += size;
+ if (in_sysex && tmp[tmp_size-1] == 0xf7)
+ in_sysex = false;
+
+ if (!in_sysex) {
+ if ((res = jack.midi_event_write(dst, c.offset, tmp, tmp_size)) < 0)
+ pw_log_warn("midi %p: can't write event: %s", dst,
+ spa_strerror(res));
+ tmp_size = 0;
+ }
}
- if ((res = jack.midi_event_write(dst, c.offset, data, size)) < 0)
- pw_log_warn("midi %p: can't write event: %s", dst,
- spa_strerror(res));
}
}
@@ -302,11 +319,19 @@ static void jack_to_midi(float *dst, float *src, uint32_t size)
spa_pod_builder_push_sequence(&b, &f, 0);
for (i = 0; i < count; i++) {
jack_midi_event_t ev;
+ uint64_t state = 0;
jack.midi_event_get(&ev, src, i);
- spa_pod_builder_control(&b, ev.time, SPA_CONTROL_Midi);
- spa_pod_builder_bytes(&b, ev.buffer, ev.size);
+ while (ev.size > 0) {
+ uint32_t ump[4];
+ int ump_size = spa_ump_from_midi(&ev.buffer, &ev.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);
}
diff --git a/src/modules/module-jack-tunnel/weakjack.h b/src/modules/module-jack-tunnel/weakjack.h
index 6a3d9bc67..6d5b5503e 100644
--- a/src/modules/module-jack-tunnel/weakjack.h
+++ b/src/modules/module-jack-tunnel/weakjack.h
@@ -158,36 +158,34 @@ static inline int weakjack_load_by_path(struct weakjack *jack, const char *path)
static inline int weakjack_load(struct weakjack *jack, const char *lib)
{
int res = -ENOENT;
- const char *search_dirs, *p, *state = NULL;
- char path[PATH_MAX];
- size_t len;
- while ((p = strstr(lib, "../")) != NULL)
- lib = p + 3;
+ if (lib[0] != '/') {
+ const char *search_dirs, *p, *state = NULL;
+ char path[PATH_MAX];
+ size_t len;
- search_dirs = getenv("LIBJACK_PATH");
- if (!search_dirs)
- search_dirs = PREFIX "/lib64/:" PREFIX "/lib/:"
- "/usr/lib64/:/usr/lib/:" LIBDIR;
+ search_dirs = getenv("LIBJACK_PATH");
+ if (!search_dirs)
+ search_dirs = PREFIX "/lib64/:" PREFIX "/lib/:"
+ "/usr/lib64/:/usr/lib/:" LIBDIR;
- res = -ENAMETOOLONG;
+ while ((p = pw_split_walk(search_dirs, ":", &len, &state))) {
+ int pathlen;
- while ((p = pw_split_walk(search_dirs, ":", &len, &state))) {
- int pathlen;
-
- if (len == 0 || len >= sizeof(path))
- continue;
-
- if (strncmp(lib, p, len) == 0 && (lib[len-1] == '/' || lib[len] == '/'))
- pathlen = snprintf(path, sizeof(path), "%s", lib);
- else
+ if (len >= sizeof(path)) {
+ res = -ENAMETOOLONG;
+ continue;
+ }
pathlen = snprintf(path, sizeof(path), "%.*s/%s", (int) len, p, lib);
-
- if (pathlen < 0 || (size_t) pathlen >= sizeof(path))
- continue;
-
- if ((res = weakjack_load_by_path(jack, path)) == 0)
- break;
+ if (pathlen < 0 || (size_t) pathlen >= sizeof(path)) {
+ res = -ENAMETOOLONG;
+ continue;
+ }
+ if ((res = weakjack_load_by_path(jack, path)) == 0)
+ break;
+ }
+ } else {
+ res = weakjack_load_by_path(jack, lib);
}
return res;
}
diff --git a/src/modules/module-link-factory.c b/src/modules/module-link-factory.c
index 1f01078e8..d54df2758 100644
--- a/src/modules/module-link-factory.c
+++ b/src/modules/module-link-factory.c
@@ -485,12 +485,12 @@ static void *create_object(void *_data,
linger = pw_properties_get_bool(properties, PW_KEY_OBJECT_LINGER, false);
- pw_properties_setf(properties, PW_KEY_FACTORY_ID, "%u",
+ pw_properties_setf(properties, PW_KEY_FACTORY_ID, "%d",
pw_impl_factory_get_info(d->factory)->id);
client = resource ? pw_resource_get_client(resource) : NULL;
if (client && !linger)
- pw_properties_setf(properties, PW_KEY_CLIENT_ID, "%u",
+ pw_properties_setf(properties, PW_KEY_CLIENT_ID, "%d",
pw_impl_client_get_info(client)->id);
if (!d->allow_passive)
diff --git a/src/modules/module-metadata.c b/src/modules/module-metadata.c
index 84b98a7ce..79d80d1b4 100644
--- a/src/modules/module-metadata.c
+++ b/src/modules/module-metadata.c
@@ -203,9 +203,9 @@ static void *create_object(void *_data,
if (properties == NULL)
return NULL;
- pw_properties_setf(properties, PW_KEY_FACTORY_ID, "%u",
+ pw_properties_setf(properties, PW_KEY_FACTORY_ID, "%d",
pw_impl_factory_get_info(data->factory)->id);
- pw_properties_setf(properties, PW_KEY_MODULE_ID, "%u",
+ pw_properties_setf(properties, PW_KEY_MODULE_ID, "%d",
pw_impl_module_get_info(data->module)->id);
if (pw_properties_get(properties, PW_KEY_METADATA_NAME) == NULL)
@@ -218,7 +218,7 @@ static void *create_object(void *_data,
goto error_resource;
}
- pw_properties_setf(properties, PW_KEY_CLIENT_ID, "%u",
+ pw_properties_setf(properties, PW_KEY_CLIENT_ID, "%d",
pw_impl_client_get_info(client)->id);
result = pw_metadata_new(context, metadata_resource, properties);
diff --git a/src/modules/module-netjack2/peer.c b/src/modules/module-netjack2/peer.c
index bec71fe0d..eacc1c95b 100644
--- a/src/modules/module-netjack2/peer.c
+++ b/src/modules/module-netjack2/peer.c
@@ -273,18 +273,39 @@ static inline void *n2j_midi_buffer_reserve(struct nj2_midi_buffer *buf,
}
static inline void n2j_midi_buffer_write(struct nj2_midi_buffer *buf,
- uint32_t offset, const void *data, uint32_t size, bool fix)
+ uint32_t offset, void *data, uint32_t size)
{
- uint8_t *ptr = n2j_midi_buffer_reserve(buf, offset, size);
- if (ptr != NULL) {
+ void *ptr = n2j_midi_buffer_reserve(buf, offset, size);
+ if (ptr != NULL)
memcpy(ptr, data, size);
- if (fix)
- fix_midi_event(ptr, size);
- }
else
buf->lost_events++;
}
+static inline void n2j_midi_buffer_append(struct nj2_midi_buffer *buf,
+ void *data, uint32_t size)
+{
+ struct nj2_midi_event *ev;
+ uint32_t old_size;
+ uint8_t *old_ptr, *new_ptr;
+
+ ev = &buf->event[--buf->event_count];
+ old_size = ev->size;
+ if (old_size <= MIDI_INLINE_MAX) {
+ old_ptr = ev->buffer;
+ } else {
+ buf->write_pos -= old_size;
+ old_ptr = SPA_PTROFF(buf, ev->offset, void);
+ }
+ new_ptr = n2j_midi_buffer_reserve(buf, ev->time, old_size + size);
+ if (new_ptr == NULL) {
+ buf->lost_events++;
+ } else {
+ memmove(new_ptr, old_ptr, old_size);
+ memcpy(new_ptr+old_size, data, size);
+ }
+}
+
static void midi_to_netjack2(struct netjack2_peer *peer,
struct nj2_midi_buffer *buf, float *src, uint32_t n_samples)
{
@@ -293,6 +314,7 @@ static void midi_to_netjack2(struct netjack2_peer *peer,
struct spa_pod_sequence seq;
struct spa_pod_control c;
const void *seq_body, *c_body;
+ bool in_sysex = false;
buf->magic = MIDI_BUFFER_MAGIC;
buf->buffer_size = peer->params.period_size * sizeof(float);
@@ -310,17 +332,39 @@ static void midi_to_netjack2(struct netjack2_peer *peer,
return;
while (spa_pod_parser_get_control_body(&parser, &c, &c_body) >= 0) {
- uint32_t size = c.value.size;
- const uint8_t *data = c_body;
+ int size;
+ uint8_t data[16];
+ bool was_sysex = in_sysex;
+ size_t c_size = c.value.size;
+ uint64_t state = 0;
- if (c.type != SPA_CONTROL_Midi)
+ if (c.type != SPA_CONTROL_UMP)
continue;
- if (c.offset >= n_samples) {
- buf->lost_events++;
- continue;
+ while (c_size > 0) {
+ size = spa_ump_to_midi((const uint32_t**)&c_body, &c_size, data, sizeof(data), &state);
+ if (size <= 0)
+ break;
+
+ if (c.offset >= n_samples) {
+ buf->lost_events++;
+ continue;
+ }
+
+ if (!in_sysex && data[0] == 0xf0)
+ in_sysex = true;
+
+ if (!in_sysex && peer->fix_midi)
+ fix_midi_event(data, size);
+
+ if (in_sysex && data[size-1] == 0xf7)
+ in_sysex = false;
+
+ if (was_sysex)
+ n2j_midi_buffer_append(buf, data, size);
+ else
+ n2j_midi_buffer_write(buf, c.offset, data, size);
}
- n2j_midi_buffer_write(buf, c.offset, data, size, peer->fix_midi);
}
if (buf->write_pos > 0)
memmove(SPA_PTROFF(buf, sizeof(*buf) + buf->event_count * sizeof(struct nj2_midi_event), void),
@@ -351,6 +395,8 @@ static inline void netjack2_to_midi(float *dst, uint32_t size, struct nj2_midi_b
for (i = 0; i < buf->event_count; i++) {
struct nj2_midi_event *ev = &buf->event[i];
uint8_t *data;
+ size_t s;
+ uint64_t state = 0;
if (ev->size <= MIDI_INLINE_MAX)
data = ev->buffer;
@@ -359,8 +405,17 @@ static inline void netjack2_to_midi(float *dst, uint32_t size, struct nj2_midi_b
else
continue;
- spa_pod_builder_control(&b, ev->time, SPA_CONTROL_Midi);
- spa_pod_builder_bytes(&b, data, ev->size);
+ s = ev->size;
+ while (s > 0) {
+ uint32_t ump[4];
+ int ump_size = spa_ump_from_midi(&data, &s, ump, sizeof(ump), 0, &state);
+ if (ump_size <= 0) {
+ pw_log_warn("invalid MIDI received: %s", spa_strerror(ump_size));
+ 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);
}
@@ -774,9 +829,6 @@ static int netjack2_recv_midi(struct netjack2_peer *peer, struct nj2_packet_head
sub_cycle = ntohl(header->sub_cycle);
peer->sync.num_packets = ntohl(header->num_packets);
max_size = peer->params.mtu - sizeof(*header);
-
- if (sub_cycle > 0 && max_size > UINT32_MAX / sub_cycle)
- return -EOVERFLOW;
offset = max_size * sub_cycle;
data += sizeof(*header);
@@ -785,7 +837,7 @@ static int netjack2_recv_midi(struct netjack2_peer *peer, struct nj2_packet_head
midi_data = peer->midi_data;
midi_size = peer->midi_size;
- if (offset <= midi_size && (size_t)len <= midi_size - offset)
+ if (offset + len < midi_size)
memcpy(SPA_PTROFF(midi_data, offset, void), data, len);
if (++(*count) < peer->sync.num_packets)
@@ -799,7 +851,7 @@ static int netjack2_recv_midi(struct netjack2_peer *peer, struct nj2_packet_head
size_t used = sizeof(*mbuf)
+ mbuf->event_count * sizeof(struct nj2_midi_event)
+ mbuf->write_pos;
- if (used < sizeof(*mbuf) || used > midi_size)
+ if (used > midi_size)
break;
if (i < n_info && info[i].data != NULL) {
@@ -824,7 +876,7 @@ static int netjack2_recv_float(struct netjack2_peer *peer, struct nj2_packet_hea
return -errno;
active_ports = ntohl(header->active_ports);
- if (active_ports == 0 || active_ports > MAX_CHANNELS)
+ if (active_ports == 0)
return 0;
uint32_t max_size = PACKET_AVAILABLE_SIZE(peer->params.mtu);
@@ -833,11 +885,11 @@ static int netjack2_recv_float(struct netjack2_peer *peer, struct nj2_packet_hea
sub_period_size = SPA_MIN(period, (uint32_t)peer->sync.frames);
sub_period_bytes = sub_period_size * sizeof(float) + sizeof(int32_t);
- if ((size_t)len < (size_t)active_ports * sub_period_bytes + sizeof(*header))
+ if ((size_t)len < active_ports * sub_period_bytes + sizeof(*header))
return 0;
sub_cycle = ntohl(header->sub_cycle);
- if (sub_period_size == 0 || sub_cycle > peer->quantum_limit / sub_period_size)
+ if (sub_cycle * sub_period_size > peer->quantum_limit)
return 0;
for (i = 0; i < active_ports; i++) {
diff --git a/src/modules/module-profiler.c b/src/modules/module-profiler.c
index 557ca2649..b49629ba9 100644
--- a/src/modules/module-profiler.c
+++ b/src/modules/module-profiler.c
@@ -166,7 +166,7 @@ static void do_flush_event(void *data, uint64_t count)
avail = spa_ringbuffer_get_read_index(&n->buffer, &idx);
- pw_log_trace("%p: node:%p avail %d", n, impl, avail);
+ pw_log_trace("%p: avail %d", impl, avail);
if (avail > 0) {
size_t size = total + avail + sizeof(struct spa_pod_struct);
@@ -559,7 +559,7 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
free(impl);
return -errno;
}
- pw_properties_setf(impl->properties, PW_KEY_OBJECT_ID, "%u", pw_global_get_id(impl->global));
+ pw_properties_setf(impl->properties, PW_KEY_OBJECT_ID, "%d", pw_global_get_id(impl->global));
pw_properties_setf(impl->properties, PW_KEY_OBJECT_SERIAL, "%"PRIu64,
pw_global_get_serial(impl->global));
diff --git a/src/modules/module-protocol-native.c b/src/modules/module-protocol-native.c
index 2a0b2f438..98a43829b 100644
--- a/src/modules/module-protocol-native.c
+++ b/src/modules/module-protocol-native.c
@@ -663,7 +663,7 @@ static struct client_data *client_new(struct server *s, int fd)
}
#endif
- pw_properties_setf(props, PW_KEY_MODULE_ID, "%u", d->module->global->id);
+ pw_properties_setf(props, PW_KEY_MODULE_ID, "%d", d->module->global->id);
client = pw_context_create_client(s->this.core,
protocol, props, sizeof(struct client_data));
diff --git a/src/modules/module-protocol-native/connection.c b/src/modules/module-protocol-native/connection.c
index 15c739428..b376a0f69 100644
--- a/src/modules/module-protocol-native/connection.c
+++ b/src/modules/module-protocol-native/connection.c
@@ -536,7 +536,7 @@ static int prepare_packet(struct pw_protocol_native_connection *conn, struct buf
size -= impl->hdr_size;
buf->msg.fds = &buf->fds[buf->fds_offset];
- if (buf->msg.n_fds + buf->fds_offset > buf->n_fds)
+ if (buf->msg.n_fds + buf->fds_offset > MAX_FDS)
return -EPROTO;
if (size < len)
diff --git a/src/modules/module-protocol-native/test-connection.c b/src/modules/module-protocol-native/test-connection.c
index 0c82d2da8..eabcbbd67 100644
--- a/src/modules/module-protocol-native/test-connection.c
+++ b/src/modules/module-protocol-native/test-connection.c
@@ -3,7 +3,6 @@
/* SPDX-License-Identifier: MIT */
#include
-#include
#include
#include
@@ -166,87 +165,6 @@ static void test_reentering(struct pw_protocol_native_connection *in,
}
}
-/*
- * Test that a packet claiming more FDs in its header than were actually
- * sent via SCM_RIGHTS is rejected. Without the n_fds validation this
- * would cause the receiver to read uninitialised / stale FD values.
- */
-static void test_spoofed_fds(struct pw_protocol_native_connection *in,
- struct pw_protocol_native_connection *out)
-{
- const struct pw_protocol_native_message *msg;
- int res;
-
- /*
- * First, send a valid message through the normal API so that the
- * receiver's version handshake happens (it switches to HDR_SIZE=16
- * on the first message). Use a message with 0 FDs.
- */
- {
- struct spa_pod_builder *b;
- struct pw_protocol_native_message *wmsg;
-
- b = pw_protocol_native_connection_begin(out, 0, 1, &wmsg);
- spa_assert_se(b != NULL);
- spa_pod_builder_add_struct(b, SPA_POD_Int(0));
- pw_protocol_native_connection_end(out, b);
- pw_protocol_native_connection_flush(out);
-
- /* Consume it on the reading side */
- res = pw_protocol_native_connection_get_next(in, &msg);
- spa_assert_se(res == 1);
- }
-
- /*
- * Now craft a raw packet on the wire that claims n_fds=5 in the
- * header but send 0 actual FDs via SCM_RIGHTS.
- *
- * v3 header layout (16 bytes / 4 uint32s):
- * p[0] = id
- * p[1] = (opcode << 24) | (payload_size & 0xffffff)
- * p[2] = seq
- * p[3] = n_fds
- *
- * We need a minimal valid SPA pod as payload.
- */
- {
- /* Build a tiny SPA pod: struct { Int(0) } */
- uint8_t payload[32];
- struct spa_pod_builder pb;
-
- spa_pod_builder_init(&pb, payload, sizeof(payload));
- spa_pod_builder_add_struct(&pb, SPA_POD_Int(0));
-
- uint32_t payload_size = pb.state.offset;
- uint32_t header[4];
-
- spa_assert_se(payload_size <= sizeof(payload));
-
- header[0] = 1; /* id */
- header[1] = (5u << 24) | (payload_size & 0xffffff); /* opcode=5, size */
- header[2] = 0; /* seq */
- header[3] = 5; /* SPOOFED: claim 5 fds, send 0 */
-
- struct iovec iov[2];
- struct msghdr mh = { 0 };
-
- iov[0].iov_base = header;
- iov[0].iov_len = sizeof(header);
- iov[1].iov_base = payload;
- iov[1].iov_len = payload_size;
- mh.msg_iov = iov;
- mh.msg_iovlen = 2;
- /* No msg_control — 0 FDs via SCM_RIGHTS */
-
- ssize_t sent = sendmsg(out->fd, &mh, MSG_NOSIGNAL);
- spa_assert_se(sent == (ssize_t)(sizeof(header) + payload_size));
- }
-
- /* The receiver must reject this packet */
- res = pw_protocol_native_connection_get_next(in, &msg);
- spa_assert_se(res == -EPROTO);
-}
-
int main(int argc, char *argv[])
{
struct pw_main_loop *loop;
@@ -280,26 +198,6 @@ int main(int argc, char *argv[])
pw_protocol_native_connection_destroy(in);
pw_protocol_native_connection_destroy(out);
-
- /* test_spoofed_fds needs its own connection pair */
- {
- int fds2[2];
- struct pw_protocol_native_connection *in2, *out2;
-
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds2) < 0)
- spa_assert_not_reached();
-
- in2 = pw_protocol_native_connection_new(context, fds2[0]);
- spa_assert_se(in2 != NULL);
- out2 = pw_protocol_native_connection_new(context, fds2[1]);
- spa_assert_se(out2 != NULL);
-
- test_spoofed_fds(in2, out2);
-
- pw_protocol_native_connection_destroy(in2);
- pw_protocol_native_connection_destroy(out2);
- }
-
pw_context_destroy(context);
pw_main_loop_destroy(loop);
diff --git a/src/modules/module-protocol-pulse/message.c b/src/modules/module-protocol-pulse/message.c
index bbeb7e99e..19b4f82d6 100644
--- a/src/modules/module-protocol-pulse/message.c
+++ b/src/modules/module-protocol-pulse/message.c
@@ -383,12 +383,9 @@ static int ensure_size(struct message *m, uint32_t size)
if (m->length > m->allocated)
return -ENOMEM;
- if (size <= m->allocated - m->length)
+ if (m->length + size <= m->allocated)
return size;
- if (m->allocated + size < m->allocated)
- return -ENOMEM;
-
alloc = SPA_ROUND_UP_N(SPA_MAX(m->allocated + size, 4096u), 4096u);
diff = alloc - m->allocated;
if ((data = realloc(m->data, alloc)) == NULL) {
diff --git a/src/modules/module-protocol-pulse/modules/module-zeroconf-publish.c b/src/modules/module-protocol-pulse/modules/module-zeroconf-publish.c
index ffb5aa0fe..d4425a3fe 100644
--- a/src/modules/module-protocol-pulse/modules/module-zeroconf-publish.c
+++ b/src/modules/module-protocol-pulse/modules/module-zeroconf-publish.c
@@ -15,7 +15,14 @@
#include "../module.h"
#include "../pulse-server.h"
#include "../server.h"
-#include "../../zeroconf-utils/zeroconf.h"
+#include "../../module-zeroconf-discover/avahi-poll.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
/** \page page_pulse_module_zeroconf_publish Zeroconf Publish
*
@@ -45,17 +52,32 @@ PW_LOG_TOPIC_STATIC(mod_topic, "mod." NAME);
#define SERVICE_DATA_ID "module-zeroconf-publish.service"
+enum service_subtype {
+ SUBTYPE_HARDWARE,
+ SUBTYPE_VIRTUAL,
+ SUBTYPE_MONITOR
+};
+
struct service {
struct spa_list link;
struct module_zeroconf_publish_data *userdata;
+ AvahiEntryGroup *entry_group;
+ AvahiStringList *txt;
struct server *server;
+ const char *service_type;
+ enum service_subtype subtype;
+
+ char *name;
+ bool is_sink;
+
struct sample_spec ss;
struct channel_map cm;
struct pw_properties *props;
+ char service_name[AVAHI_LABEL_MAX];
unsigned published:1;
};
@@ -69,8 +91,8 @@ struct module_zeroconf_publish_data {
struct spa_hook manager_listener;
struct spa_hook impl_listener;
- struct pw_zeroconf *zeroconf;
- struct spa_hook zeroconf_listener;
+ AvahiPoll *avahi_poll;
+ AvahiClient *client;
/* lists of services */
struct spa_list pending;
@@ -94,43 +116,47 @@ static const struct pw_core_events core_events = {
.error = on_core_error,
};
-static void unpublish_service(struct service *s)
+static void get_service_name(struct pw_manager_object *o, char *buf, size_t length)
{
- const char *device;
+ const char *hn, *un, *n;
- spa_list_remove(&s->link);
- spa_list_append(&s->userdata->pending, &s->link);
- s->published = false;
- s->server = NULL;
+ hn = pw_get_host_name();
+ un = pw_get_user_name();
+ n = pw_properties_get(o->props, PW_KEY_NODE_DESCRIPTION);
- device = pw_properties_get(s->props, "device");
-
- pw_log_info("unpublished service: %s", device);
-
- pw_zeroconf_set_announce(s->userdata->zeroconf, s, NULL);
-}
-
-static void unpublish_all_services(struct module_zeroconf_publish_data *d)
-{
- struct service *s;
- spa_list_consume(s, &d->published, link)
- unpublish_service(s);
+ snprintf(buf, length, "%s@%s: %s", un, hn, n);
}
static void service_free(struct service *s)
{
pw_log_debug("service %p: free", s);
- if (s->published)
- unpublish_service(s);
+ if (s->entry_group)
+ avahi_entry_group_free(s->entry_group);
+
+ if (s->name)
+ free(s->name);
pw_properties_free(s->props);
+ avahi_string_list_free(s->txt);
spa_list_remove(&s->link);
- /* no need to free, the service is added as custom
- * data on the object */
}
-#define PA_CHANNEL_MAP_SNPRINT_MAX (CHANNELS_MAX * 32)
+static void unpublish_service(struct service *s)
+{
+ spa_list_remove(&s->link);
+ spa_list_append(&s->userdata->pending, &s->link);
+ s->published = false;
+ s->server = NULL;
+}
+
+static void unpublish_all_services(struct module_zeroconf_publish_data *d)
+{
+ struct service *s;
+
+ spa_list_consume(s, &d->published, link)
+ unpublish_service(s);
+}
static char* channel_map_snprint(char *s, size_t l, const struct channel_map *map)
{
@@ -162,39 +188,6 @@ static char* channel_map_snprint(char *s, size_t l, const struct channel_map *ma
return s;
}
-static void txt_record_server_data(struct pw_core_info *info, struct pw_properties *props)
-{
- struct utsname u;
-
- spa_assert(info);
-
- pw_properties_set(props, "server-version", PACKAGE_NAME" "PACKAGE_VERSION);
- pw_properties_set(props, "user-name", pw_get_user_name());
- pw_properties_set(props, "fqdn", pw_get_host_name());
- pw_properties_setf(props, "cookie", "0x%08x", info->cookie);
- if (uname(&u) >= 0)
- pw_properties_setf(props, "uname", "%s %s %s", u.sysname, u.machine, u.release);
-}
-
-static void fill_service_txt(const struct service *s, const struct pw_properties *props)
-{
- static const struct mapping {
- const char *pw_key, *txt_key;
- } mappings[] = {
- { PW_KEY_NODE_DESCRIPTION, "description" },
- { PW_KEY_DEVICE_VENDOR_NAME, "vendor-name" },
- { PW_KEY_DEVICE_PRODUCT_NAME, "product-name" },
- { PW_KEY_DEVICE_CLASS, "class" },
- { PW_KEY_DEVICE_FORM_FACTOR, "form-factor" },
- { PW_KEY_DEVICE_ICON_NAME, "icon-name" },
- };
- SPA_FOR_EACH_ELEMENT_VAR(mappings, m) {
- const char *value = pw_properties_get(props, m->pw_key);
- if (value != NULL)
- pw_properties_set(s->props, m->txt_key, value);
- }
-}
-
static void fill_service_data(struct module_zeroconf_publish_data *d, struct service *s,
struct pw_manager_object *o)
{
@@ -207,10 +200,6 @@ static void fill_service_data(struct module_zeroconf_publish_data *d, struct ser
struct card_info card_info = CARD_INFO_INIT;
struct device_info dev_info;
uint32_t flags = 0;
- const char *service_type, *subtype, *subtype_service[2];
- uint32_t n_subtype = 0;
- char cm[PA_CHANNEL_MAP_SNPRINT_MAX];
-
if (info == NULL || info->props == NULL)
return;
@@ -239,49 +228,19 @@ static void fill_service_data(struct module_zeroconf_publish_data *d, struct ser
s->ss = dev_info.ss;
s->cm = dev_info.map;
-
- s->props = pw_properties_new(NULL, NULL);
-
- txt_record_server_data(s->userdata->manager->info, s->props);
+ s->name = strdup(name);
+ s->props = pw_properties_copy(o->props);
if (is_sink) {
- service_type = SERVICE_TYPE_SINK;
- if (flags & SINK_HARDWARE) {
- subtype = "hardware";
- subtype_service[n_subtype++] = SERVICE_SUBTYPE_SINK_HARDWARE;
- } else {
- subtype = "virtual";
- subtype_service[n_subtype++] = SERVICE_SUBTYPE_SINK_VIRTUAL;
- }
+ s->is_sink = true;
+ s->service_type = SERVICE_TYPE_SINK;
+ s->subtype = flags & SINK_HARDWARE ? SUBTYPE_HARDWARE : SUBTYPE_VIRTUAL;
} else if (is_source) {
- service_type = SERVICE_TYPE_SOURCE;
- if (flags & SOURCE_HARDWARE) {
- subtype = "hardware";
- subtype_service[n_subtype++] = SERVICE_SUBTYPE_SOURCE_HARDWARE;
- } else {
- subtype = "virtual";
- subtype_service[n_subtype++] = SERVICE_SUBTYPE_SOURCE_VIRTUAL;
- }
- subtype_service[n_subtype++] = SERVICE_SUBTYPE_SOURCE_NON_MONITOR;
+ s->is_sink = false;
+ s->service_type = SERVICE_TYPE_SOURCE;
+ s->subtype = flags & SOURCE_HARDWARE ? SUBTYPE_HARDWARE : SUBTYPE_VIRTUAL;
} else
spa_assert_not_reached();
-
- pw_properties_set(s->props, "device", name);
- pw_properties_setf(s->props, "rate", "%u", s->ss.rate);
- pw_properties_setf(s->props, "channels", "%u", s->ss.channels);
- pw_properties_set(s->props, "format", format_id2paname(s->ss.format));
- pw_properties_set(s->props, "channel_map", channel_map_snprint(cm, sizeof(cm), &s->cm));
- pw_properties_set(s->props, "subtype", subtype);
-
- pw_properties_setf(s->props, PW_KEY_ZEROCONF_NAME, "%s@%s: %s",
- pw_get_user_name(), pw_get_host_name(), desc);
- pw_properties_set(s->props, PW_KEY_ZEROCONF_TYPE, service_type);
- pw_properties_setf(s->props, PW_KEY_ZEROCONF_SUBTYPES, "[ %s%s%s ]",
- n_subtype > 0 ? subtype_service[0] : "",
- n_subtype > 1 ? ", " : "",
- n_subtype > 1 ? subtype_service[1] : "");
-
- fill_service_txt(s, o->props);
}
static struct service *create_service(struct module_zeroconf_publish_data *d, struct pw_manager_object *o)
@@ -293,6 +252,8 @@ static struct service *create_service(struct module_zeroconf_publish_data *d, st
return NULL;
s->userdata = d;
+ s->entry_group = NULL;
+ get_service_name(o, s->service_name, sizeof(s->service_name));
spa_list_append(&d->pending, &s->link);
fill_service_data(d, s, o);
@@ -302,6 +263,127 @@ static struct service *create_service(struct module_zeroconf_publish_data *d, st
return s;
}
+static AvahiStringList* txt_record_server_data(struct pw_core_info *info, AvahiStringList *l)
+{
+ const char *t;
+ struct utsname u;
+
+ spa_assert(info);
+
+ l = avahi_string_list_add_pair(l, "server-version", PACKAGE_NAME" "PACKAGE_VERSION);
+
+ t = pw_get_user_name();
+ l = avahi_string_list_add_pair(l, "user-name", t);
+
+ if (uname(&u) >= 0) {
+ char sysname[sizeof(u.sysname) + sizeof(u.machine) + sizeof(u.release)];
+
+ snprintf(sysname, sizeof(sysname), "%s %s %s", u.sysname, u.machine, u.release);
+ l = avahi_string_list_add_pair(l, "uname", sysname);
+ }
+
+ t = pw_get_host_name();
+ l = avahi_string_list_add_pair(l, "fqdn", t);
+ l = avahi_string_list_add_printf(l, "cookie=0x%08x", info->cookie);
+
+ return l;
+}
+
+static void clear_entry_group(struct service *s)
+{
+ if (s->entry_group == NULL)
+ return;
+
+ avahi_entry_group_free(s->entry_group);
+ s->entry_group = NULL;
+}
+
+static void publish_service(struct service *s);
+
+static void service_entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata)
+{
+ struct service *s = userdata;
+
+ spa_assert(s);
+ if (!s->published) {
+ pw_log_info("cancel unpublished service: %s", s->service_name);
+ clear_entry_group(s);
+ return;
+ }
+
+ switch (state) {
+ case AVAHI_ENTRY_GROUP_ESTABLISHED:
+ pw_log_info("established service: %s", s->service_name);
+ break;
+ case AVAHI_ENTRY_GROUP_COLLISION:
+ {
+ char *t;
+
+ t = avahi_alternative_service_name(s->service_name);
+ pw_log_info("service name collision: renaming '%s' to '%s'", s->service_name, t);
+ snprintf(s->service_name, sizeof(s->service_name), "%s", t);
+ avahi_free(t);
+
+ unpublish_service(s);
+ publish_service(s);
+ break;
+ }
+ case AVAHI_ENTRY_GROUP_FAILURE:
+ pw_log_error("failed to establish service '%s': %s",
+ s->service_name,
+ avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g))));
+ unpublish_service(s);
+ clear_entry_group(s);
+ break;
+
+ case AVAHI_ENTRY_GROUP_UNCOMMITED:
+ case AVAHI_ENTRY_GROUP_REGISTERING:
+ break;
+ }
+}
+
+#define PA_CHANNEL_MAP_SNPRINT_MAX (CHANNELS_MAX * 32)
+
+static AvahiStringList *get_service_txt(const struct service *s)
+{
+ static const char * const subtype_text[] = {
+ [SUBTYPE_HARDWARE] = "hardware",
+ [SUBTYPE_VIRTUAL] = "virtual",
+ [SUBTYPE_MONITOR] = "monitor"
+ };
+
+ static const struct mapping {
+ const char *pw_key, *txt_key;
+ } mappings[] = {
+ { PW_KEY_NODE_DESCRIPTION, "description" },
+ { PW_KEY_DEVICE_VENDOR_NAME, "vendor-name" },
+ { PW_KEY_DEVICE_PRODUCT_NAME, "product-name" },
+ { PW_KEY_DEVICE_CLASS, "class" },
+ { PW_KEY_DEVICE_FORM_FACTOR, "form-factor" },
+ { PW_KEY_DEVICE_ICON_NAME, "icon-name" },
+ };
+
+ char cm[PA_CHANNEL_MAP_SNPRINT_MAX];
+ AvahiStringList *txt = NULL;
+
+ txt = txt_record_server_data(s->userdata->manager->info, txt);
+
+ txt = avahi_string_list_add_pair(txt, "device", s->name);
+ txt = avahi_string_list_add_printf(txt, "rate=%u", s->ss.rate);
+ txt = avahi_string_list_add_printf(txt, "channels=%u", s->ss.channels);
+ txt = avahi_string_list_add_pair(txt, "format", format_id2paname(s->ss.format));
+ txt = avahi_string_list_add_pair(txt, "channel_map", channel_map_snprint(cm, sizeof(cm), &s->cm));
+ txt = avahi_string_list_add_pair(txt, "subtype", subtype_text[s->subtype]);
+
+ SPA_FOR_EACH_ELEMENT_VAR(mappings, m) {
+ const char *value = pw_properties_get(s->props, m->pw_key);
+ if (value != NULL)
+ txt = avahi_string_list_add_pair(txt, m->txt_key, value);
+ }
+
+ return txt;
+}
+
static struct server *find_server(struct service *s, int *proto, uint16_t *port)
{
struct module_zeroconf_publish_data *d = s->userdata;
@@ -310,47 +392,109 @@ static struct server *find_server(struct service *s, int *proto, uint16_t *port)
spa_list_for_each(server, &impl->servers, link) {
if (server->addr.ss_family == AF_INET) {
- *proto = 4;
+ *proto = AVAHI_PROTO_INET;
*port = ntohs(((struct sockaddr_in*) &server->addr)->sin_port);
return server;
} else if (server->addr.ss_family == AF_INET6) {
- *proto = 6;
+ *proto = AVAHI_PROTO_INET6;
*port = ntohs(((struct sockaddr_in6*) &server->addr)->sin6_port);
return server;
}
}
+
return NULL;
}
static void publish_service(struct service *s)
{
struct module_zeroconf_publish_data *d = s->userdata;
- int proto, res;
+ int proto;
uint16_t port;
- struct server *server = find_server(s, &proto, &port);
- const char *device;
+ struct server *server = find_server(s, &proto, &port);
if (!server)
return;
- device = pw_properties_get(s->props, "device");
-
pw_log_debug("found server:%p proto:%d port:%d", server, proto, port);
- pw_properties_setf(s->props, PW_KEY_ZEROCONF_PROTO, "%d", proto);
- pw_properties_setf(s->props, PW_KEY_ZEROCONF_PORT, "%d", port);
-
- if ((res = pw_zeroconf_set_announce(s->userdata->zeroconf, s, &s->props->dict)) < 0) {
- pw_log_error("failed to announce service %s: %s", device, spa_strerror(res));
+ if (!d->client || avahi_client_get_state(d->client) != AVAHI_CLIENT_S_RUNNING)
return;
+
+ s->published = true;
+ if (!s->entry_group) {
+ s->entry_group = avahi_entry_group_new(d->client, service_entry_group_callback, s);
+ if (s->entry_group == NULL) {
+ pw_log_error("avahi_entry_group_new(): %s",
+ avahi_strerror(avahi_client_errno(d->client)));
+ goto error;
+ }
+ } else {
+ avahi_entry_group_reset(s->entry_group);
+ }
+
+ if (s->txt == NULL)
+ s->txt = get_service_txt(s);
+
+ if (avahi_entry_group_add_service_strlst(
+ s->entry_group,
+ AVAHI_IF_UNSPEC, proto,
+ 0,
+ s->service_name,
+ s->service_type,
+ NULL,
+ NULL,
+ port,
+ s->txt) < 0) {
+ pw_log_error("avahi_entry_group_add_service_strlst(): %s",
+ avahi_strerror(avahi_client_errno(d->client)));
+ goto error;
+ }
+
+ if (avahi_entry_group_add_service_subtype(
+ s->entry_group,
+ AVAHI_IF_UNSPEC, proto,
+ 0,
+ s->service_name,
+ s->service_type,
+ NULL,
+ s->is_sink ? (s->subtype == SUBTYPE_HARDWARE ? SERVICE_SUBTYPE_SINK_HARDWARE : SERVICE_SUBTYPE_SINK_VIRTUAL) :
+ (s->subtype == SUBTYPE_HARDWARE ? SERVICE_SUBTYPE_SOURCE_HARDWARE : (s->subtype == SUBTYPE_VIRTUAL ? SERVICE_SUBTYPE_SOURCE_VIRTUAL : SERVICE_SUBTYPE_SOURCE_MONITOR))) < 0) {
+
+ pw_log_error("avahi_entry_group_add_service_subtype(): %s",
+ avahi_strerror(avahi_client_errno(d->client)));
+ goto error;
+ }
+
+ if (!s->is_sink && s->subtype != SUBTYPE_MONITOR) {
+ if (avahi_entry_group_add_service_subtype(
+ s->entry_group,
+ AVAHI_IF_UNSPEC, proto,
+ 0,
+ s->service_name,
+ SERVICE_TYPE_SOURCE,
+ NULL,
+ SERVICE_SUBTYPE_SOURCE_NON_MONITOR) < 0) {
+ pw_log_error("avahi_entry_group_add_service_subtype(): %s",
+ avahi_strerror(avahi_client_errno(d->client)));
+ goto error;
+ }
+ }
+
+ if (avahi_entry_group_commit(s->entry_group) < 0) {
+ pw_log_error("avahi_entry_group_commit(): %s",
+ avahi_strerror(avahi_client_errno(d->client)));
+ goto error;
}
spa_list_remove(&s->link);
spa_list_append(&d->published, &s->link);
- s->published = true;
s->server = server;
- pw_log_info("published service: %s", device);
+ pw_log_info("created service: %s", s->service_name);
+ return;
+
+error:
+ s->published = false;
return;
}
@@ -362,6 +506,62 @@ static void publish_pending(struct module_zeroconf_publish_data *data)
publish_service(s);
}
+static void clear_pending_entry_groups(struct module_zeroconf_publish_data *data)
+{
+ struct service *s;
+
+ spa_list_for_each(s, &data->pending, link)
+ clear_entry_group(s);
+}
+
+static void client_callback(AvahiClient *c, AvahiClientState state, void *d)
+{
+ struct module_zeroconf_publish_data *data = d;
+
+ spa_assert(c);
+ spa_assert(data);
+
+ data->client = c;
+
+ switch (state) {
+ case AVAHI_CLIENT_S_RUNNING:
+ pw_log_info("the avahi daemon is up and running");
+ publish_pending(data);
+ break;
+ case AVAHI_CLIENT_S_COLLISION:
+ pw_log_error("host name collision");
+ unpublish_all_services(d);
+ break;
+ case AVAHI_CLIENT_FAILURE:
+ {
+ int err = avahi_client_errno(data->client);
+
+ pw_log_error("avahi client failure: %s", avahi_strerror(err));
+
+ unpublish_all_services(data);
+ clear_pending_entry_groups(data);
+ avahi_client_free(data->client);
+ data->client = NULL;
+
+ if (err == AVAHI_ERR_DISCONNECTED) {
+ data->client = avahi_client_new(data->avahi_poll, AVAHI_CLIENT_NO_FAIL, client_callback, data, &err);
+ if (data->client == NULL)
+ pw_log_error("failed to create avahi client: %s", avahi_strerror(err));
+ }
+
+ if (data->client == NULL)
+ module_schedule_unload(data->module);
+
+ break;
+ }
+ case AVAHI_CLIENT_CONNECTING:
+ pw_log_info("connecting to the avahi daemon...");
+ break;
+ default:
+ break;
+ }
+}
+
static void manager_removed(void *d, struct pw_manager_object *o)
{
if (!pw_manager_object_is_sink(o) && !pw_manager_object_is_source(o))
@@ -424,6 +624,7 @@ static void impl_server_stopped(void *data, struct server *server)
if (s->server == server)
unpublish_service(s);
}
+
publish_pending(d);
}
@@ -433,18 +634,10 @@ static const struct impl_events impl_events = {
.server_stopped = impl_server_stopped,
};
-static void on_zeroconf_error(void *data, int err, const char *message)
-{
- pw_log_error("got zeroconf error %d: %s", err, message);
-}
-static const struct pw_zeroconf_events zeroconf_events = {
- PW_VERSION_ZEROCONF_EVENTS,
- .error = on_zeroconf_error,
-};
-
static int module_zeroconf_publish_load(struct module *module)
{
struct module_zeroconf_publish_data *data = module->user_data;
+ int error;
data->core = pw_context_connect(module->impl->context, NULL, 0);
if (data->core == NULL) {
@@ -456,22 +649,24 @@ static int module_zeroconf_publish_load(struct module *module)
&data->core_listener,
&core_events, data);
+ data->avahi_poll = pw_avahi_poll_new(module->impl->context);
+
+ data->client = avahi_client_new(data->avahi_poll, AVAHI_CLIENT_NO_FAIL,
+ client_callback, data, &error);
+ if (!data->client) {
+ pw_log_error("failed to create avahi client: %s", avahi_strerror(error));
+ return -errno;
+ }
+
data->manager = pw_manager_new(data->core);
if (data->manager == NULL) {
pw_log_error("failed to create pipewire manager: %m");
return -errno;
}
+
pw_manager_add_listener(data->manager, &data->manager_listener,
&manager_events, data);
- data->zeroconf = pw_zeroconf_new(module->impl->context, NULL);
- if (!data->zeroconf) {
- pw_log_error("failed to create zeroconf: %m");
- return -errno;
- }
- pw_zeroconf_add_listener(data->zeroconf, &data->zeroconf_listener,
- &zeroconf_events, data);
-
impl_add_listener(module->impl, &data->impl_listener, &impl_events, data);
return 0;
@@ -489,18 +684,22 @@ static int module_zeroconf_publish_unload(struct module *module)
spa_list_consume(s, &d->pending, link)
service_free(s);
- if (d->zeroconf) {
- spa_hook_remove(&d->zeroconf_listener);
- pw_zeroconf_destroy(d->zeroconf);
- }
+ if (d->client)
+ avahi_client_free(d->client);
+
+ if (d->avahi_poll)
+ pw_avahi_poll_free(d->avahi_poll);
+
if (d->manager != NULL) {
spa_hook_remove(&d->manager_listener);
pw_manager_destroy(d->manager);
}
+
if (d->core != NULL) {
spa_hook_remove(&d->core_listener);
pw_core_disconnect(d->core);
}
+
return 0;
}
diff --git a/src/modules/module-protocol-pulse/pulse-server.c b/src/modules/module-protocol-pulse/pulse-server.c
index 38d967777..59610ef57 100644
--- a/src/modules/module-protocol-pulse/pulse-server.c
+++ b/src/modules/module-protocol-pulse/pulse-server.c
@@ -1258,6 +1258,8 @@ static void stream_param_changed(void *data, uint32_t id, const struct spa_pod *
pw_stream_set_control(stream->stream,
SPA_PROP_mute, 1, &val, 0);
}
+ if (stream->corked)
+ stream_set_paused(stream, true, "cork after create");
/* if peer exists, reply immediately, otherwise reply when the link is created */
peer = find_linked(stream->client->manager, stream->id, stream->direction);
@@ -1619,7 +1621,7 @@ static int do_create_playback_stream(struct client *client, uint32_t command, ui
struct pw_manager_object *o;
bool is_monitor;
- props = pw_properties_new(NULL, NULL);
+ props = pw_properties_copy(client->props);
if (props == NULL)
goto error_errno;
@@ -1779,7 +1781,6 @@ static int do_create_playback_stream(struct client *client, uint32_t command, ui
goto error_errno;
stream->corked = corked;
- stream->is_paused = corked;
stream->adjust_latency = adjust_latency;
stream->early_requests = early_requests;
stream->volume = volume;
@@ -1804,8 +1805,6 @@ static int do_create_playback_stream(struct client *client, uint32_t command, ui
flags = 0;
if (no_move)
flags |= PW_STREAM_FLAG_DONT_RECONNECT;
- if (corked)
- flags |= PW_STREAM_FLAG_INACTIVE;
if (sink_name != NULL) {
if (o != NULL)
@@ -1908,7 +1907,7 @@ static int do_create_record_stream(struct client *client, uint32_t command, uint
struct pw_manager_object *o;
bool is_monitor = false;
- props = pw_properties_new(NULL, NULL);
+ props = pw_properties_copy(client->props);
if (props == NULL)
goto error_errno;
@@ -2060,7 +2059,6 @@ static int do_create_record_stream(struct client *client, uint32_t command, uint
goto error_errno;
stream->corked = corked;
- stream->is_paused = corked;
stream->adjust_latency = adjust_latency;
stream->early_requests = early_requests;
stream->volume = volume;
@@ -2088,8 +2086,6 @@ static int do_create_record_stream(struct client *client, uint32_t command, uint
flags = 0;
if (no_move)
flags |= PW_STREAM_FLAG_DONT_RECONNECT;
- if (corked)
- flags |= PW_STREAM_FLAG_INACTIVE;
if (direct_on_input_idx != SPA_ID_INVALID) {
dont_inhibit_auto_suspend = false;
@@ -2302,7 +2298,7 @@ static int do_create_upload_stream(struct client *client, uint32_t command, uint
struct message *reply;
int res;
- if ((props = pw_properties_new(NULL, NULL)) == NULL)
+ if ((props = pw_properties_copy(client->props)) == NULL)
goto error_errno;
if ((res = message_get(m,
@@ -4072,45 +4068,6 @@ static const char *get_media_name(struct pw_node_info *info)
return media_name;
}
-static int fill_node_info_proplist(struct message *m, const struct spa_dict *node_props,
- const struct pw_manager_object *client)
-{
- struct pw_client_info *client_info = client ? client->info : NULL;
- uint32_t n_items, n;
- struct spa_dict dict, *client_props = NULL;
- const struct spa_dict_item *it;
- struct spa_dict_item *items, *it2;
-
- n_items = node_props->n_items;
- if (client_info && client_info->props) {
- client_props = client_info->props;
- n_items += client_props->n_items;
- }
-
- dict.n_items = n = 0;
- dict.items = items = alloca(n_items * sizeof(struct spa_dict_item));
-
- spa_dict_for_each(it, node_props)
- items[n++] = *it;
- dict.n_items = n;
-
- if (client_props) {
- spa_dict_for_each(it, client_props) {
- if (spa_streq(it->key, PW_KEY_OBJECT_ID) ||
- spa_streq(it->key, PW_KEY_OBJECT_SERIAL))
- continue;
-
- if ((it2 = (struct spa_dict_item*)spa_dict_lookup_item(&dict, it->key)))
- it2->value = it->value;
- else
- items[n++] = *it;
- }
- dict.n_items = n;
- }
- message_put(m, TAG_PROPLIST, &dict, TAG_INVALID);
- return 0;
-}
-
static int fill_sink_input_info(struct client *client, struct message *m,
struct pw_manager_object *o)
{
@@ -4171,16 +4128,10 @@ static int fill_sink_input_info(struct client *client, struct message *m,
message_put(m,
TAG_BOOLEAN, dev_info.volume_info.mute, /* muted */
TAG_INVALID);
- if (client->version >= 13) {
- int res;
- struct pw_manager_object *c = NULL;
- if (client_id != SPA_ID_INVALID) {
- struct selector sel = { .id = client_id, .type = pw_manager_object_is_client, };
- c = select_object(manager, &sel);
- }
- if ((res = fill_node_info_proplist(m, info->props, c)) < 0)
- return res;
- }
+ if (client->version >= 13)
+ message_put(m,
+ TAG_PROPLIST, info->props,
+ TAG_INVALID);
if (client->version >= 19)
message_put(m,
TAG_BOOLEAN, corked, /* corked */
@@ -4256,16 +4207,10 @@ static int fill_source_output_info(struct client *client, struct message *m,
TAG_STRING, "PipeWire", /* resample method */
TAG_STRING, "PipeWire", /* driver */
TAG_INVALID);
- if (client->version >= 13) {
- int res;
- struct pw_manager_object *c = NULL;
- if (client_id != SPA_ID_INVALID) {
- struct selector sel = { .id = client_id, .type = pw_manager_object_is_client, };
- c = select_object(manager, &sel);
- }
- if ((res = fill_node_info_proplist(m, info->props, c)) < 0)
- return res;
- }
+ if (client->version >= 13)
+ message_put(m,
+ TAG_PROPLIST, info->props,
+ TAG_INVALID);
if (client->version >= 19)
message_put(m,
TAG_BOOLEAN, corked, /* corked */
@@ -4754,6 +4699,7 @@ static int do_set_profile(struct client *client, uint32_t command, uint32_t tag,
static int do_set_default(struct client *client, uint32_t command, uint32_t tag, struct message *m)
{
struct pw_manager *manager = client->manager;
+ struct pw_manager_object *o;
const char *name, *str;
int res;
bool sink = command == COMMAND_SET_DEFAULT_SINK;
@@ -4770,10 +4716,10 @@ static int do_set_default(struct client *client, uint32_t command, uint32_t tag,
if (spa_streq(name, "@NONE@"))
name = NULL;
+ if (name != NULL && (o = find_device(client, SPA_ID_INVALID, name, sink, NULL)) == NULL)
+ return -ENOENT;
+
if (name != NULL) {
- struct pw_manager_object *o;
- if ((o = find_device(client, SPA_ID_INVALID, name, sink, NULL)) == NULL)
- return -ENOENT;
if (o->props && (str = pw_properties_get(o->props, PW_KEY_NODE_NAME)) != NULL)
name = str;
else if (spa_strendswith(name, ".monitor"))
diff --git a/src/modules/module-protocol-pulse/utils.c b/src/modules/module-protocol-pulse/utils.c
index 6b41fd9a1..e6b24e708 100644
--- a/src/modules/module-protocol-pulse/utils.c
+++ b/src/modules/module-protocol-pulse/utils.c
@@ -82,7 +82,7 @@ int check_flatpak(struct client *client, pid_t pid)
int root_fd, info_fd, res;
struct stat stat_buf;
- snprintf(root_path, sizeof(root_path), "/proc/%ld/root", (long) pid);
+ sprintf(root_path, "/proc/%ld/root", (long) pid);
root_fd = openat(AT_FDCWD, root_path, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY);
if (root_fd == -1) {
res = -errno;
diff --git a/src/modules/module-raop-discover.c b/src/modules/module-raop-discover.c
index 3675b003e..436972ac0 100644
--- a/src/modules/module-raop-discover.c
+++ b/src/modules/module-raop-discover.c
@@ -19,8 +19,12 @@
#include
#include
-#include "zeroconf-utils/zeroconf.h"
+#include
+#include
+#include
+
#include "module-protocol-pulse/format.h"
+#include "module-zeroconf-discover/avahi-poll.h"
/** \page page_module_raop_discover RAOP Discover
*
@@ -125,20 +129,29 @@ struct impl {
struct pw_properties *properties;
- struct pw_zeroconf *zeroconf;
- struct spa_hook zeroconf_listener;
+ AvahiPoll *avahi_poll;
+ AvahiClient *client;
+ AvahiServiceBrowser *sink_browser;
struct spa_list tunnel_list;
};
+struct tunnel_info {
+ const char *name;
+};
+
+#define TUNNEL_INFO(...) ((struct tunnel_info){ __VA_ARGS__ })
+
struct tunnel {
struct spa_list link;
- char *name;
+ struct tunnel_info info;
struct pw_impl_module *module;
struct spa_hook module_listener;
};
-static struct tunnel *tunnel_new(struct impl *impl, const char *name)
+static int start_client(struct impl *impl);
+
+static struct tunnel *make_tunnel(struct impl *impl, const struct tunnel_info *info)
{
struct tunnel *t;
@@ -146,28 +159,28 @@ static struct tunnel *tunnel_new(struct impl *impl, const char *name)
if (t == NULL)
return NULL;
- t->name = strdup(name);
+ t->info.name = strdup(info->name);
spa_list_append(&impl->tunnel_list, &t->link);
return t;
}
-static struct tunnel *find_tunnel(struct impl *impl, const char *name)
+static struct tunnel *find_tunnel(struct impl *impl, const struct tunnel_info *info)
{
struct tunnel *t;
spa_list_for_each(t, &impl->tunnel_list, link) {
- if (spa_streq(t->name, name))
+ if (spa_streq(t->info.name, info->name))
return t;
}
return NULL;
}
-static void tunnel_free(struct tunnel *t)
+static void free_tunnel(struct tunnel *t)
{
spa_list_remove(&t->link);
if (t->module)
pw_impl_module_destroy(t->module);
- free(t->name);
+ free((char *) t->info.name);
free(t);
}
@@ -176,9 +189,14 @@ static void impl_free(struct impl *impl)
struct tunnel *t;
spa_list_consume(t, &impl->tunnel_list, link)
- tunnel_free(t);
- if (impl->zeroconf)
- pw_zeroconf_destroy(impl->zeroconf);
+ free_tunnel(t);
+
+ if (impl->sink_browser)
+ avahi_service_browser_free(impl->sink_browser);
+ if (impl->client)
+ avahi_client_free(impl->client);
+ if (impl->avahi_poll)
+ pw_avahi_poll_free(impl->avahi_poll);
pw_properties_free(impl->properties);
free(impl);
}
@@ -206,6 +224,75 @@ static bool str_in_list(const char *haystack, const char *delimiters, const char
return false;
}
+static void pw_properties_from_avahi_string(const char *key, const char *value,
+ struct pw_properties *props)
+{
+ if (spa_streq(key, "device")) {
+ pw_properties_set(props, "raop.device", value);
+ }
+ else if (spa_streq(key, "tp")) {
+ /* transport protocol, "UDP", "TCP", "UDP,TCP" */
+ if (str_in_list(value, ",", "UDP"))
+ value = "udp";
+ else if (str_in_list(value, ",", "TCP"))
+ value = "tcp";
+ pw_properties_set(props, "raop.transport", value);
+ } else if (spa_streq(key, "et")) {
+ /* RAOP encryption types:
+ * 0 = none,
+ * 1 = RSA,
+ * 3 = FairPlay,
+ * 4 = MFiSAP (/auth-setup),
+ * 5 = FairPlay SAPv2.5 */
+ if (str_in_list(value, ",", "5"))
+ value = "fp_sap25";
+ else if (str_in_list(value, ",", "4"))
+ value = "auth_setup";
+ else if (str_in_list(value, ",", "1"))
+ value = "RSA";
+ else
+ value = "none";
+ pw_properties_set(props, "raop.encryption.type", value);
+ } else if (spa_streq(key, "cn")) {
+ /* Supported audio codecs:
+ * 0 = PCM,
+ * 1 = ALAC,
+ * 2 = AAC,
+ * 3 = AAC ELD. */
+ if (str_in_list(value, ",", "0"))
+ value = "PCM";
+ else if (str_in_list(value, ",", "1"))
+ value = "ALAC";
+ else if (str_in_list(value, ",", "2"))
+ value = "AAC";
+ else if (str_in_list(value, ",", "3"))
+ value = "AAC-ELD";
+ else
+ value = "unknown";
+ pw_properties_set(props, "raop.audio.codec", value);
+ } else if (spa_streq(key, "ch")) {
+ /* Number of channels */
+ pw_properties_set(props, PW_KEY_AUDIO_CHANNELS, value);
+ } else if (spa_streq(key, "ss")) {
+ /* Sample size */
+ if (spa_streq(value, "16"))
+ value = "S16";
+ else if (spa_streq(value, "24"))
+ value = "S24";
+ else if (spa_streq(value, "32"))
+ value = "S32";
+ else
+ value = "UNKNOWN";
+ pw_properties_set(props, PW_KEY_AUDIO_FORMAT, value);
+ } else if (spa_streq(key, "sr")) {
+ /* Sample rate */
+ pw_properties_set(props, PW_KEY_AUDIO_RATE, value);
+ } else if (spa_streq(key, "am")) {
+ /* Device model */
+ pw_properties_set(props, "device.model", value);
+ }
+}
+
static void submodule_destroy(void *data)
{
struct tunnel *t = data;
@@ -277,124 +364,76 @@ static int rule_matched(void *data, const char *location, const char *action,
return res;
}
-static void pw_properties_from_zeroconf(const char *key, const char *value,
- struct pw_properties *props)
+static void resolver_cb(AvahiServiceResolver *r, AvahiIfIndex interface, AvahiProtocol protocol,
+ AvahiResolverEvent event, const char *name, const char *type, const char *domain,
+ const char *host_name, const AvahiAddress *a, uint16_t port, AvahiStringList *txt,
+ AvahiLookupResultFlags flags, void *userdata)
{
- if (spa_streq(key, PW_KEY_ZEROCONF_IFINDEX)) {
- pw_properties_set(props, "raop.ifindex", value);
- }
- else if (spa_streq(key, PW_KEY_ZEROCONF_ADDRESS)) {
- pw_properties_set(props, "raop.ip", value);
- }
- else if (spa_streq(key, PW_KEY_ZEROCONF_PORT)) {
- pw_properties_set(props, "raop.port", value);
- }
- else if (spa_streq(key, PW_KEY_ZEROCONF_NAME)) {
- pw_properties_set(props, "raop.name", value);
- }
- else if (spa_streq(key, PW_KEY_ZEROCONF_HOSTNAME)) {
- pw_properties_set(props, "raop.hostname", value);
- }
- else if (spa_streq(key, PW_KEY_ZEROCONF_DOMAIN)) {
- pw_properties_set(props, "raop.domain", value);
- }
- else if (spa_streq(key, "device")) {
- pw_properties_set(props, "raop.device", value);
- }
- else if (spa_streq(key, "tp")) {
- /* transport protocol, "UDP", "TCP", "UDP,TCP" */
- if (str_in_list(value, ",", "UDP"))
- value = "udp";
- else if (str_in_list(value, ",", "TCP"))
- value = "tcp";
- pw_properties_set(props, "raop.transport", value);
- } else if (spa_streq(key, "et")) {
- /* RAOP encryption types:
- * 0 = none,
- * 1 = RSA,
- * 3 = FairPlay,
- * 4 = MFiSAP (/auth-setup),
- * 5 = FairPlay SAPv2.5 */
- if (str_in_list(value, ",", "5"))
- value = "fp_sap25";
- else if (str_in_list(value, ",", "4"))
- value = "auth_setup";
- else if (str_in_list(value, ",", "1"))
- value = "RSA";
- else
- value = "none";
- pw_properties_set(props, "raop.encryption.type", value);
- } else if (spa_streq(key, "cn")) {
- /* Supported audio codecs:
- * 0 = PCM,
- * 1 = ALAC,
- * 2 = AAC,
- * 3 = AAC ELD. */
- if (str_in_list(value, ",", "0"))
- value = "PCM";
- else if (str_in_list(value, ",", "1"))
- value = "ALAC";
- else if (str_in_list(value, ",", "2"))
- value = "AAC";
- else if (str_in_list(value, ",", "3"))
- value = "AAC-ELD";
- else
- value = "unknown";
- pw_properties_set(props, "raop.audio.codec", value);
- } else if (spa_streq(key, "ch")) {
- /* Number of channels */
- pw_properties_set(props, PW_KEY_AUDIO_CHANNELS, value);
- } else if (spa_streq(key, "ss")) {
- /* Sample size */
- if (spa_streq(value, "16"))
- value = "S16";
- else if (spa_streq(value, "24"))
- value = "S24";
- else if (spa_streq(value, "32"))
- value = "S32";
- else
- value = "UNKNOWN";
- pw_properties_set(props, PW_KEY_AUDIO_FORMAT, value);
- } else if (spa_streq(key, "sr")) {
- /* Sample rate */
- pw_properties_set(props, PW_KEY_AUDIO_RATE, value);
- } else if (spa_streq(key, "am")) {
- /* Device model */
- pw_properties_set(props, "device.model", value);
- }
-}
-
-static void on_zeroconf_added(void *data, const void *user, const struct spa_dict *info)
-{
- struct impl *impl = data;
- const char *name, *str;
+ struct impl *impl = userdata;
+ struct tunnel_info tinfo;
struct tunnel *t;
- const struct spa_dict_item *it;
+ const char *str, *link_local_range = "169.254.";
+ AvahiStringList *l;
struct pw_properties *props = NULL;
+ char at[AVAHI_ADDRESS_STR_MAX], if_suffix[16] = "";
- name = spa_dict_lookup(info, PW_KEY_ZEROCONF_NAME);
-
- t = find_tunnel(impl, name);
- if (t == NULL) {
- if ((t = tunnel_new(impl, name)) == NULL) {
- pw_log_error("Can't make tunnel: %m");
- goto done;
- }
- }
- if (t->module != NULL) {
- pw_log_info("found duplicate mdns entry for %s on IP %s - "
- "skipping tunnel creation", name,
- spa_dict_lookup(info, PW_KEY_ZEROCONF_ADDRESS));
+ if (event != AVAHI_RESOLVER_FOUND) {
+ pw_log_error("Resolving of '%s' failed: %s", name,
+ avahi_strerror(avahi_client_errno(impl->client)));
goto done;
}
- if ((props = pw_properties_new(NULL, NULL)) == NULL) {
+ avahi_address_snprint(at, sizeof(at), a);
+ if (spa_strstartswith(at, link_local_range))
+ pw_log_info("found link-local ip address %s for '%s'", at, name);
+
+ tinfo = TUNNEL_INFO(.name = name);
+
+ t = find_tunnel(impl, &tinfo);
+ if (t == NULL)
+ t = make_tunnel(impl, &tinfo);
+ if (t == NULL) {
+ pw_log_error("Can't make tunnel: %m");
+ goto done;
+ }
+ if (t->module != NULL) {
+ pw_log_info("found duplicate mdns entry for %s on IP %s - skipping tunnel creation", name, at);
+ goto done;
+ }
+
+ props = pw_properties_new(NULL, NULL);
+ if (props == NULL) {
pw_log_error("Can't allocate properties: %m");
goto done;
}
- spa_dict_for_each(it, info)
- pw_properties_from_zeroconf(it->key, it->value, props);
+ if (a->proto == AVAHI_PROTO_INET6 &&
+ a->data.ipv6.address[0] == 0xfe &&
+ (a->data.ipv6.address[1] & 0xc0) == 0x80)
+ snprintf(if_suffix, sizeof(if_suffix), "%%%d", interface);
+
+ /* For IPv4 link-local, bind to the discovery interface */
+ if (a->proto == AVAHI_PROTO_INET &&
+ spa_strstartswith(at, link_local_range))
+ snprintf(if_suffix, sizeof(if_suffix), "%%%d", interface);
+
+ pw_properties_setf(props, "raop.ip", "%s%s", at, if_suffix);
+ pw_properties_setf(props, "raop.ifindex", "%d", interface);
+ pw_properties_setf(props, "raop.port", "%u", port);
+ pw_properties_setf(props, "raop.name", "%s", name);
+ pw_properties_setf(props, "raop.hostname", "%s", host_name);
+ pw_properties_setf(props, "raop.domain", "%s", domain);
+
+ for (l = txt; l; l = l->next) {
+ char *key, *value;
+
+ if (avahi_string_list_get_pair(l, &key, &value, NULL) != 0)
+ break;
+
+ pw_properties_from_avahi_string(key, value, props);
+ avahi_free(key);
+ avahi_free(value);
+ }
if ((str = pw_properties_get(impl->properties, "raop.latency.ms")) != NULL)
pw_properties_set(props, "raop.latency.ms", str);
@@ -413,28 +452,123 @@ static void on_zeroconf_added(void *data, const void *user, const struct spa_dic
if (!minfo.matched)
pw_log_info("unmatched service found %s", str);
}
+
done:
+ avahi_service_resolver_free(r);
pw_properties_free(props);
}
-static void on_zeroconf_removed(void *data, const void *user, const struct spa_dict *info)
+
+static void browser_cb(AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol,
+ AvahiBrowserEvent event, const char *name, const char *type, const char *domain,
+ AvahiLookupResultFlags flags, void *userdata)
{
- struct impl *impl = data;
- const char *name;
+ struct impl *impl = userdata;
+ struct tunnel_info info;
struct tunnel *t;
- name = spa_dict_lookup(info, PW_KEY_ZEROCONF_NAME);
-
- if ((t = find_tunnel(impl, name)) == NULL)
+ if ((flags & AVAHI_LOOKUP_RESULT_LOCAL) && !impl->discover_local)
return;
- tunnel_free(t);
+ info = TUNNEL_INFO(.name = name);
+
+ t = find_tunnel(impl, &info);
+
+ switch (event) {
+ case AVAHI_BROWSER_NEW:
+ if (t != NULL) {
+ pw_log_info("found duplicate mdns entry - skipping tunnel creation");
+ return;
+ }
+ if (!(avahi_service_resolver_new(impl->client,
+ interface, protocol,
+ name, type, domain,
+ AVAHI_PROTO_UNSPEC, 0,
+ resolver_cb, impl)))
+ pw_log_error("can't make service resolver: %s",
+ avahi_strerror(avahi_client_errno(impl->client)));
+ break;
+ case AVAHI_BROWSER_REMOVE:
+ if (t == NULL)
+ return;
+ free_tunnel(t);
+ break;
+ default:
+ break;
+ }
+}
+
+
+static struct AvahiServiceBrowser *make_browser(struct impl *impl, const char *service_type)
+{
+ struct AvahiServiceBrowser *s;
+
+ s = avahi_service_browser_new(impl->client,
+ AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
+ service_type, NULL, 0,
+ browser_cb, impl);
+ if (s == NULL) {
+ pw_log_error("can't make browser for %s: %s", service_type,
+ avahi_strerror(avahi_client_errno(impl->client)));
+ }
+ return s;
+}
+
+static void client_callback(AvahiClient *c, AvahiClientState state, void *userdata)
+{
+ struct impl *impl = userdata;
+
+ impl->client = c;
+
+ switch (state) {
+ case AVAHI_CLIENT_S_REGISTERING:
+ case AVAHI_CLIENT_S_RUNNING:
+ case AVAHI_CLIENT_S_COLLISION:
+ if (impl->sink_browser == NULL)
+ impl->sink_browser = make_browser(impl, SERVICE_TYPE_SINK);
+ if (impl->sink_browser == NULL)
+ goto error;
+ break;
+ case AVAHI_CLIENT_FAILURE:
+ if (avahi_client_errno(c) == AVAHI_ERR_DISCONNECTED)
+ start_client(impl);
+
+ SPA_FALLTHROUGH;
+ case AVAHI_CLIENT_CONNECTING:
+ if (impl->sink_browser) {
+ avahi_service_browser_free(impl->sink_browser);
+ impl->sink_browser = NULL;
+ }
+ break;
+ default:
+ break;
+ }
+ return;
+error:
+ pw_impl_module_schedule_destroy(impl->module);
+}
+
+static int start_client(struct impl *impl)
+{
+ int res;
+ if ((impl->client = avahi_client_new(impl->avahi_poll,
+ AVAHI_CLIENT_NO_FAIL,
+ client_callback, impl,
+ &res)) == NULL) {
+ pw_log_error("can't create client: %s", avahi_strerror(res));
+ pw_impl_module_schedule_destroy(impl->module);
+ return -EIO;
+ }
+ return 0;
+}
+
+static int start_avahi(struct impl *impl)
+{
+
+ impl->avahi_poll = pw_avahi_poll_new(impl->context);
+
+ return start_client(impl);
}
-static const struct pw_zeroconf_events zeroconf_events = {
- PW_VERSION_ZEROCONF_EVENTS,
- .added = on_zeroconf_added,
- .removed = on_zeroconf_removed,
-};
SPA_EXPORT
int pipewire__module_init(struct pw_impl_module *module, const char *args)
@@ -442,7 +576,6 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
struct pw_context *context = pw_impl_module_get_context(module);
struct pw_properties *props;
struct impl *impl;
- const char *local;
int res;
PW_LOG_TOPIC_INIT(mod_topic);
@@ -466,24 +599,15 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
impl->context = context;
impl->properties = props;
- if ((local = pw_properties_get(impl->properties, "raop.discover-local")) == NULL)
- local = "false";
- pw_properties_set(impl->properties, PW_KEY_ZEROCONF_DISCOVER_LOCAL, local);
+ impl->discover_local = pw_properties_get_bool(impl->properties,
+ "raop.discover-local", false);
pw_impl_module_add_listener(module, &impl->module_listener, &module_events, impl);
pw_impl_module_update_properties(module, &SPA_DICT_INIT_ARRAY(module_props));
- if ((impl->zeroconf = pw_zeroconf_new(context, &props->dict)) == NULL) {
- pw_log_error("can't create zeroconf: %m");
- goto error_errno;
- }
- pw_zeroconf_add_listener(impl->zeroconf, &impl->zeroconf_listener,
- &zeroconf_events, impl);
+ start_avahi(impl);
- pw_zeroconf_set_browse(impl->zeroconf, NULL,
- &SPA_DICT_ITEMS(
- SPA_DICT_ITEM(PW_KEY_ZEROCONF_TYPE, SERVICE_TYPE_SINK)));
return 0;
error_errno:
diff --git a/src/modules/module-raop-sink.c b/src/modules/module-raop-sink.c
index 6e85f7d61..e217ff5b2 100644
--- a/src/modules/module-raop-sink.c
+++ b/src/modules/module-raop-sink.c
@@ -45,7 +45,6 @@
#include "network-utils.h"
#include "module-raop/rtsp-client.h"
-#include "module-raop/base64.h"
#include "module-rtp/rtp.h"
#include "module-rtp/stream.h"
@@ -131,6 +130,11 @@
PW_LOG_TOPIC(mod_topic, "mod." NAME);
#define PW_LOG_TOPIC_DEFAULT mod_topic
+#define BUFFER_SIZE (1u<<22)
+#define BUFFER_MASK (BUFFER_SIZE-1)
+#define BUFFER_SIZE2 (BUFFER_SIZE>>1)
+#define BUFFER_MASK2 (BUFFER_SIZE2-1)
+
#define FRAMES_PER_TCP_PACKET 4096
#define FRAMES_PER_UDP_PACKET 352
@@ -269,6 +273,13 @@ struct impl {
bool mute;
float volume;
+
+ struct spa_ringbuffer ring;
+ uint8_t buffer[BUFFER_SIZE];
+
+ struct spa_io_position *io_position;
+
+ uint32_t filled;
};
static inline void bit_writer(uint8_t **p, int *pos, uint8_t data, int len)
@@ -346,7 +357,7 @@ static int send_udp_sync_packet(struct impl *impl, uint32_t rtptime, unsigned in
res = sendmsg(impl->control_fd, &msg, MSG_NOSIGNAL);
if (res < 0) {
res = -errno;
- pw_log_warn("error sending control packet: %d (%m)", res);
+ pw_log_warn("error sending control packet: %d", res);
}
pw_log_debug("raop control sync: first:%d latency:%u now:%"PRIx64" rtptime:%u",
@@ -692,6 +703,49 @@ on_control_source_io(void *data, int fd, uint32_t mask)
}
}
+static void base64_encode(const uint8_t *data, size_t len, char *enc, char pad)
+{
+ static const char tab[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ size_t i;
+ for (i = 0; i < len; i += 3) {
+ uint32_t v;
+ v = data[i+0] << 16;
+ v |= (i+1 < len ? data[i+1] : 0) << 8;
+ v |= (i+2 < len ? data[i+2] : 0);
+ *enc++ = tab[(v >> (3*6)) & 0x3f];
+ *enc++ = tab[(v >> (2*6)) & 0x3f];
+ *enc++ = i+1 < len ? tab[(v >> (1*6)) & 0x3f] : pad;
+ *enc++ = i+2 < len ? tab[(v >> (0*6)) & 0x3f] : pad;
+ }
+ *enc = '\0';
+}
+
+static size_t base64_decode(const char *data, size_t len, uint8_t *dec)
+{
+ uint8_t tab[] = {
+ 62, -1, -1, -1, 63, 52, 53, 54, 55, 56,
+ 57, 58, 59, 60, 61, -1, -1, -1, -1, -1,
+ -1, -1, 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, -1, -1,
+ -1, -1, -1, -1, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+ 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 };
+ size_t i, j;
+ for (i = 0, j = 0; i < len; i += 4) {
+ uint32_t v;
+ v = tab[data[i+0]-43] << (3*6);
+ v |= tab[data[i+1]-43] << (2*6);
+ v |= (data[i+2] == '=' ? 0 : tab[data[i+2]-43]) << (1*6);
+ v |= (data[i+3] == '=' ? 0 : tab[data[i+3]-43]);
+ dec[j++] = (v >> 16) & 0xff;
+ if (data[i+2] != '=') dec[j++] = (v >> 8) & 0xff;
+ if (data[i+3] != '=') dec[j++] = v & 0xff;
+ }
+ return j;
+}
+
SPA_PRINTF_FUNC(2,3)
static int MD5_hash(char hash[MD5_HASH_LENGTH+1], const char *fmt, ...)
{
@@ -707,9 +761,8 @@ static int MD5_hash(char hash[MD5_HASH_LENGTH+1], const char *fmt, ...)
size = MD5_DIGEST_LENGTH;
EVP_Digest(buffer, strlen(buffer), d, &size, EVP_md5(), NULL);
- explicit_bzero(buffer, sizeof(buffer));
for (i = 0; i < MD5_DIGEST_LENGTH; i++)
- snprintf(&hash[2*i], 3, "%02x", (uint8_t) d[i]);
+ sprintf(&hash[2*i], "%02x", (uint8_t) d[i]);
hash[MD5_HASH_LENGTH] = '\0';
return 0;
}
@@ -725,8 +778,7 @@ static int rtsp_add_raop_auth_header(struct impl *impl, const char *method)
char buf[256];
char enc[512];
spa_scnprintf(buf, sizeof(buf), "%s:%s", RAOP_AUTH_USER_NAME, impl->password);
- pw_base64_encode((uint8_t*)buf, strlen(buf), enc, '=');
- explicit_bzero(buf, sizeof(buf));
+ base64_encode((uint8_t*)buf, strlen(buf), enc, '=');
spa_scnprintf(auth, sizeof(auth), "Basic %s", enc);
}
else if (spa_streq(impl->auth_method, "Digest")) {
@@ -1084,8 +1136,8 @@ static int rsa_encrypt(uint8_t *data, int len, uint8_t *enc)
"imNVvYFZeCXg/IdTQ+x4IRdiXNv5hEew==";
char e[] = "AQAB";
- msize = pw_base64_decode(n, strlen(n), modulus);
- esize = pw_base64_decode(e, strlen(e), exponent);
+ msize = base64_decode(n, strlen(n), modulus);
+ esize = base64_decode(e, strlen(e), exponent);
#if OPENSSL_API_LEVEL >= 30000
EVP_PKEY *pkey = NULL;
@@ -1211,15 +1263,15 @@ static int rtsp_do_announce(struct impl *impl)
(res = pw_getrandom(impl->aes_iv, sizeof(impl->aes_iv), 0)) < 0)
return res;
- pw_base64_encode(rac, sizeof(rac), sac, '\0');
+ base64_encode(rac, sizeof(rac), sac, '\0');
pw_properties_set(impl->headers, "Apple-Challenge", sac);
rsa_len = rsa_encrypt(impl->aes_key, 16, rsakey);
if (rsa_len < 0)
return -rsa_len;
- pw_base64_encode(rsakey, rsa_len, key, '=');
- pw_base64_encode(impl->aes_iv, 16, iv, '=');
+ base64_encode(rsakey, rsa_len, key, '=');
+ base64_encode(impl->aes_iv, 16, iv, '=');
sdp = spa_aprintf("v=0\r\n"
"o=iTunes %s 0 IN IP%d %s\r\n"
@@ -1334,8 +1386,6 @@ static int rtsp_do_options_auth(struct impl *impl, const struct spa_dict *header
return -EINVAL;
impl->auth_method = strdup(tokens[0]);
- if (impl->auth_method == NULL)
- return -ENOMEM;
if (spa_streq(impl->auth_method, "Digest")) {
realm = find_attr(tokens, "realm");
@@ -1345,8 +1395,6 @@ static int rtsp_do_options_auth(struct impl *impl, const struct spa_dict *header
impl->realm = strdup(realm);
impl->nonce = strdup(nonce);
- if (impl->realm == NULL || impl->nonce == NULL)
- return -ENOMEM;
}
return rtsp_send(impl, "OPTIONS", NULL, NULL, rtsp_options_auth_reply);
@@ -1673,10 +1721,7 @@ static void impl_destroy(struct impl *impl)
pw_properties_free(impl->headers);
pw_properties_free(impl->stream_props);
pw_properties_free(impl->props);
- if (impl->password) {
- explicit_bzero(impl->password, strlen(impl->password));
- free(impl->password);
- }
+ free(impl->password);
free(impl);
}
diff --git a/src/modules/module-raop/base64.h b/src/modules/module-raop/base64.h
deleted file mode 100644
index d8906c287..000000000
--- a/src/modules/module-raop/base64.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/* PipeWire */
-/* SPDX-FileCopyrightText: Copyright © 2026 Wim Taymans */
-/* SPDX-License-Identifier: MIT */
-
-#ifndef PIPEWIRE_BASE64_H
-#define PIPEWIRE_BASE64_H
-
-#include
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-static inline void pw_base64_encode(const uint8_t *data, size_t len, char *enc, char pad)
-{
- static const char tab[] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- size_t i;
- for (i = 0; i < len; i += 3) {
- uint32_t v;
- v = data[i+0] << 16;
- v |= (i+1 < len ? data[i+1] : 0) << 8;
- v |= (i+2 < len ? data[i+2] : 0);
- *enc++ = tab[(v >> (3*6)) & 0x3f];
- *enc++ = tab[(v >> (2*6)) & 0x3f];
- *enc++ = i+1 < len ? tab[(v >> (1*6)) & 0x3f] : pad;
- *enc++ = i+2 < len ? tab[(v >> (0*6)) & 0x3f] : pad;
- }
- *enc = '\0';
-}
-
-static inline size_t pw_base64_decode(const char *data, size_t len, uint8_t *dec)
-{
- uint8_t tab[] = {
- 62, -1, -1, -1, 63, 52, 53, 54, 55, 56,
- 57, 58, 59, 60, 61, -1, -1, -1, -1, -1,
- -1, -1, 0, 1, 2, 3, 4, 5, 6, 7,
- 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
- 18, 19, 20, 21, 22, 23, 24, 25, -1, -1,
- -1, -1, -1, -1, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
- 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 };
- size_t i, j;
- for (i = 0, j = 0; i < len; i += 4) {
- uint32_t v;
- v = tab[data[i+0]-43] << (3*6);
- v |= tab[data[i+1]-43] << (2*6);
- v |= (data[i+2] == '=' ? 0 : tab[data[i+2]-43]) << (1*6);
- v |= (data[i+3] == '=' ? 0 : tab[data[i+3]-43]);
- dec[j++] = (v >> 16) & 0xff;
- if (data[i+2] != '=') dec[j++] = (v >> 8) & 0xff;
- if (data[i+3] != '=') dec[j++] = v & 0xff;
- }
- return j;
-}
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* PIPEWIRE_BASE64_H */
diff --git a/src/modules/module-raop/rtsp-client.c b/src/modules/module-raop/rtsp-client.c
index 4bcff8b88..fae71977c 100644
--- a/src/modules/module-raop/rtsp-client.c
+++ b/src/modules/module-raop/rtsp-client.c
@@ -445,10 +445,7 @@ on_source_io(void *data, int fd, uint32_t mask)
int res;
if (mask & (SPA_IO_ERR | SPA_IO_HUP)) {
- socklen_t len = sizeof(res);
- if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &res, &len) < 0)
- res = errno;
- res = -res;
+ res = -EPIPE;
goto error;
}
if (mask & SPA_IO_IN) {
@@ -481,7 +478,7 @@ int pw_rtsp_client_connect(struct pw_rtsp_client *client,
{
struct addrinfo hints;
struct addrinfo *result, *rp;
- int res, fd = -1;
+ int res, fd;
char port_str[12];
if (client->source != NULL)
diff --git a/src/modules/module-roc-sink.c b/src/modules/module-roc-sink.c
index 66a2c716b..39ca2bce1 100644
--- a/src/modules/module-roc-sink.c
+++ b/src/modules/module-roc-sink.c
@@ -120,6 +120,8 @@ struct module_roc_sink_data {
roc_endpoint *remote_control_addr;
int remote_control_port;
+
+ roc_log_level loglevel;
};
static void stream_destroy(void *d)
@@ -389,7 +391,8 @@ static const struct spa_dict_item module_roc_sink_info[] = {
"( remote.repair.port= ) "
"( remote.control.port= ) "
"( audio.position= ) "
- "( sink.props= { key=val ... } ) " },
+ "( sink.props= { key=val ... } ) "
+ "( log.level=|DEFAULT|NONE|RROR|INFO|DEBUG|TRACE ) " },
{ PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
};
@@ -510,6 +513,14 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
pw_log_error("can't connect: %m");
goto out;
}
+ if ((str = pw_properties_get(props, "log.level")) != NULL) {
+ const struct spa_log *log_conf = pw_log_get();
+ const roc_log_level default_level = pw_roc_log_level_pw_2_roc(log_conf->level);
+ if (pw_roc_parse_log_level(&data->loglevel, str, default_level)) {
+ pw_log_error("Invalid log level %s, using default", str);
+ data->loglevel = default_level;
+ }
+ }
pw_proxy_add_listener((struct pw_proxy*)data->core,
&data->core_proxy_listener,
diff --git a/src/modules/module-roc-source.c b/src/modules/module-roc-source.c
index a46189e5d..2173c6af1 100644
--- a/src/modules/module-roc-source.c
+++ b/src/modules/module-roc-source.c
@@ -140,6 +140,8 @@ struct module_roc_source_data {
roc_endpoint *local_control_addr;
int local_control_port;
+
+ roc_log_level loglevel;
};
static void stream_destroy(void *d)
@@ -428,7 +430,8 @@ static const struct spa_dict_item module_roc_source_info[] = {
"( local.repair.port= ) "
"( local.control.port= ) "
"( audio.position= ) "
- "( source.props= { key=value ... } ) " },
+ "( source.props= { key=value ... } ) "
+ "( log.level=|DEFAULT|NONE|RROR|INFO|DEBUG|TRACE ) " },
{ PW_KEY_MODULE_VERSION, PACKAGE_VERSION },
};
@@ -564,6 +567,14 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
} else {
data->fec_code = ROC_FEC_ENCODING_DEFAULT;
}
+ if ((str = pw_properties_get(props, "log.level")) != NULL) {
+ const struct spa_log *log_conf = pw_log_get();
+ const roc_log_level default_level = pw_roc_log_level_pw_2_roc(log_conf->level);
+ if (pw_roc_parse_log_level(&data->loglevel, str, default_level)) {
+ pw_log_error("Invalid log level %s, using default", str);
+ data->loglevel = default_level;
+ }
+ }
data->core = pw_context_get_object(data->module_context, PW_TYPE_INTERFACE_Core);
if (data->core == NULL) {
diff --git a/src/modules/module-roc/common.c b/src/modules/module-roc/common.c
index 475c5f40f..244c203dd 100644
--- a/src/modules/module-roc/common.c
+++ b/src/modules/module-roc/common.c
@@ -5,54 +5,17 @@
PW_LOG_TOPIC(roc_log_topic, "mod.roc.lib");
-static inline roc_log_level pw_roc_log_level_pw_2_roc(const enum spa_log_level pw_log_level)
-{
- switch (pw_log_level) {
- case SPA_LOG_LEVEL_NONE:
- return ROC_LOG_NONE;
- case SPA_LOG_LEVEL_ERROR:
- return ROC_LOG_ERROR;
- case SPA_LOG_LEVEL_WARN:
- return ROC_LOG_ERROR;
- case SPA_LOG_LEVEL_INFO:
- return ROC_LOG_INFO;
- case SPA_LOG_LEVEL_DEBUG:
- return ROC_LOG_DEBUG;
- case SPA_LOG_LEVEL_TRACE:
- return ROC_LOG_TRACE;
- default:
- return ROC_LOG_NONE;
- }
-}
-
-static inline enum spa_log_level pw_roc_log_level_roc_2_pw(const roc_log_level roc_log_level)
-{
- switch (roc_log_level) {
- case ROC_LOG_NONE:
- return SPA_LOG_LEVEL_NONE;
- case ROC_LOG_ERROR:
- return SPA_LOG_LEVEL_ERROR;
- case ROC_LOG_INFO:
- return SPA_LOG_LEVEL_INFO;
- case ROC_LOG_DEBUG:
- return SPA_LOG_LEVEL_DEBUG;
- case ROC_LOG_TRACE:
- return SPA_LOG_LEVEL_TRACE;
- default:
- return SPA_LOG_LEVEL_NONE;
- }
-}
-
-static void pw_roc_log_handler(const roc_log_message *message, void *argument)
-{
- const enum spa_log_level log_level = pw_roc_log_level_roc_2_pw(message->level);
- if (SPA_UNLIKELY(pw_log_topic_enabled(log_level, roc_log_topic))) {
- pw_log_logt(log_level, roc_log_topic, message->file, message->line, message->module, "%s", message->text);
- }
-}
-
void pw_roc_log_init(void)
{
roc_log_set_handler(pw_roc_log_handler, NULL);
roc_log_set_level(pw_roc_log_level_pw_2_roc(roc_log_topic->has_custom_level ? roc_log_topic->level : pw_log_level));
}
+
+void pw_roc_log_handler(const roc_log_message *message, void *argument)
+{
+ const enum spa_log_level log_level = pw_roc_log_level_roc_2_pw(message->level);
+ if (SPA_UNLIKELY(pw_log_topic_enabled(log_level, roc_log_topic))) {
+ pw_log_logt(log_level, roc_log_topic, message->file, message->line, message->module, message->text, "");
+ }
+}
+
diff --git a/src/modules/module-roc/common.h b/src/modules/module-roc/common.h
index d49e392fe..c94ac69a8 100644
--- a/src/modules/module-roc/common.h
+++ b/src/modules/module-roc/common.h
@@ -3,6 +3,7 @@
#include
#include
+#include
#include
#include
@@ -20,6 +21,7 @@
#define PW_ROC_STEREO_POSITIONS "[ FL FR ]"
void pw_roc_log_init(void);
+void pw_roc_log_handler(const roc_log_message *message, void *argument);
static inline int pw_roc_parse_fec_encoding(roc_fec_encoding *out, const char *str)
{
@@ -135,4 +137,62 @@ static inline void pw_roc_fec_encoding_to_proto(roc_fec_encoding fec_code, roc_p
}
}
+static inline roc_log_level pw_roc_log_level_pw_2_roc(const enum spa_log_level pw_log_level)
+{
+ switch (pw_log_level) {
+ case SPA_LOG_LEVEL_NONE:
+ return ROC_LOG_NONE;
+ case SPA_LOG_LEVEL_ERROR:
+ return ROC_LOG_ERROR;
+ case SPA_LOG_LEVEL_WARN:
+ return ROC_LOG_ERROR;
+ case SPA_LOG_LEVEL_INFO:
+ return ROC_LOG_INFO;
+ case SPA_LOG_LEVEL_DEBUG:
+ return ROC_LOG_DEBUG;
+ case SPA_LOG_LEVEL_TRACE:
+ return ROC_LOG_TRACE;
+ default:
+ return ROC_LOG_NONE;
+ }
+}
+
+static inline enum spa_log_level pw_roc_log_level_roc_2_pw(const roc_log_level roc_log_level)
+{
+ switch (roc_log_level) {
+ case ROC_LOG_NONE:
+ return SPA_LOG_LEVEL_NONE;
+ case ROC_LOG_ERROR:
+ return SPA_LOG_LEVEL_ERROR;
+ case ROC_LOG_INFO:
+ return SPA_LOG_LEVEL_INFO;
+ case ROC_LOG_DEBUG:
+ return SPA_LOG_LEVEL_DEBUG;
+ case ROC_LOG_TRACE:
+ return SPA_LOG_LEVEL_TRACE;
+ default:
+ return SPA_LOG_LEVEL_NONE;
+ }
+}
+
+static inline int pw_roc_parse_log_level(roc_log_level *loglevel, const char *str,
+ roc_log_level default_level)
+{
+ if (spa_streq(str, "DEFAULT"))
+ *loglevel = default_level;
+ else if (spa_streq(str, "NONE"))
+ *loglevel = ROC_LOG_NONE;
+ else if (spa_streq(str, "ERROR"))
+ *loglevel = ROC_LOG_ERROR;
+ else if (spa_streq(str, "INFO"))
+ *loglevel = ROC_LOG_INFO;
+ else if (spa_streq(str, "DEBUG"))
+ *loglevel = ROC_LOG_DEBUG;
+ else if (spa_streq(str, "TRACE"))
+ *loglevel = ROC_LOG_TRACE;
+ else
+ return -EINVAL;
+ return 0;
+}
+
#endif /* MODULE_ROC_COMMON_H */
diff --git a/src/modules/module-rtp-sap.c b/src/modules/module-rtp-sap.c
index cfbcbf419..c734758c3 100644
--- a/src/modules/module-rtp-sap.c
+++ b/src/modules/module-rtp-sap.c
@@ -1235,11 +1235,8 @@ static struct session *session_new_announce(struct impl *impl, struct node *node
sess->has_sdp = true;
}
- pw_log_debug("sending out initial SAP");
send_sap(impl, sess, 0);
- pw_log_debug("new announcement session up and running");
-
return sess;
error_free:
@@ -1838,7 +1835,6 @@ static int start_sap(struct impl *impl)
pw_timer_queue_add(impl->timer_queue, &impl->start_sap_retry_timer,
NULL, 1 * SPA_NSEC_PER_SEC,
on_start_sap_retry_timer_event, impl);
- pw_log_info("starting SAP retry timer");
/* It is important to return 0 in this case. Otherwise, the nonzero return
* value will later be propagated through the core as an error. */
@@ -2009,10 +2005,8 @@ static void impl_destroy(struct impl *impl)
pw_timer_queue_cancel(&impl->sap_send_timer);
pw_timer_queue_cancel(&impl->start_sap_retry_timer);
pw_timer_queue_cancel(&impl->igmp_recovery.timer);
- if (impl->sap_source) {
- pw_log_info("destroying SAP source");
+ if (impl->sap_source)
pw_loop_destroy_source(impl->loop, impl->sap_source);
- }
if (impl->sap_fd != -1)
close(impl->sap_fd);
diff --git a/src/modules/module-rtp-session.c b/src/modules/module-rtp-session.c
index 2dca681d6..63470c539 100644
--- a/src/modules/module-rtp-session.c
+++ b/src/modules/module-rtp-session.c
@@ -27,7 +27,12 @@
#include
#include
-#include "zeroconf-utils/zeroconf.h"
+#include
+#include
+#include
+#include
+
+#include "module-zeroconf-discover/avahi-poll.h"
#include
#include
@@ -155,21 +160,31 @@ static const struct spa_dict_item module_info[] = {
};
struct service_info {
- int ifindex;
- int protocol;
+ AvahiIfIndex interface;
+ AvahiProtocol protocol;
const char *name;
const char *type;
const char *domain;
+ const char *host_name;
+ AvahiAddress address;
+ uint16_t port;
};
#define SERVICE_INFO(...) ((struct service_info){ __VA_ARGS__ })
+struct service {
+ struct service_info info;
+
+ struct spa_list link;
+ struct impl *impl;
+
+ struct session *sess;
+};
+
struct session {
struct impl *impl;
struct spa_list link;
- struct service_info info;
-
struct sockaddr_storage ctrl_addr;
socklen_t ctrl_len;
struct sockaddr_storage data_addr;
@@ -214,8 +229,11 @@ struct impl {
struct pw_properties *props;
bool discover_local;
- struct pw_zeroconf *zeroconf;
- struct spa_hook zeroconf_listener;
+ AvahiPoll *avahi_poll;
+ AvahiClient *client;
+ AvahiServiceBrowser *browser;
+ AvahiEntryGroup *group;
+ struct spa_list service_list;
struct pw_properties *stream_props;
@@ -577,9 +595,6 @@ static void free_session(struct session *sess)
if (sess->recv)
rtp_stream_destroy(sess->recv);
free(sess->name);
- free((char *) sess->info.name);
- free((char *) sess->info.type);
- free((char *) sess->info.domain);
free(sess);
}
@@ -597,8 +612,7 @@ static bool cmp_ip(const struct sockaddr_storage *sa, const struct sockaddr_stor
return false;
}
-static struct session *make_session(struct impl *impl, struct service_info *info,
- struct pw_properties *props)
+static struct session *make_session(struct impl *impl, struct pw_properties *props)
{
struct session *sess;
const char *str;
@@ -613,11 +627,6 @@ static struct session *make_session(struct impl *impl, struct service_info *info
sess->impl = impl;
sess->ssrc = pw_rand32();
- sess->info.ifindex = info->ifindex;
- sess->info.protocol = info->protocol;
- sess->info.name = strdup(info->name);
- sess->info.type = strdup(info->type);
- sess->info.domain = strdup(info->domain);
str = pw_properties_get(props, "sess.name");
sess->name = str ? strdup(str) : strdup("RTP Session");
@@ -660,21 +669,6 @@ error:
return NULL;
}
-static struct session *find_session_by_info(struct impl *impl,
- const struct service_info *info)
-{
- struct session *s;
- spa_list_for_each(s, &impl->sessions, link) {
- if (s->info.ifindex == info->ifindex &&
- s->info.protocol == info->protocol &&
- spa_streq(s->info.name, info->name) &&
- spa_streq(s->info.type, info->type) &&
- spa_streq(s->info.domain, info->domain))
- return s;
- }
- return NULL;
-}
-
static struct session *find_session_by_addr_name(struct impl *impl,
const struct sockaddr_storage *sa, const char *name)
{
@@ -1226,8 +1220,8 @@ static void impl_destroy(struct impl *impl)
if (impl->data_source)
pw_loop_destroy_source(impl->data_loop, impl->data_source);
- if (impl->zeroconf)
- pw_zeroconf_destroy(impl->zeroconf);
+ if (impl->client)
+ avahi_client_free(impl->client);
if (impl->data_loop)
pw_context_release_loop(impl->context, impl->data_loop);
@@ -1269,7 +1263,21 @@ static const struct pw_core_events core_events = {
.error = on_core_error,
};
-static const char *get_service_type(struct impl *impl)
+static void free_service(struct service *s)
+{
+ spa_list_remove(&s->link);
+
+ if (s->sess)
+ free_session(s->sess);
+
+ free((char *) s->info.name);
+ free((char *) s->info.type);
+ free((char *) s->info.domain);
+ free((char *) s->info.host_name);
+ free(s);
+}
+
+static const char *get_service_name(struct impl *impl)
{
const char *str;
str = pw_properties_get(impl->props, "sess.media");
@@ -1280,36 +1288,21 @@ static const char *get_service_type(struct impl *impl)
return NULL;
}
-static void on_zeroconf_added(void *data, const void *user, const struct spa_dict *info)
+static struct service *make_service(struct impl *impl, const struct service_info *info,
+ AvahiStringList *txt)
{
- struct impl *impl = data;
- const char *str, *service_type, *address, *hostname;
- struct service_info sinfo;
+ struct service *s = NULL;
+ char at[AVAHI_ADDRESS_STR_MAX], if_suffix[16] = "";
struct session *sess;
- int ifindex = -1, protocol = 0, res, port = 0;
+ int res, ipv;
struct pw_properties *props = NULL;
+ const char *service_name, *str;
+ AvahiStringList *l;
bool compatible = true;
- if ((str = spa_dict_lookup(info, PW_KEY_ZEROCONF_IFINDEX)))
- ifindex = atoi(str);
- if ((str = spa_dict_lookup(info, PW_KEY_ZEROCONF_PROTO)))
- protocol = atoi(str);
- if ((str = spa_dict_lookup(info, PW_KEY_ZEROCONF_PORT)))
- port = atoi(str);
-
- sinfo = SERVICE_INFO(.ifindex = ifindex,
- .protocol = protocol,
- .name = spa_dict_lookup(info, PW_KEY_ZEROCONF_NAME),
- .type = spa_dict_lookup(info, PW_KEY_ZEROCONF_TYPE),
- .domain = spa_dict_lookup(info, PW_KEY_ZEROCONF_DOMAIN));
-
- sess = find_session_by_info(impl, &sinfo);
- if (sess != NULL)
- return;
-
/* check for compatible session */
- service_type = get_service_type(impl);
- compatible = spa_streq(service_type, sinfo.type);
+ service_name = get_service_name(impl);
+ compatible = spa_streq(service_name, info->type);
props = pw_properties_copy(impl->stream_props);
if (props == NULL) {
@@ -1317,53 +1310,55 @@ static void on_zeroconf_added(void *data, const void *user, const struct spa_dic
goto error;
}
- if (spa_streq(service_type, "_pipewire-audio._udp")) {
+ if (spa_streq(service_name, "_pipewire-audio._udp")) {
uint32_t mask = 0;
- const struct spa_dict_item *it;
- spa_dict_for_each(it, info) {
+ for (l = txt; l && compatible; l = l->next) {
const char *k = NULL;
+ char *key, *value;
- if (!compatible)
+ if (avahi_string_list_get_pair(l, &key, &value, NULL) != 0)
break;
- if (spa_streq(it->key, "subtype")) {
+ if (spa_streq(key, "subtype")) {
k = "sess.media";
mask |= 1<<0;
- } else if (spa_streq(it->key, "format")) {
+ } else if (spa_streq(key, "format")) {
k = PW_KEY_AUDIO_FORMAT;
mask |= 1<<1;
- } else if (spa_streq(it->key, "rate")) {
+ } else if (spa_streq(key, "rate")) {
k = PW_KEY_AUDIO_RATE;
mask |= 1<<2;
- } else if (spa_streq(it->key, "channels")) {
+ } else if (spa_streq(key, "channels")) {
k = PW_KEY_AUDIO_CHANNELS;
mask |= 1<<3;
- } else if (spa_streq(it->key, "position")) {
+ } else if (spa_streq(key, "position")) {
pw_properties_set(props,
- SPA_KEY_AUDIO_POSITION, it->value);
- } else if (spa_streq(it->key, "layout")) {
+ SPA_KEY_AUDIO_POSITION, value);
+ } else if (spa_streq(key, "layout")) {
pw_properties_set(props,
- SPA_KEY_AUDIO_LAYOUT, it->value);
- } else if (spa_streq(it->key, "channelnames")) {
+ SPA_KEY_AUDIO_LAYOUT, value);
+ } else if (spa_streq(key, "channelnames")) {
pw_properties_set(props,
- PW_KEY_NODE_CHANNELNAMES, it->value);
- } else if (spa_streq(it->key, "ts-refclk")) {
+ PW_KEY_NODE_CHANNELNAMES, value);
+ } else if (spa_streq(key, "ts-refclk")) {
pw_properties_set(props,
- "sess.ts-refclk", it->value);
- if (spa_streq(it->value, impl->ts_refclk))
+ "sess.ts-refclk", value);
+ if (spa_streq(value, impl->ts_refclk))
pw_properties_set(props,
"sess.ts-direct", "true");
- } else if (spa_streq(it->key, "ts-offset")) {
+ } else if (spa_streq(key, "ts-offset")) {
uint32_t v;
- if (spa_atou32(it->value, &v, 0))
+ if (spa_atou32(value, &v, 0))
pw_properties_setf(props,
"rtp.receiver-ts-offset", "%u", v);
}
if (k != NULL) {
str = pw_properties_get(props, k);
- if (str == NULL || !spa_streq(str, it->value))
+ if (str == NULL || !spa_streq(str, value))
compatible = false;
}
+ avahi_free(key);
+ avahi_free(value);
}
str = pw_properties_get(props, "sess.media");
if (spa_streq(str, "opus") && mask != 0xd)
@@ -1373,147 +1368,281 @@ static void on_zeroconf_added(void *data, const void *user, const struct spa_dic
}
if (!compatible) {
pw_log_info("found incompatible session IP%d:%s",
- sinfo.protocol, sinfo.name);
+ info->protocol == AVAHI_PROTO_INET ? 4 : 6,
+ info->name);
res = 0;
goto error;
}
- address = spa_dict_lookup(info, PW_KEY_ZEROCONF_ADDRESS);
- hostname = spa_dict_lookup(info, PW_KEY_ZEROCONF_HOSTNAME);
+ s = calloc(1, sizeof(*s));
+ if (s == NULL) {
+ res = -errno;
+ goto error;
+ }
- pw_log_info("create session: %s %s:%u %s", sinfo.name, address, port, sinfo.type);
+ s->impl = impl;
+ spa_list_append(&impl->service_list, &s->link);
- pw_properties_set(props, "sess.name", sinfo.name);
- pw_properties_set(props, "destination.ip", address);
- pw_properties_setf(props, "destination.ifindex", "%u", sinfo.ifindex);
- pw_properties_setf(props, "destination.port", "%u", port);
+ s->info.interface = info->interface;
+ s->info.protocol = info->protocol;
+ s->info.name = strdup(info->name);
+ s->info.type = strdup(info->type);
+ s->info.domain = strdup(info->domain);
+ s->info.host_name = strdup(info->host_name);
+ s->info.address = info->address;
+ s->info.port = info->port;
+
+ avahi_address_snprint(at, sizeof(at), &s->info.address);
+ pw_log_info("create session: %s %s:%u %s", s->info.name, at, s->info.port, s->info.type);
+
+ if (s->info.protocol == AVAHI_PROTO_INET6 &&
+ s->info.address.data.ipv6.address[0] == 0xfe &&
+ (s->info.address.data.ipv6.address[1] & 0xc0) == 0x80)
+ snprintf(if_suffix, sizeof(if_suffix), "%%%d", s->info.interface);
+
+ ipv = s->info.protocol == AVAHI_PROTO_INET ? 4 : 6;
+ pw_properties_set(props, "sess.name", s->info.name);
+ pw_properties_setf(props, "destination.ip", "%s%s", at, if_suffix);
+ pw_properties_setf(props, "destination.ifindex", "%u", s->info.interface);
+ pw_properties_setf(props, "destination.port", "%u", s->info.port);
if (pw_properties_get(props, PW_KEY_NODE_NAME) == NULL)
pw_properties_setf(props, PW_KEY_NODE_NAME, "rtp_session.%s.%s.ipv%d",
- sinfo.name, hostname, sinfo.protocol);
+ s->info.name, s->info.host_name, ipv);
if (pw_properties_get(props, PW_KEY_NODE_DESCRIPTION) == NULL)
pw_properties_setf(props, PW_KEY_NODE_DESCRIPTION, "%s (IPv%d)",
- sinfo.name, sinfo.protocol);
+ s->info.name, ipv);
if (pw_properties_get(props, PW_KEY_MEDIA_NAME) == NULL)
pw_properties_setf(props, PW_KEY_MEDIA_NAME, "RTP Session with %s (IPv%d)",
- sinfo.name, sinfo.protocol);
+ s->info.name, ipv);
- sess = make_session(impl, &sinfo, spa_steal_ptr(props));
+ sess = make_session(impl, props);
+ props = NULL;
if (sess == NULL) {
res = -errno;
pw_log_error("can't create session: %m");
goto error;
}
+ s->sess = sess;
- if ((res = pw_net_parse_address(address, port, &sess->ctrl_addr, &sess->ctrl_len)) < 0) {
- pw_log_error("invalid address %s: %s", address, spa_strerror(res));
+ if ((res = pw_net_parse_address(at, s->info.port, &sess->ctrl_addr, &sess->ctrl_len)) < 0) {
+ pw_log_error("invalid address %s: %s", at, spa_strerror(res));
}
- if ((res = pw_net_parse_address(address, port+1, &sess->data_addr, &sess->data_len)) < 0) {
- pw_log_error("invalid address %s: %s", address, spa_strerror(res));
+ if ((res = pw_net_parse_address(at, s->info.port+1, &sess->data_addr, &sess->data_len)) < 0) {
+ pw_log_error("invalid address %s: %s", at, spa_strerror(res));
}
- return;
+ return s;
error:
pw_properties_free(props);
- return;
+ if (s != NULL)
+ free_service(s);
+ errno = -res;
+ return NULL;
}
-static void on_zeroconf_removed(void *data, const void *user, const struct spa_dict *info)
+static struct service *find_service(struct impl *impl, const struct service_info *info)
{
- struct impl *impl = data;
+ struct service *s;
+ spa_list_for_each(s, &impl->service_list, link) {
+ if (s->info.interface == info->interface &&
+ s->info.protocol == info->protocol &&
+ spa_streq(s->info.name, info->name) &&
+ spa_streq(s->info.type, info->type) &&
+ spa_streq(s->info.domain, info->domain))
+ return s;
+ }
+ return NULL;
+}
+
+static void resolver_cb(AvahiServiceResolver *r, AvahiIfIndex interface, AvahiProtocol protocol,
+ AvahiResolverEvent event, const char *name, const char *type, const char *domain,
+ const char *host_name, const AvahiAddress *a, uint16_t port, AvahiStringList *txt,
+ AvahiLookupResultFlags flags, void *userdata)
+{
+ struct impl *impl = userdata;
struct service_info sinfo;
- struct session *sess;
- const char *str;
- int ifindex = -1, protocol = 0;
- if ((str = spa_dict_lookup(info, PW_KEY_ZEROCONF_IFINDEX)))
- ifindex = atoi(str);
- if ((str = spa_dict_lookup(info, PW_KEY_ZEROCONF_PROTO)))
- protocol = atoi(str);
+ if (event != AVAHI_RESOLVER_FOUND) {
+ pw_log_error("Resolving of '%s' failed: %s", name,
+ avahi_strerror(avahi_client_errno(impl->client)));
+ goto done;
+ }
- sinfo = SERVICE_INFO(.ifindex = ifindex,
+ sinfo = SERVICE_INFO(.interface = interface,
.protocol = protocol,
- .name = spa_dict_lookup(info, PW_KEY_ZEROCONF_NAME),
- .type = spa_dict_lookup(info, PW_KEY_ZEROCONF_TYPE),
- .domain = spa_dict_lookup(info, PW_KEY_ZEROCONF_DOMAIN));
+ .name = name,
+ .type = type,
+ .domain = domain,
+ .host_name = host_name,
+ .address = *a,
+ .port = port);
- sess = find_session_by_info(impl, &sinfo);
- if (sess == NULL)
+ make_service(impl, &sinfo, txt);
+done:
+ avahi_service_resolver_free(r);
+}
+
+static void browser_cb(AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol,
+ AvahiBrowserEvent event, const char *name, const char *type, const char *domain,
+ AvahiLookupResultFlags flags, void *userdata)
+{
+ struct impl *impl = userdata;
+ struct service_info info;
+ struct service *s;
+
+ if ((flags & AVAHI_LOOKUP_RESULT_LOCAL) && !impl->discover_local)
return;
- free_session(sess);
+ info = SERVICE_INFO(.interface = interface,
+ .protocol = protocol,
+ .name = name,
+ .type = type,
+ .domain = domain);
+
+ s = find_service(impl, &info);
+
+ switch (event) {
+ case AVAHI_BROWSER_NEW:
+ if (s != NULL)
+ return;
+ if (!(avahi_service_resolver_new(impl->client,
+ interface, protocol,
+ name, type, domain,
+ AVAHI_PROTO_UNSPEC, 0,
+ resolver_cb, impl)))
+ pw_log_error("can't make service resolver: %s",
+ avahi_strerror(avahi_client_errno(impl->client)));
+ break;
+ case AVAHI_BROWSER_REMOVE:
+ if (s == NULL)
+ return;
+ free_service(s);
+ break;
+ default:
+ break;
+ }
}
static int make_browser(struct impl *impl)
{
- const char *service_type;
- int res;
+ const char *service_name;
- service_type = get_service_type(impl);
- if (service_type == NULL)
+ service_name = get_service_name(impl);
+ if (service_name == NULL)
return -EINVAL;
- if ((res = pw_zeroconf_set_browse(impl->zeroconf, impl,
- &SPA_DICT_ITEMS(
- SPA_DICT_ITEM(PW_KEY_ZEROCONF_TYPE, service_type)))) < 0) {
- pw_log_error("can't make browser for %s: %s",
- service_type, spa_strerror(res));
- return res;
+ if (impl->browser == NULL) {
+ impl->browser = avahi_service_browser_new(impl->client,
+ AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
+ service_name, NULL, 0,
+ browser_cb, impl);
+ }
+ if (impl->browser == NULL) {
+ pw_log_error("can't make browser: %s",
+ avahi_strerror(avahi_client_errno(impl->client)));
+ return -EIO;
}
return 0;
}
+static void entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata)
+{
+ switch (state) {
+ case AVAHI_ENTRY_GROUP_ESTABLISHED:
+ pw_log_info("Service successfully established");
+ break;
+ case AVAHI_ENTRY_GROUP_COLLISION:
+ pw_log_error("Service name collision");
+ break;
+ case AVAHI_ENTRY_GROUP_FAILURE:
+ pw_log_error("Entry group failure: %s",
+ avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g))));
+ break;
+ case AVAHI_ENTRY_GROUP_UNCOMMITED:
+ case AVAHI_ENTRY_GROUP_REGISTERING:;
+ break;
+ }
+}
+
static int make_announce(struct impl *impl)
{
int res;
- const char *service_type, *str;
- struct pw_properties *props;
+ const char *service_name, *str;
+ AvahiStringList *txt = NULL;
- props = pw_properties_new(NULL, NULL);
-
- if ((service_type = get_service_type(impl)) == NULL)
+ if ((service_name = get_service_name(impl)) == NULL)
return -ENOTSUP;
- if (spa_streq(service_type, "_pipewire-audio._udp")) {
+ if (impl->group == NULL) {
+ impl->group = avahi_entry_group_new(impl->client,
+ entry_group_callback, impl);
+ }
+ if (impl->group == NULL) {
+ pw_log_error("can't make group: %s",
+ avahi_strerror(avahi_client_errno(impl->client)));
+ return -EIO;
+ }
+ avahi_entry_group_reset(impl->group);
+
+ if (spa_streq(service_name, "_pipewire-audio._udp")) {
str = pw_properties_get(impl->props, "sess.media");
- pw_properties_set(props, "subtype", str);
+ txt = avahi_string_list_add_pair(txt, "subtype", str);
if ((str = pw_properties_get(impl->stream_props, PW_KEY_AUDIO_FORMAT)) != NULL)
- pw_properties_set(props, "format", str);
+ txt = avahi_string_list_add_pair(txt, "format", str);
if ((str = pw_properties_get(impl->stream_props, PW_KEY_AUDIO_RATE)) != NULL)
- pw_properties_set(props, "rate", str);
+ txt = avahi_string_list_add_pair(txt, "rate", str);
if ((str = pw_properties_get(impl->stream_props, PW_KEY_AUDIO_CHANNELS)) != NULL)
- pw_properties_set(props, "channels", str);
+ txt = avahi_string_list_add_pair(txt, "channels", str);
if ((str = pw_properties_get(impl->stream_props, SPA_KEY_AUDIO_POSITION)) != NULL)
- pw_properties_set(props, "position", str);
+ txt = avahi_string_list_add_pair(txt, "position", str);
if ((str = pw_properties_get(impl->stream_props, SPA_KEY_AUDIO_LAYOUT)) != NULL)
- pw_properties_set(props, "layout", str);
+ txt = avahi_string_list_add_pair(txt, "layout", str);
if ((str = pw_properties_get(impl->stream_props, PW_KEY_NODE_CHANNELNAMES)) != NULL)
- pw_properties_set(props, "channelnames", str);
+ txt = avahi_string_list_add_pair(txt, "channelnames", str);
if (impl->ts_refclk != NULL) {
- pw_properties_set(props, "ts-refclk", impl->ts_refclk);
- pw_properties_setf(props, "ts-offset", "%u", impl->ts_offset);
+ txt = avahi_string_list_add_pair(txt, "ts-refclk", impl->ts_refclk);
+ txt = avahi_string_list_add_printf(txt, "ts-offset=%u", impl->ts_offset);
}
}
+ res = avahi_entry_group_add_service_strlst(impl->group,
+ AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
+ (AvahiPublishFlags)0, impl->session_name,
+ service_name, NULL, NULL,
+ impl->ctrl_port, txt);
- pw_properties_set(props, PW_KEY_ZEROCONF_NAME, impl->session_name);
- pw_properties_set(props, PW_KEY_ZEROCONF_TYPE, service_type);
- pw_properties_setf(props, PW_KEY_ZEROCONF_PORT, "%u", impl->ctrl_port);
-
- res = pw_zeroconf_set_announce(impl->zeroconf, impl, &props->dict);
-
- pw_properties_free(props);
+ avahi_string_list_free(txt);
if (res < 0) {
- pw_log_error("can't add service: %s", spa_strerror(res));
- return res;
+ pw_log_error("can't add service: %s",
+ avahi_strerror(avahi_client_errno(impl->client)));
+ return -EIO;
+ }
+ if ((res = avahi_entry_group_commit(impl->group)) < 0) {
+ pw_log_error("can't commit group: %s",
+ avahi_strerror(avahi_client_errno(impl->client)));
+ return -EIO;
}
return 0;
}
+static void client_callback(AvahiClient *c, AvahiClientState state, void *userdata)
+{
+ struct impl *impl = userdata;
+ impl->client = c;
-static const struct pw_zeroconf_events zeroconf_events = {
- PW_VERSION_ZEROCONF_EVENTS,
- .added = on_zeroconf_added,
- .removed = on_zeroconf_removed,
-};
+ switch (state) {
+ case AVAHI_CLIENT_S_REGISTERING:
+ case AVAHI_CLIENT_S_RUNNING:
+ case AVAHI_CLIENT_S_COLLISION:
+ make_browser(impl);
+ make_announce(impl);
+ break;
+ case AVAHI_CLIENT_FAILURE:
+ case AVAHI_CLIENT_CONNECTING:
+ break;
+ default:
+ break;
+ }
+}
static void copy_props(struct impl *impl, struct pw_properties *props, const char *key)
{
@@ -1544,6 +1673,7 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
args = "";
spa_list_init(&impl->sessions);
+ spa_list_init(&impl->service_list);
props = pw_properties_new_string(args);
if (props == NULL) {
@@ -1555,8 +1685,6 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
impl->discover_local = pw_properties_get_bool(impl->props,
"sess.discover-local", false);
- pw_properties_set(impl->props, PW_KEY_ZEROCONF_DISCOVER_LOCAL,
- impl->discover_local ? "true" : "false");
stream_props = pw_properties_new(NULL, NULL);
if (stream_props == NULL) {
@@ -1676,17 +1804,14 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
if ((res = setup_apple_session(impl)) < 0)
goto out;
- impl->zeroconf = pw_zeroconf_new(impl->context, &impl->props->dict);
- if (impl->zeroconf == NULL) {
- res = -errno;
- pw_log_error("can't create zeroconf: %m");
+ impl->avahi_poll = pw_avahi_poll_new(impl->context);
+ if ((impl->client = avahi_client_new(impl->avahi_poll,
+ AVAHI_CLIENT_NO_FAIL,
+ client_callback, impl,
+ &res)) == NULL) {
+ pw_log_error("can't create avahi client: %s", avahi_strerror(res));
goto out;
}
- pw_zeroconf_add_listener(impl->zeroconf, &impl->zeroconf_listener,
- &zeroconf_events, impl);
-
- make_browser(impl);
- make_announce(impl);
pw_impl_module_add_listener(module, &impl->module_listener, &module_events, impl);
diff --git a/src/modules/module-rtp-source.c b/src/modules/module-rtp-source.c
index b0b52ed50..8f911c62a 100644
--- a/src/modules/module-rtp-source.c
+++ b/src/modules/module-rtp-source.c
@@ -231,7 +231,7 @@ struct impl {
/* Monotonic timestamp of the last time a packet was
* received. This is accessed with atomic accessors
* to avoid race conditions. */
- SPA_ALIGNED(8) uint64_t last_packet_time;
+ uint64_t last_packet_time;
struct pw_timer standby_timer;
/* This timer is used when the first stream_start() call fails because
@@ -246,9 +246,6 @@ struct impl {
socklen_t src_len;
struct spa_source *source;
- bool is_multicast;
- bool filter_by_address;
-
uint8_t *buffer;
size_t buffer_size;
@@ -303,41 +300,14 @@ on_rtp_io(void *data, int fd, uint32_t mask)
ssize_t len;
int suppressed;
uint64_t current_time;
- struct sockaddr_storage recvaddr;
- socklen_t recvaddr_len = sizeof(recvaddr);
current_time = get_time_ns(impl);
if (mask & SPA_IO_IN) {
- if ((len = recvfrom(fd, impl->buffer, impl->buffer_size, 0, (struct sockaddr *)(&recvaddr), &recvaddr_len)) < 0)
+
+ if ((len = recv(fd, impl->buffer, impl->buffer_size, 0)) < 0)
goto receive_error;
- /* Filter the packets to exclude those with source addresses
- * that do not match the expected one. Only used with unicast.
- * (The bind() call in make_socket takes care of only
- * receiving packets that target the specified port.) */
- if (impl->filter_by_address && !pw_net_are_addresses_equal(&recvaddr, &(impl->src_addr), false)) {
- /* In the IPv6 case, pw_net_get_ip() produces output formatted
- * as "%". Both constants
- * INET6_ADDRSTRLEN and IFNAMSIZ include the null terminator
- * in their respective length values. This works out well for
- * the formatted output, since this ensures there is one extra
- * character for the % delimiter and another extra character
- * for the null terminator of the entire string.
- *
- * (In the IPv4 case, pw_net_get_ip() just outputs the address.) */
- char address_str[INET6_ADDRSTRLEN + IFNAMSIZ];
- int res;
-
- res = pw_net_get_ip(&recvaddr, address_str, sizeof(address_str), NULL, NULL);
- if (SPA_LIKELY(res == 0))
- pw_log_trace("Filtering out packet with mismatching address %s", address_str);
- else
- pw_log_warn("Filtering out packet with unrecognized address");
-
- return;
- }
-
if (len < 12)
goto short_packet;
@@ -504,12 +474,12 @@ finish:
}
static int make_socket(const struct sockaddr* sa, socklen_t salen, char *ifname,
- struct igmp_recovery *igmp_recovery, bool *is_multicast,
- bool *filter_by_address)
+ struct igmp_recovery *igmp_recovery)
{
int af, fd, val, res;
struct ifreq req;
struct sockaddr_storage ba = *(struct sockaddr_storage *)sa;
+ bool do_connect = false;
char addr[128];
af = sa->sa_family;
@@ -552,16 +522,12 @@ static int make_socket(const struct sockaddr* sa, socklen_t salen, char *ifname,
pw_net_get_ip((struct sockaddr_storage*)sa, addr, sizeof(addr), NULL, NULL);
pw_log_info("join IPv4 group: %s", addr);
res = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mr4, sizeof(mr4));
- *filter_by_address = false;
- *is_multicast = true;
} else {
struct sockaddr_in *ba4 = (struct sockaddr_in*)&ba;
- *filter_by_address = (ba4->sin_addr.s_addr != INADDR_ANY);
- *is_multicast = false;
- /* Make sure the ANY address is always used. This is important
- * for the bind() call below - with unicast, it shall only filter
- * by port number (address filtering is done by recvfrom()). */
- ba4->sin_addr.s_addr = INADDR_ANY;
+ if (ba4->sin_addr.s_addr != INADDR_ANY) {
+ ba4->sin_addr.s_addr = INADDR_ANY;
+ do_connect = true;
+ }
}
} else if (af == AF_INET6) {
struct sockaddr_in6 *sa6 = (struct sockaddr_in6*)sa;
@@ -573,15 +539,8 @@ static int make_socket(const struct sockaddr* sa, socklen_t salen, char *ifname,
pw_net_get_ip((struct sockaddr_storage*)sa, addr, sizeof(addr), NULL, NULL);
pw_log_info("join IPv6 group: %s", addr);
res = setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mr6, sizeof(mr6));
- *filter_by_address = false;
- *is_multicast = true;
} else {
struct sockaddr_in6 *ba6 = (struct sockaddr_in6*)&ba;
- *filter_by_address = !IN6_IS_ADDR_UNSPECIFIED(&(ba6->sin6_addr.s6_addr));
- *is_multicast = false;
- /* Make sure the ANY address is always used. This is important
- * for the bind() call below - with unicast, it shall only filter
- * by port number (address filtering is done by recvfrom()). */
ba6->sin6_addr = in6addr_any;
}
} else {
@@ -610,6 +569,13 @@ static int make_socket(const struct sockaddr* sa, socklen_t salen, char *ifname,
pw_log_error("bind() failed: %m");
goto error;
}
+ if (do_connect) {
+ if (connect(fd, sa, salen) < 0) {
+ res = -errno;
+ pw_log_error("connect() failed: %m");
+ goto error;
+ }
+ }
return fd;
error:
close(fd);
@@ -647,9 +613,7 @@ static void stream_open_connection(void *data, int *result)
if ((fd = make_socket((const struct sockaddr *)&impl->src_addr,
impl->src_len, impl->ifname,
- &(impl->igmp_recovery),
- &(impl->is_multicast),
- &(impl->filter_by_address))) < 0) {
+ &(impl->igmp_recovery))) < 0) {
/* If make_socket() tries to create a socket and join to a multicast
* group while the network interfaces are not ready yet to do so
* (usually because a network manager component is still setting up
@@ -699,13 +663,11 @@ static void stream_open_connection(void *data, int *result)
goto finish;
}
- if (impl->is_multicast) {
- if ((res = pw_timer_queue_add(impl->timer_queue, &impl->igmp_recovery.timer,
- NULL, impl->igmp_recovery.check_interval * SPA_NSEC_PER_SEC,
- on_igmp_recovery_timer_event, impl)) < 0) {
- pw_log_error("can't add timer: %s", spa_strerror(res));
- goto finish;
- }
+ if ((res = pw_timer_queue_add(impl->timer_queue, &impl->igmp_recovery.timer,
+ NULL, impl->igmp_recovery.check_interval * SPA_NSEC_PER_SEC,
+ on_igmp_recovery_timer_event, impl)) < 0) {
+ pw_log_error("can't add timer: %s", spa_strerror(res));
+ goto finish;
}
finish:
diff --git a/src/modules/module-rtp/audio.c b/src/modules/module-rtp/audio.c
index 085f3bae8..d20e9a37c 100644
--- a/src/modules/module-rtp/audio.c
+++ b/src/modules/module-rtp/audio.c
@@ -546,7 +546,7 @@ static void rtp_audio_flush_packets(struct impl *impl, uint32_t num_packets, uin
else
header.m = 0;
- rtp_timestamp = impl->ts_offset + impl->ts_align + (set_timestamp ? set_timestamp : timestamp);
+ rtp_timestamp = impl->ts_offset + (set_timestamp ? set_timestamp : timestamp);
header.sequence_number = htons(impl->seq);
header.timestamp = htonl(rtp_timestamp);
@@ -556,12 +556,12 @@ static void rtp_audio_flush_packets(struct impl *impl, uint32_t num_packets, uin
((uint64_t)timestamp * stride) % impl->actual_max_buffer_size,
&iov[1], tosend * stride);
- pw_log_trace_fp("sending %d packet:%d ts_offset:%d timestamp:%u (%f s)",
+ pw_log_trace("sending %d packet:%d ts_offset:%d timestamp:%u (%f s)",
tosend, num_packets, impl->ts_offset, timestamp,
(double)timestamp * impl->io_position->clock.rate.num /
impl->io_position->clock.rate.denom);
- rtp_stream_call_send_packet(impl, iov, 3);
+ rtp_stream_emit_send_packet(impl, iov, 3);
impl->seq++;
impl->first = false;
@@ -606,7 +606,7 @@ static void rtp_audio_stop_timer(struct impl *impl)
static void rtp_audio_flush_timeout(struct impl *impl, uint64_t expirations)
{
if (expirations > 1)
- pw_log_trace("missing timeout %"PRIu64, expirations);
+ pw_log_warn("missing timeout %"PRIu64, expirations);
rtp_audio_flush_packets(impl, expirations, 0);
}
@@ -705,10 +705,8 @@ static void rtp_audio_process_capture(void *data)
* that resynchronization is needed, then this will be done immediately below. */
if (!impl->have_sync) {
- if (!impl->direct_timestamp)
- impl->ts_align = actual_timestamp - impl->ring.readindex;
- pw_log_info("(re)sync to timestamp:%u seq:%u ts_offset:%u ts_align:%u SSRC:%u",
- actual_timestamp, impl->seq, impl->ts_offset, impl->ts_align, impl->ssrc);
+ pw_log_info("(re)sync to timestamp:%u seq:%u ts_offset:%u SSRC:%u",
+ actual_timestamp, impl->seq, impl->ts_offset, impl->ssrc);
spa_ringbuffer_read_update(&impl->ring, actual_timestamp);
spa_ringbuffer_write_update(&impl->ring, actual_timestamp);
memset(impl->buffer, 0, BUFFER_SIZE);
diff --git a/src/modules/module-rtp/midi.c b/src/modules/module-rtp/midi.c
index 1237f66c6..5fbdf3b63 100644
--- a/src/modules/module-rtp/midi.c
+++ b/src/modules/module-rtp/midi.c
@@ -151,7 +151,7 @@ static int parse_journal(struct impl *impl, uint8_t *packet, uint16_t seq, uint3
return -EINVAL;
j = (struct rtp_midi_journal*)packet;
uint16_t seqnum = ntohs(j->checkpoint_seqnum);
- rtp_stream_call_send_feedback(impl, seqnum);
+ rtp_stream_emit_send_feedback(impl, seqnum);
return 0;
}
@@ -271,6 +271,9 @@ static int rtp_midi_receive_midi(struct impl *impl, uint8_t *packet, uint32_t ti
while (offs < end) {
uint32_t delta;
int size;
+ uint64_t state = 0;
+ uint8_t *d;
+ size_t s;
if (first && !hdr.z)
delta = 0;
@@ -291,9 +294,17 @@ static int rtp_midi_receive_midi(struct impl *impl, uint8_t *packet, uint32_t ti
return -EINVAL;
}
- spa_pod_builder_control(&b, timestamp, SPA_CONTROL_Midi);
- spa_pod_builder_bytes(&b, &packet[offs], size);
+ d = &packet[offs];
+ s = size;
+ while (s > 0) {
+ uint32_t ump[4];
+ int ump_size = spa_ump_from_midi(&d, &s, ump, sizeof(ump), 0, &state);
+ if (ump_size <= 0)
+ break;
+ spa_pod_builder_control(&b, timestamp, SPA_CONTROL_UMP);
+ spa_pod_builder_bytes(&b, ump, ump_size);
+ }
offs += size;
first = false;
}
@@ -367,7 +378,7 @@ unexpected_ssrc:
return -EINVAL;
}
-static int write_event(uint8_t *p, uint32_t buffer_size, uint32_t value, const void *ev, uint32_t size)
+static int write_event(uint8_t *p, uint32_t buffer_size, uint32_t value, void *ev, uint32_t size)
{
uint64_t buffer;
uint8_t b;
@@ -426,54 +437,62 @@ static void rtp_midi_flush_packets(struct impl *impl,
while (spa_pod_parser_get_control_body(parser, &c, &c_body) >= 0) {
uint32_t delta, offset;
- uint32_t size = c.value.size;
- const uint8_t *data = c_body;
+ uint8_t event[16];
+ int size;
+ size_t c_size = c.value.size;
+ uint64_t state = 0;
- if (c.type != SPA_CONTROL_Midi)
+ if (c.type != SPA_CONTROL_UMP)
continue;
- offset = c.offset * impl->rate / rate;
+ while (c_size > 0) {
+ size = spa_ump_to_midi((const uint32_t **)&c_body, &c_size, event, sizeof(event), &state);
+ if (size <= 0)
+ break;
- if (len > 0 && (len + size > max_size ||
- offset - base > impl->psamples)) {
- /* flush packet when we have one and when it's either
- * too large or has too much data. */
- if (len < 16) {
- midi_header.b = 0;
- midi_header.len = len;
- iov[1].iov_len = sizeof(midi_header) - 1;
- } else {
- midi_header.b = 1;
- midi_header.len = (len >> 8) & 0xf;
- midi_header.len_b = len & 0xff;
- iov[1].iov_len = sizeof(midi_header);
+ offset = c.offset * impl->rate / rate;
+
+ if (len > 0 && (len + size > max_size ||
+ offset - base > impl->psamples)) {
+ /* flush packet when we have one and when it's either
+ * too large or has too much data. */
+ if (len < 16) {
+ midi_header.b = 0;
+ midi_header.len = len;
+ iov[1].iov_len = sizeof(midi_header) - 1;
+ } else {
+ midi_header.b = 1;
+ midi_header.len = (len >> 8) & 0xf;
+ midi_header.len_b = len & 0xff;
+ iov[1].iov_len = sizeof(midi_header);
+ }
+ iov[2].iov_len = len;
+
+ pw_log_trace("sending %d timestamp:%d %u %u",
+ len, timestamp + base,
+ offset, impl->psamples);
+ rtp_stream_emit_send_packet(impl, iov, 3);
+
+ impl->seq++;
+ len = 0;
}
- iov[2].iov_len = len;
+ if ((unsigned int)size > BUFFER_SIZE || len > BUFFER_SIZE - size) {
+ pw_log_error("Buffer overflow prevented!");
+ return; // FIXME: what to do instead?
+ }
+ if (len == 0) {
+ /* start new packet */
+ base = prev_offset = offset;
+ header.sequence_number = htons(impl->seq);
+ header.timestamp = htonl(impl->ts_offset + timestamp + base);
- pw_log_trace("sending %d timestamp:%d %u %u",
- len, timestamp + base,
- offset, impl->psamples);
- rtp_stream_call_send_packet(impl, iov, 3);
-
- impl->seq++;
- len = 0;
- }
- if ((unsigned int)size > BUFFER_SIZE || len > BUFFER_SIZE - size) {
- pw_log_error("Buffer overflow prevented!");
- return; // FIXME: what to do instead?
- }
- if (len == 0) {
- /* start new packet */
- base = prev_offset = offset;
- header.sequence_number = htons(impl->seq);
- header.timestamp = htonl(impl->ts_offset + timestamp + base);
-
- memcpy(&impl->buffer[len], data, size);
- len += size;
- } else {
- delta = offset - prev_offset;
- prev_offset = offset;
- len += write_event(&impl->buffer[len], BUFFER_SIZE - len, delta, data, size);
+ memcpy(&impl->buffer[len], event, size);
+ len += size;
+ } else {
+ delta = offset - prev_offset;
+ prev_offset = offset;
+ len += write_event(&impl->buffer[len], BUFFER_SIZE - len, delta, event, size);
+ }
}
}
if (len > 0) {
@@ -491,7 +510,7 @@ static void rtp_midi_flush_packets(struct impl *impl,
iov[2].iov_len = len;
pw_log_trace("sending %d timestamp:%d", len, base);
- rtp_stream_call_send_packet(impl, iov, 3);
+ rtp_stream_emit_send_packet(impl, iov, 3);
impl->seq++;
}
}
diff --git a/src/modules/module-rtp/opus.c b/src/modules/module-rtp/opus.c
index 9175d4a31..d13a4efaf 100644
--- a/src/modules/module-rtp/opus.c
+++ b/src/modules/module-rtp/opus.c
@@ -252,7 +252,7 @@ static void rtp_opus_flush_packets(struct impl *impl)
pw_log_trace("sending %d len:%d timestamp:%d", tosend, res, timestamp);
iov[1].iov_len = res;
- rtp_stream_call_send_packet(impl, iov, 2);
+ rtp_stream_emit_send_packet(impl, iov, 2);
impl->seq++;
timestamp += tosend;
diff --git a/src/modules/module-rtp/stream.c b/src/modules/module-rtp/stream.c
index 11bba4f98..d69b16524 100644
--- a/src/modules/module-rtp/stream.c
+++ b/src/modules/module-rtp/stream.c
@@ -48,11 +48,8 @@ PW_LOG_TOPIC_EXTERN(mod_topic);
#define rtp_stream_emit_open_connection(s,r) rtp_stream_emit(s, open_connection, 0,r)
#define rtp_stream_emit_close_connection(s,r) rtp_stream_emit(s, close_connection, 0,r)
#define rtp_stream_emit_param_changed(s,i,p) rtp_stream_emit(s, param_changed,0,i,p)
-
-#define rtp_stream_call(s,m,v,...) spa_callbacks_call_fast(&s->rtp_callbacks, \
- struct rtp_stream_events, m, v, ##__VA_ARGS__)
-#define rtp_stream_call_send_packet(s,i,l) rtp_stream_call(s, send_packet,0,i,l)
-#define rtp_stream_call_send_feedback(s,seq) rtp_stream_call(s, send_feedback,0,seq)
+#define rtp_stream_emit_send_packet(s,i,l) rtp_stream_emit(s, send_packet,0,i,l)
+#define rtp_stream_emit_send_feedback(s,seq) rtp_stream_emit(s, send_feedback,0,seq)
enum rtp_stream_internal_state {
/* The state when the stream is idle / stopped. The background
@@ -88,8 +85,6 @@ struct impl {
struct spa_hook stream_listener;
struct pw_stream_events stream_events;
- struct spa_callbacks rtp_callbacks;
-
struct spa_hook_list listener_list;
struct spa_hook listener;
@@ -114,7 +109,6 @@ struct impl {
uint32_t mtu;
uint32_t header_size;
uint32_t payload_size;
- uint32_t ts_align;
struct spa_ringbuffer ring;
uint8_t buffer[BUFFER_SIZE];
@@ -432,7 +426,7 @@ static int stream_stop(struct impl *impl)
* because a stop involves closing the connection. If the timer is still
* running, it needs an open connection for sending out remaining packets. */
if (!timer_running) {
- int res = 0;
+ int res;
pw_log_info("closing connection as part of stopping the stream");
rtp_stream_emit_close_connection(impl, &res);
if (res > 0) {
@@ -1008,7 +1002,6 @@ struct rtp_stream *rtp_stream_new(struct pw_core *core,
(res = stream_start(impl)) < 0)
goto out;
- impl->rtp_callbacks = SPA_CALLBACKS_INIT(events, data);
spa_hook_list_append(&impl->listener_list, &impl->listener, events, data);
return (struct rtp_stream*)impl;
diff --git a/src/modules/module-scheduler-v1.c b/src/modules/module-scheduler-v1.c
deleted file mode 100644
index 5756f7a56..000000000
--- a/src/modules/module-scheduler-v1.c
+++ /dev/null
@@ -1,1040 +0,0 @@
-/* PipeWire */
-/* SPDX-FileCopyrightText: Copyright © 2018 Wim Taymans */
-/* SPDX-License-Identifier: MIT */
-
-#include "config.h"
-
-#include
-#include
-#include
-#include
-#include
-#include