summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.ac8
-rw-r--r--man/pulse-client.conf.5.xml.in19
-rw-r--r--man/pulse-daemon.conf.5.xml.in59
-rw-r--r--po/LINGUAS3
-rw-r--r--po/POTFILES.in1
-rw-r--r--po/fr.po2153
-rw-r--r--po/sv.po1799
-rw-r--r--src/.gitignore3
-rw-r--r--src/Makefile.am76
-rw-r--r--src/daemon/daemon-conf.c42
-rw-r--r--src/daemon/daemon-conf.h2
-rw-r--r--src/daemon/daemon.conf.in4
-rwxr-xr-xsrc/daemon/default.pa.in5
-rw-r--r--src/daemon/main.c14
-rwxr-xr-xsrc/daemon/system.pa.in5
-rw-r--r--src/modules/alsa-util.c15
l---------src/modules/bluetooth/Makefile1
-rw-r--r--src/modules/bluetooth/ipc.c118
-rw-r--r--src/modules/bluetooth/ipc.h308
-rw-r--r--src/modules/bluetooth/module-bluetooth-device.c929
-rw-r--r--src/modules/bluetooth/module-bluetooth-discover.c928
-rw-r--r--src/modules/bluetooth/module-bluetooth-proximity.c (renamed from src/modules/module-bt-proximity.c)2
-rw-r--r--src/modules/bluetooth/proximity-helper.c (renamed from src/modules/bt-proximity-helper.c)0
-rw-r--r--src/modules/bluetooth/rtp.h76
-rw-r--r--src/modules/bluetooth/sbc.c1411
-rw-r--r--src/modules/bluetooth/sbc.h97
-rw-r--r--src/modules/bluetooth/sbc_math.h72
-rw-r--r--src/modules/bluetooth/sbc_tables.h167
l---------[-rw-r--r--]src/modules/gconf/Makefile14
-rw-r--r--src/modules/module-alsa-sink.c16
-rw-r--r--src/modules/module-alsa-source.c17
-rw-r--r--src/modules/module-protocol-stub.c2
-rw-r--r--src/modules/module-stream-restore.c2
l---------[-rw-r--r--]src/modules/rtp/Makefile14
-rw-r--r--src/pulse/client-conf.c3
-rw-r--r--src/pulse/client-conf.h1
-rw-r--r--src/pulse/client.conf.in1
-rw-r--r--src/pulse/context.c4
-rw-r--r--src/pulse/stream.c6
-rw-r--r--src/pulsecore/conf-parser.c18
-rw-r--r--src/pulsecore/conf-parser.h3
-rw-r--r--src/pulsecore/core-util.c47
-rw-r--r--src/pulsecore/core-util.h1
-rw-r--r--src/pulsecore/core.c9
-rw-r--r--src/pulsecore/core.h3
-rw-r--r--src/pulsecore/idxset.c5
-rw-r--r--src/pulsecore/lock-autospawn.c (renamed from src/pulse/lock-autospawn.c)0
-rw-r--r--src/pulsecore/lock-autospawn.h (renamed from src/pulse/lock-autospawn.h)0
-rw-r--r--src/pulsecore/memblock.c18
-rw-r--r--src/pulsecore/memblock.h2
-rw-r--r--src/pulsecore/prioq.c256
-rw-r--r--src/pulsecore/prioq.h64
-rw-r--r--src/pulsecore/proplist-util.c2
-rw-r--r--src/pulsecore/protocol-native.c2
-rw-r--r--src/pulsecore/resampler.c39
-rw-r--r--src/pulsecore/resampler.h7
-rw-r--r--src/pulsecore/sink-input.c3
-rw-r--r--src/pulsecore/source-output.c3
-rw-r--r--src/tests/envelope-test.c2
-rw-r--r--src/tests/lock-autospawn-test.c2
-rw-r--r--src/tests/mcalign-test.c2
-rw-r--r--src/tests/memblock-test.c6
-rw-r--r--src/tests/memblockq-test.c2
-rw-r--r--src/tests/mix-test.c2
-rw-r--r--src/tests/prioq-test.c44
-rw-r--r--src/tests/remix-test.c2
-rw-r--r--src/tests/resampler-test.c2
67 files changed, 8782 insertions, 161 deletions
diff --git a/configure.ac b/configure.ac
index 4a560b12..3c3550fb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -40,11 +40,11 @@ AC_SUBST(PA_PROTOCOL_VERSION, 14)
# The stable ABI for client applications, for the version info x:y:z
# always will hold y=z
-AC_SUBST(LIBPULSE_VERSION_INFO, [5:0:5])
+AC_SUBST(LIBPULSE_VERSION_INFO, [6:0:6])
# A simplified, synchronous, ABI-stable interface for client
# applications, for the version info x:y:z always will hold y=z
-AC_SUBST(LIBPULSE_SIMPLE_VERSION_INFO, [0:1:0])
+AC_SUBST(LIBPULSE_SIMPLE_VERSION_INFO, [0:2:0])
# The ABI-stable network browsing interface for client applications,
# for the version info x:y:z always will hold y=z
@@ -52,12 +52,12 @@ AC_SUBST(LIBPULSE_BROWSE_VERSION_INFO, [1:1:1])
# The ABI-stable GLib adapter for client applications, for the version
# info x:y:z always will hold y=z
-AC_SUBST(LIBPULSE_MAINLOOP_GLIB_VERSION_INFO, [0:3:0])
+AC_SUBST(LIBPULSE_MAINLOOP_GLIB_VERSION_INFO, [0:4:0])
# An internally used, ABI-unstable library that contains the
# PulseAudio core, SONAMEs are bumped on every release, version info
# suffix will always be 0:0
-AC_SUBST(LIBPULSECORE_VERSION_INFO, [6:0:0])
+AC_SUBST(LIBPULSECORE_VERSION_INFO, [7:0:0])
AC_CANONICAL_HOST
AC_DEFINE_UNQUOTED([CANONICAL_HOST], "$host", [Canonical host string.])
diff --git a/man/pulse-client.conf.5.xml.in b/man/pulse-client.conf.5.xml.in
index ae8de1f8..26e38908 100644
--- a/man/pulse-client.conf.5.xml.in
+++ b/man/pulse-client.conf.5.xml.in
@@ -31,15 +31,15 @@ USA.
<description>
<p>The PulseAudio client library reads configuration directives from
- a file <file>~/.pulse/client.conf</file> on startup, and when that
+ a file <file>~/.pulse/client.conf</file> on startup and when that
file doesn't exist from
<file>@pulseconfdir@/client.conf</file>.</p>
<p>The configuration file is a simple collection of variable
declarations. If the configuration file parser encounters either ;
- or # for it ignores the rest of the line until its end.</p>
+ or # it ignores the rest of the line until its end.</p>
- <p>For the settings that take a boolean argument, the values
+ <p>For the settings that take a boolean argument the values
<opt>true</opt>, <opt>yes</opt>, <opt>on</opt> and <opt>1</opt>
are equivalent, resp. <opt>false</opt>, <opt>no</opt>,
<opt>off</opt>, <opt>0</opt>.</p>
@@ -69,7 +69,7 @@ USA.
<option>
<p><opt>autospawn=</opt> Autospawn a PulseAudio daemon when
- needed. Takes a boolean value, defaults to "no".</p>
+ needed. Takes a boolean value, defaults to "yes".</p>
</option>
<option>
@@ -81,7 +81,7 @@ USA.
<option>
<p><opt>extra-arguments=</opt> Extra arguments to pass to the
PulseAudio daemon when autospawning. Defaults to
- <opt>--log-target=syslog --exit-idle-time=5</opt>
+ <opt>--log-target=syslog</opt>
</p>
</option>
@@ -97,6 +97,15 @@ USA.
<opt>no</opt>.</p>
</option>
+ <option>
+ <p><opt>shm-size-bytes=</opt> Sets the shared memory segment
+ size for clients, in bytes. If left unspecified or is set to 0
+ it will default to some system-specific default, usually 64
+ MiB. Please note that usually there is no need to change this
+ value, unless you are running an OS kernel that does not do
+ memory overcommit.</p>
+ </option>
+
</section>
<section name="Authors">
diff --git a/man/pulse-daemon.conf.5.xml.in b/man/pulse-daemon.conf.5.xml.in
index c2eefaa5..a516ee3f 100644
--- a/man/pulse-daemon.conf.5.xml.in
+++ b/man/pulse-daemon.conf.5.xml.in
@@ -31,7 +31,7 @@ USA.
<description>
<p>The PulseAudio sound server reads configuration directives from
- a file <file>~/.pulse/daemon.conf</file> on startup, and when that
+ a file <file>~/.pulse/daemon.conf</file> on startup and when that
file doesn't exist from
<file>@pulseconfdir@/daemon.conf</file>. Please note that the
server also reads a configuration script on startup
@@ -40,9 +40,9 @@ USA.
<p>The configuration file is a simple collection of variable
declarations. If the configuration file parser encounters either ;
- or # for it ignores the rest of the line until its end.</p>
+ or # it ignores the rest of the line until its end.</p>
- <p>For the settings that take a boolean argument, the values
+ <p>For the settings that take a boolean argument the values
<opt>true</opt>, <opt>yes</opt>, <opt>on</opt> and <opt>1</opt>
are equivalent, resp. <opt>false</opt>, <opt>no</opt>,
<opt>off</opt>, <opt>0</opt>.</p>
@@ -77,6 +77,11 @@ USA.
</option>
<option>
+ <p><opt>disallow-exit=</opt> Disallow exit on user
+ request. Defaults to <opt>no</opt>.</p>
+ </option>
+
+ <option>
<p><opt>resample-method=</opt> The resampling algorithm to
use. Use one of <opt>src-sinc-best-quality</opt>,
<opt>src-sinc-medium-quality</opt>, <opt>src-sinc-fastest</opt>,
@@ -106,6 +111,16 @@ USA.
</option>
<option>
+ <p><opt>disable-lfe-remixing=</opt> When upmixing or downmixing
+ ignore LFE channels. When this option is on the output LFE
+ channel will only get a signal when an input LFE channel is
+ available as well. If no input LFE channel is available the
+ output LFE channel will always be 0. If no output LFE channel is
+ available the signal on the input LFE channel will be
+ ignored. Defaults to "on".</p>
+ </option>
+
+ <option>
<p><opt>use-pid-file=</opt> Create a PID file in
<file>/tmp/pulse-$USER/pid</file>. Of this is enabled you may
use commands like <opt>--kill</opt> or <opt>--check</opt>. If
@@ -141,6 +156,15 @@ USA.
argument takes precedence.</p>
</option>
+ <option>
+ <p><opt>shm-size-bytes=</opt> Sets the shared memory segment
+ size for the daemon, in bytes. If left unspecified or is set to 0
+ it will default to some system-specific default, usually 64
+ MiB. Please note that usually there is no need to change this
+ value, unless you are running an OS kernel that does not do
+ memory overcommit.</p>
+ </option>
+
</section>
<section name="Scheduling">
@@ -230,9 +254,17 @@ USA.
default script file. The default behaviour is to load
<file>~/.pulse/default.pa</file>, and if that file does not
exist fall back to the system wide installed version
- <file>@pulseconfdir@/default.pa</file>. If <opt>-n</opt> is
- passed on the command line the default configuration script is
- ignored.</p>
+ <file>@pulseconfdir@/default.pa</file>. If run in system-wide
+ mode the file <file>@pulseconfdir@/system.pa</file> is used
+ instead. If <opt>-n</opt> is passed on the command line
+ or <opt>default-script-file=</opt> is disabled the default
+ configuration script is ignored.</p>
+ </option>
+
+ <option>
+ <p><opt>default-script-file=</opt> Load the default
+ configuration script file as specified
+ in <opt>default-script-file=</opt>. Defaults to "yes".</p>
</option>
</section>
@@ -272,6 +304,9 @@ USA.
<p><opt>rlimit-as</opt> Defaults to -1.</p>
</option>
<option>
+ <p><opt>rlimit-rss</opt> Defaults to -1.</p>
+ </option>
+ <option>
<p><opt>rlimit-core</opt> Defaults to -1.</p>
</option>
<option>
@@ -290,6 +325,15 @@ USA.
<p><opt>rlimit-nproc</opt> Defaults to -1.</p>
</option>
<option>
+ <p><opt>rlimit-locks</opt> Defaults to -1.</p>
+ </option>
+ <option>
+ <p><opt>rlimit-sigpending</opt> Defaults to -1.</p>
+ </option>
+ <option>
+ <p><opt>rlimit-msgqueue</opt> Defaults to -1.</p>
+ </option>
+ <option>
<p><opt>rlimit-memlock</opt> Defaults to 16 KiB. Please note
that the JACK client libraries may require more locked
memory.</p>
@@ -307,6 +351,9 @@ USA.
<opt>realtime-scheduling</opt> is enabled. The JACK client
libraries require a real-time prority of 9 by default. </p>
</option>
+ <option>
+ <p><opt>rlimit-rttime</opt> Defaults to 1000000.</p>
+ </option>
</section>
diff --git a/po/LINGUAS b/po/LINGUAS
index 7673daa9..e3f5e8f5 100644
--- a/po/LINGUAS
+++ b/po/LINGUAS
@@ -1 +1,4 @@
de
+el
+fr
+sv
diff --git a/po/POTFILES.in b/po/POTFILES.in
index fa28b6a7..6efb1d08 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -190,3 +190,4 @@ src/utils/padsp.c
src/utils/pax11publish.c
src/utils/pacmd.c
src/utils/paplay.c
+src/pulsecore/lock-autospawn.c
diff --git a/po/fr.po b/po/fr.po
new file mode 100644
index 00000000..9cd91bf3
--- /dev/null
+++ b/po/fr.po
@@ -0,0 +1,2153 @@
+# French translation of pulseaudio.
+# Copyright (C) 2006-2008 Lennart Poettering
+# This file is distributed under the same license as the pulseaudio package.
+#
+# Robert-André Mauchin <zebob.m@pengzone.org>, 2008.
+# Michaël Ughetto <telimektar esraonline com>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: pulseaudio trunk\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-09-06 06:06+0000\n"
+"PO-Revision-Date: 2008-09-06 10:49+0200\n"
+"Last-Translator: Robert-André Mauchin <zebob.m@pengzone.org>\n"
+"Language-Team: Fedora French <fedora-trans-fr@redhat.com>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n>1;\n"
+
+#: ../src/daemon/ltdl-bind-now.c:177 ../src/daemon/ltdl-bind-now.c:197
+msgid "Failed to add bind-now-loader."
+msgstr "Échec lors de l'ajout du chargeur bind-now."
+
+#: ../src/daemon/ltdl-bind-now.c:184
+msgid "Failed to find original dlopen loader."
+msgstr "Échec lors de la recherche du chargeur dlopen original."
+
+#: ../src/daemon/polkit.c:55
+#, c-format
+msgid "Cannot connect to system bus: %s"
+msgstr "Impossible de se connecter au bus système : %s"
+
+#: ../src/daemon/polkit.c:65
+#, c-format
+msgid "Cannot get caller from PID: %s"
+msgstr "Impossible d'obtenir le programme appelant à partir du PID : %s"
+
+#: ../src/daemon/polkit.c:77
+msgid "Cannot set UID on caller object."
+msgstr "Impossible de définir un UID sur l'objet appelant."
+
+#: ../src/daemon/polkit.c:82
+msgid "Failed to get CK session."
+msgstr "Échec lors de l'obtention de la session CK."
+
+#: ../src/daemon/polkit.c:90
+msgid "Cannot set UID on session object."
+msgstr "Impossible de définir l'UID sur l'objet de session."
+
+#: ../src/daemon/polkit.c:95
+msgid "Cannot allocate PolKitAction."
+msgstr "Impossible d'allouer PolKitAction."
+
+#: ../src/daemon/polkit.c:100
+msgid "Cannot set action_id"
+msgstr "Impossible de définir action_id."
+
+#: ../src/daemon/polkit.c:105
+msgid "Cannot allocate PolKitContext."
+msgstr "Impossible d'allouer PolKitContext."
+
+#: ../src/daemon/polkit.c:110
+#, c-format
+msgid "Cannot initialize PolKitContext: %s"
+msgstr "Impossible d'initialiser PolKitContext : %s"
+
+#: ../src/daemon/polkit.c:119
+#, c-format
+msgid "Could not determine whether caller is authorized: %s"
+msgstr "Impossible de déterminer si le programme appelant est autorisé : %s"
+
+#: ../src/daemon/polkit.c:139
+#, c-format
+msgid "Cannot obtain auth: %s"
+msgstr "Impossible d'obtenir l'authentification : %s"
+
+#: ../src/daemon/polkit.c:148
+#, c-format
+msgid "PolicyKit responded with '%s'"
+msgstr "PolicyKit a renvoyé « %s »"
+
+#: ../src/daemon/main.c:134
+#, c-format
+msgid "Got signal %s."
+msgstr "Signal %s obtenu."
+
+#: ../src/daemon/main.c:161
+msgid "Exiting."
+msgstr "Fermeture."
+
+#: ../src/daemon/main.c:179
+#, c-format
+msgid "Failed to find user '%s'."
+msgstr "Impossible de trouver l'utilisateur « %s »."
+
+#: ../src/daemon/main.c:184
+#, c-format
+msgid "Failed to find group '%s'."
+msgstr "Impossible de trouver le groupe « %s »."
+
+#: ../src/daemon/main.c:188
+#, c-format
+msgid "Found user '%s' (UID %lu) and group '%s' (GID %lu)."
+msgstr "Utilisateur « %s ” (UID %lu) et groupe « %s » (GID %lu) trouvé."
+
+#: ../src/daemon/main.c:193
+#, c-format
+msgid "GID of user '%s' and of group '%s' don't match."
+msgstr ""
+"Le GID de l'utilisateur « %s » et du groupe « %s » ne sont pas identiques."
+
+#: ../src/daemon/main.c:198
+#, c-format
+msgid "Home directory of user '%s' is not '%s', ignoring."
+msgstr "Le dossier personnel de l'utilisateur « %s » n'est pas « %s », ignoré."
+
+#: ../src/daemon/main.c:201 ../src/daemon/main.c:206
+#, c-format
+msgid "Failed to create '%s': %s"
+msgstr "Échec lors de la création de « %s » : %s"
+
+#: ../src/daemon/main.c:213
+#, c-format
+msgid "Failed to change group list: %s"
+msgstr "Échec lors du changement de la liste du groupe : %s"
+
+#: ../src/daemon/main.c:229
+#, c-format
+msgid "Failed to change GID: %s"
+msgstr "Échec lors du changement de GID : %s"
+
+#: ../src/daemon/main.c:245
+#, c-format
+msgid "Failed to change UID: %s"
+msgstr "Échec lors du changement d'UID : %s"
+
+#: ../src/daemon/main.c:259
+msgid "Successfully dropped root privileges."
+msgstr "Les permissions root ont été correctement abandonnées."
+
+#: ../src/daemon/main.c:267
+msgid "System wide mode unsupported on this platform."
+msgstr "Mode système étendu non pris en charge sur cette plateforme."
+
+#: ../src/daemon/main.c:285
+#, c-format
+msgid "setrlimit(%s, (%u, %u)) failed: %s"
+msgstr "setrlimit(%s, (%u, %u)) a échoué : %s"
+
+#: ../src/daemon/main.c:425
+msgid "Failed to parse command line."
+msgstr "Échec lors de l'analyse de la ligne de commande"
+
+#: ../src/daemon/main.c:441
+#, c-format
+msgid "We're in the group '%s', allowing high-priority scheduling."
+msgstr ""
+"Nous sommes dans le groupe « %s », permettant une planification à haute "
+"priorité."
+
+#: ../src/daemon/main.c:448
+#, c-format
+msgid "We're in the group '%s', allowing real-time scheduling."
+msgstr ""
+"Nous sommes dans le groupe « %s », permettant une planification en temps réel."
+
+#: ../src/daemon/main.c:456
+msgid "PolicyKit grants us acquire-high-priority privilege."
+msgstr "PolicyKit a accordé l'acquisition des permissions de haute priorité."
+
+#: ../src/daemon/main.c:459
+msgid "PolicyKit refuses acquire-high-priority privilege."
+msgstr "PolicyKit a refusé l'acquisition des permissions de haute priorité."
+
+#: ../src/daemon/main.c:464
+msgid "PolicyKit grants us acquire-real-time privilege."
+msgstr "PolicyKit a accordé l'acquisition des permissions de temps réel."
+
+#: ../src/daemon/main.c:467
+msgid "PolicyKit refuses acquire-real-time privilege."
+msgstr "PolicyKit a refusé l'acquisition des permissions de temps réel."
+
+#: ../src/daemon/main.c:479
+msgid ""
+"Called SUID root and real-time/high-priority scheduling was requested in the "
+"configuration. However, we lack the necessary priviliges:\n"
+"We are not in group '"
+msgstr ""
+"Le SUID root a été appelé et la planification à haute priorité/en temps réel "
+"demandée dans la configuration. Néanmoins nous n'avons pas les permissions "
+"nécessaires :\n"
+"nous ne somme pas dans le groupe "
+
+#: ../src/daemon/main.c:480
+msgid ""
+"' and PolicyKit refuse to grant us priviliges. Dropping SUID again.\n"
+"For enabling real-time scheduling please acquire the appropriate PolicyKit "
+"priviliges, or become a member of '"
+msgstr ""
+" et PolicyKit refuse de nous accorder les permissions. Abandon du SUID à nouveau.\n"
+"Pour activer la planification en temps réel, veuillez aquérir les permissions "
+"PolicyKit appropriées, ou devenez membre de "
+
+#: ../src/daemon/main.c:481
+msgid ""
+"', or increase the RLIMIT_NICE/RLIMIT_RTPRIO resource limits for this user."
+msgstr ""
+", ou augmentez les limites de ressource RLIMIT_NICE/RLIMIT_RTPRIO pour cet utilisateur."
+
+#: ../src/daemon/main.c:497
+msgid ""
+"High-priority scheduling enabled in configuration but not allowed by policy."
+msgstr ""
+"La planification à haute priorité est activée dans la configuration mais "
+"n'est pas permise par la politique."
+
+#: ../src/daemon/main.c:522
+msgid "Successfully increased RLIMIT_RTPRIO"
+msgstr "Augmentation de RLIMIT_RTPRIO réussie"
+
+#: ../src/daemon/main.c:525
+#, c-format
+msgid "RLIMIT_RTPRIO failed: %s"
+msgstr "RLIMIT_RTPRIO a échoué : %s"
+
+#: ../src/daemon/main.c:532
+msgid "Giving up CAP_NICE"
+msgstr "Abandon de CAP_NICE"
+
+#: ../src/daemon/main.c:539
+msgid ""
+"Real-time scheduling enabled in configuration but not allowed by policy."
+msgstr ""
+"La planification en temps réel est activée mais n'est pas permise par la "
+"politique."
+
+#: ../src/daemon/main.c:597
+msgid "Daemon not running"
+msgstr "Lé démon n'est pas lancé"
+
+#: ../src/daemon/main.c:599
+#, c-format
+msgid "Daemon running as PID %u"
+msgstr "Le démon est lancé avec le PID %u"
+
+#: ../src/daemon/main.c:609
+#, c-format
+msgid "Failed to kill daemon: %s"
+msgstr "Impossible de tuer le démon : %s"
+
+#: ../src/daemon/main.c:627
+msgid ""
+"This program is not intended to be run as root (unless --system is "
+"specified)."
+msgstr ""
+"Le programme n'est pas conçu pour être lancé en tant que root (sauf si --"
+"system est renseigné)."
+
+#: ../src/daemon/main.c:629
+msgid "Root priviliges required."
+msgstr "Les permissions root sont nécessaires."
+
+#: ../src/daemon/main.c:634
+msgid "--start not supported for system instances."
+msgstr "--start n'est pas pris en charge pour les instances système."
+
+#: ../src/daemon/main.c:639
+msgid "Running in system mode, but --disallow-exit not set!"
+msgstr ""
+"Le démon s'exécute en mode système, mais --disallow-exit n'est pas défini."
+
+#: ../src/daemon/main.c:642
+msgid "Running in system mode, but --disallow-module-loading not set!"
+msgstr ""
+"Le démon s'exécute en mode système, mais --disallow-module-loading n'est pas "
+"défini."
+
+#: ../src/daemon/main.c:645
+msgid "Running in system mode, forcibly disabling SHM mode!"
+msgstr "Le démon s'exécute en mode système, désactivation forcée du mode SHM."
+
+#: ../src/daemon/main.c:650
+msgid "Running in system mode, forcibly disabling exit idle time!"
+msgstr ""
+"Le démon s'exécute en mode système, désactivation forcée de la fermeture "
+"après délai d'inactivité."
+
+#: ../src/daemon/main.c:677
+msgid "Failed to acquire stdio."
+msgstr "Échec lors de l'acquisition de stdio."
+
+#: ../src/daemon/main.c:683
+#, c-format
+msgid "pipe failed: %s"
+msgstr "Échec du tube : %s"
+
+#: ../src/daemon/main.c:688
+#, c-format
+msgid "fork() failed: %s"
+msgstr "Échec de fork() : %s"
+
+#: ../src/daemon/main.c:702
+#, c-format
+msgid "read() failed: %s"
+msgstr "Échec de read() : %s"
+
+#: ../src/daemon/main.c:708
+msgid "Daemon startup failed."
+msgstr "Échec lors du démarrage du démon."
+
+#: ../src/daemon/main.c:710
+msgid "Daemon startup successful."
+msgstr "Démarrage du démon réussi."
+
+#: ../src/daemon/main.c:780
+#, c-format
+msgid "This is PulseAudio %s"
+msgstr "Pulseaudio %s"
+
+#: ../src/daemon/main.c:781
+#, c-format
+msgid "Compilation CFLAGS: %s"
+msgstr "CFLAGS de compilation : %s"
+
+#: ../src/daemon/main.c:784
+msgid "Compiled with Valgrind support: yes"
+msgstr "Compilé avec la prise en charge Valgrind : oui"
+
+#: ../src/daemon/main.c:786
+msgid "Compiled with Valgrind support: no"
+msgstr "Compilé avec la prise en charge Valgrind : non"
+
+#: ../src/daemon/main.c:790
+msgid "Optimized build: yes"
+msgstr "Construction optimisée : oui"
+
+#: ../src/daemon/main.c:792
+msgid "Optimized build: no"
+msgstr "Construction optimisée : non"
+
+#: ../src/daemon/main.c:795
+#, c-format
+msgid "Page size is %lu bytes"
+msgstr "La taille de la page est de %lu octets"
+
+#: ../src/daemon/main.c:798
+msgid "Failed to get machine ID"
+msgstr "Échec lors de l'obtention de l'ID de la machine"
+
+#: ../src/daemon/main.c:801
+#, c-format
+msgid "Machine ID is %s."
+msgstr "L'ID de la machine est %s."
+
+#: ../src/daemon/main.c:806
+#, c-format
+msgid "Using runtime directory %s."
+msgstr "Utilisation du répertoire d'exécution %s."
+
+#: ../src/daemon/main.c:811
+#, c-format
+msgid "Using state directory %s."
+msgstr "Utilisation du répertoire d'état %s."
+
+#: ../src/daemon/main.c:814
+#, c-format
+msgid "Running in system mode: %s"
+msgstr "Exécution en mode système : %s"
+
+#: ../src/daemon/main.c:829
+msgid "pa_pid_file_create() failed."
+msgstr "Échec de pa_pid_file_create()."
+
+#: ../src/daemon/main.c:841
+msgid "Fresh high-resolution timers available! Bon appetit!"
+msgstr ""
+"De nouvelles horloges à haute résolution sont disponibles ! Bon appétit !"
+
+#: ../src/daemon/main.c:843
+msgid ""
+"Dude, your kernel stinks! The chef's recommendation today is Linux with high-"
+"resolution timers enabled!"
+msgstr ""
+"Eh mec, ton noyau il pue ! La recommandation d'aujourd'hui du patron est "
+"d'activer les horloges à haute résolution sur ton Linux."
+
+#: ../src/daemon/main.c:853
+msgid "pa_core_new() failed."
+msgstr "Échec de pa_core_new()."
+
+#: ../src/daemon/main.c:913
+msgid "Failed to initialize daemon."
+msgstr "Échec lors de l'initialisation du démon"
+
+#: ../src/daemon/main.c:918
+msgid "Daemon startup without any loaded modules, refusing to work."
+msgstr "Démarrage du démon sans aucun module chargé : refus de fonctionner."
+
+#: ../src/daemon/main.c:923
+#, c-format
+msgid "Default sink name (%s) does not exist in name register."
+msgstr ""
+"Le nom de la destination par défaut (%s) n'existe pas dans le registre des "
+"noms."
+
+#: ../src/daemon/main.c:936
+msgid "Daemon startup complete."
+msgstr "Démarrage du démon effectué."
+
+#: ../src/daemon/main.c:942
+msgid "Daemon shutdown initiated."
+msgstr "Fermeture du démon initiée."
+
+#: ../src/daemon/main.c:963
+msgid "Daemon terminated."
+msgstr "Démon terminé."
+
+#: ../src/daemon/cmdline.c:117
+#, c-format
+msgid ""
+"%s [options]\n"
+"\n"
+"COMMANDS:\n"
+" -h, --help Show this help\n"
+" --version Show version\n"
+" --dump-conf Dump default configuration\n"
+" --dump-modules Dump list of available modules\n"
+" --dump-resample-methods Dump available resample methods\n"
+" --cleanup-shm Cleanup stale shared memory "
+"segments\n"
+" --start Start the daemon if it is not "
+"running\n"
+" -k --kill Kill a running daemon\n"
+" --check Check for a running daemon\n"
+"\n"
+"OPTIONS:\n"
+" --system[=BOOL] Run as system-wide instance\n"
+" -D, --daemonize[=BOOL] Daemonize after startup\n"
+" --fail[=BOOL] Quit when startup fails\n"
+" --high-priority[=BOOL] Try to set high nice level\n"
+" (only available as root, when SUID "
+"or\n"
+" with elevated RLIMIT_NICE)\n"
+" --realtime[=BOOL] Try to enable realtime scheduling\n"
+" (only available as root, when SUID "
+"or\n"
+" with elevated RLIMIT_RTPRIO)\n"
+" --disallow-module-loading[=BOOL] Disallow module user requested "
+"module\n"
+" loading/unloading after startup\n"
+" --disallow-exit[=BOOL] Disallow user requested exit\n"
+" --exit-idle-time=SECS Terminate the daemon when idle and "
+"this\n"
+" time passed\n"
+" --module-idle-time=SECS Unload autoloaded modules when idle "
+"and\n"
+" this time passed\n"
+" --scache-idle-time=SECS Unload autoloaded samples when idle "
+"and\n"
+" this time passed\n"
+" --log-level[=LEVEL] Increase or set verbosity level\n"
+" -v Increase the verbosity level\n"
+" --log-target={auto,syslog,stderr} Specify the log target\n"
+" -p, --dl-search-path=PATH Set the search path for dynamic "
+"shared\n"
+" objects (plugins)\n"
+" --resample-method=METHOD Use the specified resampling method\n"
+" (See --dump-resample-methods for\n"
+" possible values)\n"
+" --use-pid-file[=BOOL] Create a PID file\n"
+" --no-cpu-limit[=BOOL] Do not install CPU load limiter on\n"
+" platforms that support it.\n"
+" --disable-shm[=BOOL] Disable shared memory support.\n"
+"\n"
+"STARTUP SCRIPT:\n"
+" -L, --load=\"MODULE ARGUMENTS\" Load the specified plugin module "
+"with\n"
+" the specified argument\n"
+" -F, --file=FILENAME Run the specified script\n"
+" -C Open a command line on the running "
+"TTY\n"
+" after startup\n"
+"\n"
+" -n Don't load default script file\n"
+msgstr ""
+"%s [options]\n"
+"\n"
+"COMMANDES :\n"
+" -h, --help Affiche cette aide\n"
+" --version Affiche la version\n"
+" --dump-conf Affiche la configuration par défaut\n"
+" --dump-modules Affiche la liste des modules "
+"disponibles\n"
+" --dump-resample-methods Affiche la liste des méthodes "
+"d'échantillonnage disponibles\n"
+" --cleanup-shm Nettoie les segments de mémoire "
+"partagée périmés\n"
+" --start Démarre le démon s'il n'est pas "
+"lancé\n"
+" -k --kill Tue un démon en cours d'exécution\n"
+" --check Vérifie s'il existe un démon en "
+"cours d'exécution\n"
+"\n"
+"OPTIONS :\n"
+" --system[=BOOL] Exécuter en tant qu'instance "
+"système\n"
+" -D, --daemonize[=BOOL] Définir en tant que démon après le "
+"démarrage\n"
+" --fail[=BOOL] Quitte quand le démarrage échoue\n"
+" --high-priority[=BOOL] Tente de définir un niveau nice plus "
+"élevé\n"
+" (seulement disponible en tant que "
+"root, avec le SUID ou\n"
+" avec un RLIMIT_NICE élevé)\n"
+" --realtime[=BOOL] Tente d'activer une planification en "
+"temps réel\n"
+" (seulement disponible en tant que "
+"root, avec le SUID ou\n"
+" ave un RLIMIT_RTPRIO élevé)\n"
+" --disallow-module-loading[=BOOL] Empêche les chargements/"
+"déchargements de module\n"
+" demandés par l'utilisateur après le "
+"démarrage\n"
+" --disallow-exit[=BOOL] Empêche les fermetures demandées par "
+"l'utilisateur\n"
+" --exit-idle-time=SECS Termine le démon quand la durée "
+"d'inactivité \n"
+" et ce temps se sont écoulés\n"
+" --module-idle-time=SECS Décharge les modules chargés "
+"automatiquement \n"
+" quand la durée d'inactivité et ce "
+"temps se sont écoulés\n"
+" --scache-idle-time=SECS Décharge les échantillons chargés "
+"automatiquement \n"
+" quand la durée d'inactivité et ce "
+"temps se sont écoulés\n"
+" --log-level[=NIVEAU] Augmente ou définit le niveau de "
+"verbosité\n"
+" -v Augmente le niveau de verbosité\n"
+" --log-target={auto,syslog,stderr} Indique la cible du journal\n"
+" -p, --dl-search-path=CHEMIN Définit le chemin de recherche pour "
+"les objets dynamiques\n"
+" partagés (extensions)\n"
+" --resample-method=MÉTHODE Utilise la méthode de "
+"rééchantillonnage indiquée\n"
+" (Voir --dump-resample-methods pour\n"
+" les valeurs possibles)\n"
+" --use-pid-file[=BOOL] Crée un fichier PID\n"
+" --no-cpu-limit[=BOOL] Ne pas installer de limiteur de "
+"charge CPU\n"
+" sur les plateformes qui le "
+"supportent.\n"
+" --disable-shm[=BOOL] Désactive la prise en charge de la "
+"mémoire partagée.\n"
+"\n"
+"SCRIPT DE DÉMARRAGE :\n"
+" -L, --load=\"PARAMÈTRES DU MODULE\" Charge le module d'extension indiqué "
+"avec\n"
+" le paramètre indiqué\n"
+" -F, --file=NOMDEFICHIER Exécute le script indiqué\n"
+" -C Ouvre une ligne de commande sur le "
+"TTY en cours \n"
+" après le démarrage\n"
+"\n"
+" -n Ne pas charger les fichiers de "
+"scripts par défaut\n"
+
+#: ../src/daemon/cmdline.c:245
+msgid "--daemonize expects boolean argument"
+msgstr "--daemonize requiert un paramètre booléen"
+
+#: ../src/daemon/cmdline.c:252
+msgid "--fail expects boolean argument"
+msgstr "--fail requiert un paramètre booléen"
+
+#: ../src/daemon/cmdline.c:262
+msgid ""
+"--log-level expects log level argument (either numeric in range 0..4 or one "
+"of debug, info, notice, warn, error)."
+msgstr ""
+"--log-level requiert un paramètre de niveau de journal (soit numérique entre "
+"0 et 4, soit de débogage : info, notice, warn , error)."
+
+#: ../src/daemon/cmdline.c:274
+msgid "--high-priority expects boolean argument"
+msgstr "--high-priority requiert un paramètre booléen"
+
+#: ../src/daemon/cmdline.c:281
+msgid "--realtime expects boolean argument"
+msgstr "--realtime requiert un paramètre booléen"
+
+#: ../src/daemon/cmdline.c:288
+msgid "--disallow-module-loading expects boolean argument"
+msgstr "--disallow-module-loading requiert un paramètre booléen"
+
+#: ../src/daemon/cmdline.c:295
+msgid "--disallow-exit boolean argument"
+msgstr "--disallow-exit requiert un paramètre booléen"
+
+#: ../src/daemon/cmdline.c:302
+msgid "--use-pid-file expects boolean argument"
+msgstr "--use-pid-file requiert un paramètre booléen"
+
+#: ../src/daemon/cmdline.c:319
+msgid "Invalid log target: use either 'syslog', 'stderr' or 'auto'."
+msgstr "Cible du journal invalide : utilisez « syslog », « stderr » ou « auto »."
+
+#: ../src/daemon/cmdline.c:338
+#, c-format
+msgid "Invalid resample method '%s'."
+msgstr "Méthode de rééchantillonnage invalide « %s »."
+
+#: ../src/daemon/cmdline.c:345
+msgid "--system expects boolean argument"
+msgstr "--system requiert un paramètre booléen"
+
+#: ../src/daemon/cmdline.c:352
+msgid "--no-cpu-limit expects boolean argument"
+msgstr "--no-cpu-limit requiert un paramètre booléen"
+
+#: ../src/daemon/cmdline.c:359
+msgid "--disable-shm expects boolean argument"
+msgstr "--disable-shm requiert un paramètre booléen"
+
+#: ../src/daemon/dumpmodules.c:60
+#, c-format
+msgid "Name: %s\n"
+msgstr "Nom : %s\n"
+
+#: ../src/daemon/dumpmodules.c:63
+#, c-format
+msgid "No module information available\n"
+msgstr "Aucune information de module disponible\n"
+
+#: ../src/daemon/dumpmodules.c:66
+#, c-format
+msgid "Version: %s\n"
+msgstr "Version : %s\n"
+
+#: ../src/daemon/dumpmodules.c:68
+#, c-format
+msgid "Description: %s\n"
+msgstr "Description : %s\n"
+
+#: ../src/daemon/dumpmodules.c:70
+#, c-format
+msgid "Author: %s\n"
+msgstr "Auteur : %s\n"
+
+#: ../src/daemon/dumpmodules.c:72
+#, c-format
+msgid "Usage: %s\n"
+msgstr "Utilisation : %s\n"
+
+#: ../src/daemon/dumpmodules.c:73
+#, c-format
+msgid "Load Once: %s\n"
+msgstr "Chargement unique : %s\n"
+
+#: ../src/daemon/dumpmodules.c:77
+#, c-format
+msgid "Path: %s\n"
+msgstr "Chemin : %s\n"
+
+# dans les lignes suivantes [%s = nom de fichier: %u = ligne dans celui-ci]
+#: ../src/daemon/daemon-conf.c:203
+#, c-format
+msgid "[%s:%u] Invalid log target '%s'."
+msgstr "[%s:%u] Cible du journal « %s » invalide."
+
+#: ../src/daemon/daemon-conf.c:219
+#, c-format
+msgid "[%s:%u] Invalid log level '%s'."
+msgstr "[%s:%u] Niveau du journal « %s » invalide."
+
+#: ../src/daemon/daemon-conf.c:235
+#, c-format
+msgid "[%s:%u] Invalid resample method '%s'."
+msgstr "[%s:%u] Méthode de rééchantillonnage « %s » invalide."
+
+#: ../src/daemon/daemon-conf.c:258
+#, c-format
+msgid "[%s:%u] Invalid rlimit '%s'."
+msgstr "[%s:%u] rlimit « %s » invalide."
+
+#: ../src/daemon/daemon-conf.c:265
+#, c-format
+msgid "[%s:%u] rlimit not supported on this platform."
+msgstr "[%s:%u] rlimit n'est pas pris en charge sur cette plateforme."
+
+#: ../src/daemon/daemon-conf.c:281
+#, c-format
+msgid "[%s:%u] Invalid sample format '%s'."
+msgstr "[%s:%u] Format d'échantillon « %s » invalide."
+
+#: ../src/daemon/daemon-conf.c:299
+#, c-format
+msgid "[%s:%u] Invalid sample rate '%s'."
+msgstr "[%s:%u] Taux d'échantillonnage « %s » invalide."
+
+#: ../src/daemon/daemon-conf.c:317
+#, c-format
+msgid "[%s:%u] Invalid sample channels '%s'."
+msgstr "[%s:%u] Canaux d'échantillonnage « %s » invalide."
+
+#: ../src/daemon/daemon-conf.c:335
+#, c-format
+msgid "[%s:%u] Invalid number of fragments '%s'."
+msgstr "[%s:%u] Nombre de fragments « %s » invalide."
+
+#: ../src/daemon/daemon-conf.c:353
+#, c-format
+msgid "[%s:%u] Invalid fragment size '%s'."
+msgstr "[%s:%u] Taille du fragment « %s » invalide."
+
+#: ../src/daemon/daemon-conf.c:371
+#, c-format
+msgid "[%s:%u] Invalid nice level '%s'."
+msgstr "[%s:%u] Niveau de priorité (nice) « %s » invalide."
+
+#: ../src/daemon/daemon-conf.c:564
+#, c-format
+msgid "Failed to open configuration file: %s"
+msgstr "Échec lors de l'ouverture du fichier de configuration : %s"
+
+#: ../src/daemon/daemon-conf.c:638
+#, c-format
+msgid "### Read from configuration file: %s ###\n"
+msgstr "### Lecture à partir du fichier de configuration : %s ###\n"
+
+#: ../src/daemon/caps.c:62
+msgid "Dropping root priviliges."
+msgstr "Abandon des permissions root."
+
+#: ../src/daemon/caps.c:102
+msgid "Limited capabilities successfully to CAP_SYS_NICE."
+msgstr "Limitation des capacités à CAP_SYS_NICE réussie."
+
+#: ../src/pulse/channelmap.c:102
+msgid "Mono"
+msgstr "Mono"
+
+#: ../src/pulse/channelmap.c:104
+msgid "Front Center"
+msgstr "Avant centre"
+
+#: ../src/pulse/channelmap.c:105
+msgid "Front Left"
+msgstr "Avant gauche"
+
+#: ../src/pulse/channelmap.c:106
+msgid "Front Right"
+msgstr "Avant droit"
+
+#: ../src/pulse/channelmap.c:108
+msgid "Rear Center"
+msgstr "Arrière centre"
+
+#: ../src/pulse/channelmap.c:109
+msgid "Rear Left"
+msgstr "Arrière gauche"
+
+#: ../src/pulse/channelmap.c:110
+msgid "Rear Right"
+msgstr "Arrière droit"
+
+#: ../src/pulse/channelmap.c:112
+msgid "Low Frequency Emmiter"
+msgstr "Émetteur à basse fréquence"
+
+#: ../src/pulse/channelmap.c:114
+msgid "Front Left-of-center"
+msgstr "Avant à gauche du centre"
+
+#: ../src/pulse/channelmap.c:115
+msgid "Front Right-of-center"
+msgstr "Avant à droite du centre"
+
+#: ../src/pulse/channelmap.c:117
+msgid "Side Left"
+msgstr "Côté gauche"
+
+#: ../src/pulse/channelmap.c:118
+msgid "Side Right"
+msgstr "Côté droit"
+
+#: ../src/pulse/channelmap.c:120
+msgid "Auxiliary 0"
+msgstr "Auxiliaire 0"
+
+#: ../src/pulse/channelmap.c:121
+msgid "Auxiliary 1"
+msgstr "Auxiliaire 1"
+
+#: ../src/pulse/channelmap.c:122
+msgid "Auxiliary 2"
+msgstr "Auxiliaire 2"
+
+#: ../src/pulse/channelmap.c:123
+msgid "Auxiliary 3"
+msgstr "Auxiliaire 3"
+
+#: ../src/pulse/channelmap.c:124
+msgid "Auxiliary 4"
+msgstr "Auxiliaire 4"
+
+#: ../src/pulse/channelmap.c:125
+msgid "Auxiliary 5"
+msgstr "Auxiliaire 5"
+
+#: ../src/pulse/channelmap.c:126
+msgid "Auxiliary 6"
+msgstr "Auxiliaire 6"
+
+#: ../src/pulse/channelmap.c:127
+msgid "Auxiliary 7"
+msgstr "Auxiliaire 7"
+
+#: ../src/pulse/channelmap.c:128
+msgid "Auxiliary 8"
+msgstr "Auxiliaire 8"
+
+#: ../src/pulse/channelmap.c:129
+msgid "Auxiliary 9"
+msgstr "Auxiliaire 9"
+
+#: ../src/pulse/channelmap.c:130
+msgid "Auxiliary 10"
+msgstr "Auxiliaire 10"
+
+#: ../src/pulse/channelmap.c:131
+msgid "Auxiliary 11"
+msgstr "Auxiliaire 11"
+
+#: ../src/pulse/channelmap.c:132
+msgid "Auxiliary 12"
+msgstr "Auxiliaire 12"
+
+#: ../src/pulse/channelmap.c:133
+msgid "Auxiliary 13"
+msgstr "Auxiliaire 13"
+
+#: ../src/pulse/channelmap.c:134
+msgid "Auxiliary 14"
+msgstr "Auxiliaire 14"
+
+#: ../src/pulse/channelmap.c:135
+msgid "Auxiliary 15"
+msgstr "Auxiliaire 15"
+
+#: ../src/pulse/channelmap.c:136
+msgid "Auxiliary 16"
+msgstr "Auxiliaire 16"
+
+#: ../src/pulse/channelmap.c:137
+msgid "Auxiliary 17"
+msgstr "Auxiliaire 17"
+
+#: ../src/pulse/channelmap.c:138
+msgid "Auxiliary 18"
+msgstr "Auxiliaire 18"
+
+#: ../src/pulse/channelmap.c:139
+msgid "Auxiliary 19"
+msgstr "Auxiliaire 19"
+
+#: ../src/pulse/channelmap.c:140
+msgid "Auxiliary 20"
+msgstr "Auxiliaire 20"
+
+#: ../src/pulse/channelmap.c:141
+msgid "Auxiliary 21"
+msgstr "Auxiliaire 21"
+
+#: ../src/pulse/channelmap.c:142
+msgid "Auxiliary 22"
+msgstr "Auxiliaire 22"
+
+#: ../src/pulse/channelmap.c:143
+msgid "Auxiliary 23"
+msgstr "Auxiliaire 23"
+
+#: ../src/pulse/channelmap.c:144
+msgid "Auxiliary 24"
+msgstr "Auxiliaire 24"
+
+#: ../src/pulse/channelmap.c:145
+msgid "Auxiliary 25"
+msgstr "Auxiliaire 25"
+
+#: ../src/pulse/channelmap.c:146
+msgid "Auxiliary 26"
+msgstr "Auxiliaire 26"
+
+#: ../src/pulse/channelmap.c:147
+msgid "Auxiliary 27"
+msgstr "Auxiliaire 27"
+
+#: ../src/pulse/channelmap.c:148
+msgid "Auxiliary 28"
+msgstr "Auxiliaire 28"
+
+#: ../src/pulse/channelmap.c:149
+msgid "Auxiliary 29"
+msgstr "Auxiliaire 29"
+
+#: ../src/pulse/channelmap.c:150
+msgid "Auxiliary 30"
+msgstr "Auxiliaire 30"
+
+#: ../src/pulse/channelmap.c:151
+msgid "Auxiliary 31"
+msgstr "Auxiliaire 31"
+
+#: ../src/pulse/channelmap.c:153
+msgid "Top Center"
+msgstr "Centre haut"
+
+#: ../src/pulse/channelmap.c:155
+msgid "Top Front Center"
+msgstr "Avant centre haut"
+
+#: ../src/pulse/channelmap.c:156
+msgid "Top Front Left"
+msgstr "Avant gauche haut"
+
+#: ../src/pulse/channelmap.c:157
+msgid "Top Front Right"
+msgstr "Avant droit haut"
+
+#: ../src/pulse/channelmap.c:159
+msgid "Top Rear Center"
+msgstr "Arrière centre haut"
+
+#: ../src/pulse/channelmap.c:160
+msgid "Top Rear Left"
+msgstr "Arrière gauche haut"
+
+#: ../src/pulse/channelmap.c:161
+msgid "Top Rear Right"
+msgstr "Arrière droit haut"
+
+#: ../src/pulse/error.c:43
+msgid "OK"
+msgstr "OK"
+
+#: ../src/pulse/error.c:44
+msgid "Access denied"
+msgstr "Accès refusé"
+
+#: ../src/pulse/error.c:45
+msgid "Unknown command"
+msgstr "Commande inconnue"
+
+#: ../src/pulse/error.c:46
+msgid "Invalid argument"
+msgstr "Paramètre invalide"
+
+#: ../src/pulse/error.c:47
+msgid "Entity exists"
+msgstr "L'entité existe"
+
+#: ../src/pulse/error.c:48
+msgid "No such entity"
+msgstr "Aucune entité de ce type"
+
+#: ../src/pulse/error.c:49
+msgid "Connection refused"
+msgstr "Connexion refusée"
+
+#: ../src/pulse/error.c:50
+msgid "Protocol error"
+msgstr "Erreur du protocole"
+
+#: ../src/pulse/error.c:51
+msgid "Timeout"
+msgstr "Délai dépassé"
+
+#: ../src/pulse/error.c:52
+msgid "No authorization key"
+msgstr "Aucune clé d'autorisation"
+
+#: ../src/pulse/error.c:53
+msgid "Internal error"
+msgstr "Erreur interne"
+
+#: ../src/pulse/error.c:54
+msgid "Connection terminated"
+msgstr "Connexion terminée"
+
+#: ../src/pulse/error.c:55
+msgid "Entity killed"
+msgstr "L'entité a été tuée"
+
+#: ../src/pulse/error.c:56
+msgid "Invalid server"
+msgstr "Serveur invalide"
+
+#: ../src/pulse/error.c:57
+msgid "Module initalization failed"
+msgstr "Échec lors de l'initialisation du module"
+
+#: ../src/pulse/error.c:58
+msgid "Bad state"
+msgstr "État incorrect"
+
+#: ../src/pulse/error.c:59
+msgid "No data"
+msgstr "Aucune donnée"
+
+#: ../src/pulse/error.c:60
+msgid "Incompatible protocol version"
+msgstr "Version du protocole invalide"
+
+#: ../src/pulse/error.c:61
+msgid "Too large"
+msgstr "Trop grand"
+
+#: ../src/pulse/error.c:62
+msgid "Not supported"
+msgstr "Non pris en charge"
+
+#: ../src/pulse/error.c:63
+msgid "Unknown error code"
+msgstr "Code d'erreur inconnu"
+
+#: ../src/pulse/error.c:64
+msgid "No such extension"
+msgstr "Aucune extension de ce type"
+
+#: ../src/pulse/sample.c:134
+msgid "Invalid"
+msgstr "Invalide"
+
+#: ../src/pulse/client-conf-x11.c:55 ../src/utils/pax11publish.c:100
+msgid "XOpenDisplay() failed"
+msgstr "Échec de XOpenDisplay()"
+
+#: ../src/pulse/client-conf-x11.c:78
+msgid "Failed to parse cookie data"
+msgstr "Échec lors de l'analyse des données du cookie"
+
+#: ../src/pulse/client-conf.c:117
+#, c-format
+msgid "Failed to open configuration file '%s': %s"
+msgstr "Échec lors de l'ouverture du fichier de configuration « %s » :%s"
+
+#: ../src/pulse/context.c:542
+msgid "No cookie loaded. Attempting to connect without."
+msgstr "Aucun cookie chargé. Tentative de connexion sans celui-ci."
+
+#: ../src/pulse/context.c:596
+#, c-format
+msgid "socketpair(): %s"
+msgstr "socketpair() : %s"
+
+#: ../src/pulse/context.c:610
+#, c-format
+msgid "fork(): %s"
+msgstr "fork() : %s"
+
+#: ../src/pulse/context.c:673
+#, c-format
+msgid "waitpid(): %s"
+msgstr "waitpid() : %s"
+
+#: ../src/pulse/context.c:1354
+#, c-format
+msgid "Received message for unknown extension '%s'"
+msgstr "Message reçu pour une extension inconnue « %s »"
+
+#: ../src/utils/pacat.c:93
+#, c-format
+msgid "pa_stream_write() failed: %s\n"
+msgstr "Échec de pa_stream_write() : %s\n"
+
+#: ../src/utils/pacat.c:132
+#, c-format
+msgid "pa_stream_peek() failed: %s\n"
+msgstr "Échec de pa_stream_peek() : %s\n"
+
+#: ../src/utils/pacat.c:141
+#, c-format
+msgid "Buffer overrun, dropping incoming data\n"
+msgstr "Saturation du tampon, abandon des données entrantes\n"
+
+#: ../src/utils/pacat.c:143
+#, c-format
+msgid "pa_stream_drop() failed: %s\n"
+msgstr "Échec de pa_stream_drop() : %s\n"
+
+#: ../src/utils/pacat.c:169
+#, c-format
+msgid "Stream successfully created.\n"
+msgstr "Création du flux réussie.\n"
+
+#: ../src/utils/pacat.c:172
+#, c-format
+msgid "pa_stream_get_buffer_attr() failed: %s\n"
+msgstr "Échec de pa_stream_get_buffer_attr() : %s\n"
+
+#: ../src/utils/pacat.c:176
+#, c-format
+msgid "Buffer metrics: maxlength=%u, tlength=%u, prebuf=%u, minreq=%u\n"
+msgstr "Mesures du tampon : maxlength=%u, tlength=%u, prebuf=%u, minreq=%u\n"
+
+#: ../src/utils/pacat.c:179
+#, c-format
+msgid "Buffer metrics: maxlength=%u, fragsize=%u\n"
+msgstr "Mesures du tampon : maxlength=%u, fragsize=%u\n"
+
+#: ../src/utils/pacat.c:183
+#, c-format
+msgid "Using sample spec '%s', channel map '%s'.\n"
+msgstr ""
+"Utilisation de la spécification d'échantillon « %s », plan des canaux « %s ».\n"
+
+# l'espace manquant entre %s et suspended est voulu
+#: ../src/utils/pacat.c:187
+#, c-format
+msgid "Connected to device %s (%u, %ssuspended).\n"
+msgstr "Connecté au périphérique %s (%u, %ssuspendu).\n"
+
+#: ../src/utils/pacat.c:197
+#, c-format
+msgid "Stream error: %s\n"
+msgstr "Erreur du flux : %s\n"
+
+#: ../src/utils/pacat.c:207
+#, c-format
+msgid "Stream device suspended.%s \n"
+msgstr "Périphérique de flux suspendu %s \n"
+
+#: ../src/utils/pacat.c:209
+#, c-format
+msgid "Stream device resumed.%s \n"
+msgstr "Périphérique de flux repris %s \n"
+
+#: ../src/utils/pacat.c:217
+#, c-format
+msgid "Stream underrun.%s \n"
+msgstr "Flux vide %s \n"
+
+#: ../src/utils/pacat.c:224
+#, c-format
+msgid "Stream overrun.%s \n"
+msgstr "Flux saturé %s \n"
+
+#: ../src/utils/pacat.c:231
+#, c-format
+msgid "Stream started.%s \n"
+msgstr "Flux démarré %s \n"
+
+#: ../src/utils/pacat.c:238
+#, c-format
+msgid "Stream moved to device %s (%u, %ssuspended).%s \n"
+msgstr "Flux déplacé vers le périphérique %s (%u, %ssuspendu).%s \n"
+
+# suspendu ou non suspendu
+#: ../src/utils/pacat.c:238
+msgid "not "
+msgstr "non "
+
+#: ../src/utils/pacat.c:259
+#, c-format
+msgid "Connection established.%s \n"
+msgstr "Connection établie.%s \n"
+
+#: ../src/utils/pacat.c:262
+#, c-format
+msgid "pa_stream_new() failed: %s\n"
+msgstr "Échec de pa_stream_new() : %s\n"
+
+#: ../src/utils/pacat.c:287
+#, c-format
+msgid "pa_stream_connect_playback() failed: %s\n"
+msgstr "Échec de pa_stream_connect_playback() : %s\n"
+
+#: ../src/utils/pacat.c:293
+#, c-format
+msgid "pa_stream_connect_record() failed: %s\n"
+msgstr "Échec de pa_stream_connect_record() : %s\n"
+
+#: ../src/utils/pacat.c:307 ../src/utils/pasuspender.c:159
+#: ../src/utils/pactl.c:666 ../src/utils/paplay.c:183
+#, c-format
+msgid "Connection failure: %s\n"
+msgstr "Échec lors de la connexion : %s\n"
+
+#: ../src/utils/pacat.c:328 ../src/utils/paplay.c:75
+#, c-format
+msgid "Failed to drain stream: %s\n"
+msgstr "Échec lors du vidage du flux : %s\n"
+
+#: ../src/utils/pacat.c:333 ../src/utils/paplay.c:80
+#, c-format
+msgid "Playback stream drained.\n"
+msgstr "Flux de lecture vidé.\n"
+
+#: ../src/utils/pacat.c:343 ../src/utils/paplay.c:92
+#, c-format
+msgid "Draining connection to server.\n"
+msgstr "Vidage de la connexion au serveur.\n"
+
+#: ../src/utils/pacat.c:369
+#, c-format
+msgid "Got EOF.\n"
+msgstr "EOF obtenu.\n"
+
+#: ../src/utils/pacat.c:375
+#, c-format
+msgid "pa_stream_drain(): %s\n"
+msgstr "pa_stream_drain() : %s\n"
+
+#: ../src/utils/pacat.c:385
+#, c-format
+msgid "read() failed: %s\n"
+msgstr "Échec de read() : %s\n"
+
+#: ../src/utils/pacat.c:417
+#, c-format
+msgid "write() failed: %s\n"
+msgstr "Échec de write() : %s\n"
+
+#: ../src/utils/pacat.c:438
+#, c-format
+msgid "Got signal, exiting.\n"
+msgstr "Signal obtenu, fermeture.\n"
+
+#: ../src/utils/pacat.c:452
+#, c-format
+msgid "Failed to get latency: %s\n"
+msgstr "Échec lors de l'obtention de la latence : %s\n"
+
+#: ../src/utils/pacat.c:457
+#, c-format
+msgid "Time: %0.3f sec; Latency: %0.0f usec. \r"
+msgstr "Durée : %0.3f s ; Latency : %0.0f µs. \r"
+
+#: ../src/utils/pacat.c:477
+#, c-format
+msgid "pa_stream_update_timing_info() failed: %s\n"
+msgstr "Échec de pa_stream_update_timing_info() : %s\n"
+
+# downmix = par ex. convertir 5 canaux en 2 canaux
+# upmixer = par ex. convertir 2 canaux en 5 canaux
+# https://bugzilla.redhat.com/show_bug.cgi?id=460798
+#: ../src/utils/pacat.c:490
+#, c-format
+msgid ""
+"%s [options]\n"
+"\n"
+" -h, --help Show this help\n"
+" --version Show version\n"
+"\n"
+" -r, --record Create a connection for recording\n"
+" -p, --playback Create a connection for playback\n"
+"\n"
+" -v, --verbose Enable verbose operations\n"
+"\n"
+" -s, --server=SERVER The name of the server to connect "
+"to\n"
+" -d, --device=DEVICE The name of the sink/source to "
+"connect to\n"
+" -n, --client-name=NAME How to call this client on the "
+"server\n"
+" --stream-name=NAME How to call this stream on the "
+"server\n"
+" --volume=VOLUME Specify the initial (linear) volume "
+"in range 0...65536\n"
+" --rate=SAMPLERATE The sample rate in Hz (defaults to "
+"44100)\n"
+" --format=SAMPLEFORMAT The sample type, one of s16le, "
+"s16be, u8, float32le,\n"
+" float32be, ulaw, alaw (defaults to "
+"s16ne)\n"
+" --channels=CHANNELS The number of channels, 1 for mono, "
+"2 for stereo\n"
+" (defaults to 2)\n"
+" --channel-map=CHANNELMAP Channel map to use instead of the "
+"default\n"
+" --fix-format Take the sample format from the sink "
+"the stream is\n"
+" being connected to.\n"
+" --fix-rate Take the sampling rate from the sink "
+"the stream is\n"
+" being connected to.\n"
+" --fix-channels Take the number of channels and the "
+"channel map\n"
+" from the sink the stream is being "
+"connected to.\n"
+" --no-remix Don't upmix or downmix channels.\n"
+" --no-remap Map channels by index instead of "
+"name.\n"
+" --latency=BYTES Request the specified latency in "
+"bytes.\n"
+" --process-time=BYTES Request the specified process time "
+"per request in bytes.\n"
+msgstr ""
+"%s [options]\n"
+"\n"
+" -h, --help Affiche cette aide\n"
+" --version Affiche la version\n"
+"\n"
+" -r, --record Crée une connexion pour "
+"l'enregistrement\n"
+" -p, --playback Crée une connexion pour la lecture\n"
+"\n"
+" -v, --verbose Active le mode verbeux\n"
+"\n"
+" -s, --server=SERVEUR Le nom du serveur auquel se "
+"connecter\n"
+" -d, --device=PÉRIPHÉRIQUE Le nom de la destination/source à "
+"laquelle de connecter\n"
+" -n, --client-name=NOM Définit le nom de ce client sur le "
+"serveur\n"
+" --stream-name=NOM Définit le nom de ce flux sur le "
+"serveur\n"
+" --volume=VOLUME Indique le volume initial (linéaire) "
+"entre 0 et 65536\n"
+" --rate=TAUXDÉCHANTILLONNAGE Le taux d'échantillonnage en Hz (par "
+"défaut 44100)\n"
+" --format=FORMATDELÉCHANTILLON Le type de l'échantillon, parmi : "
+"s16le, s16be, u8, float32le,\n"
+" float32be, ulaw, alaw (par défaut "
+"s16ne)\n"
+" --channels=CANAUX Le nombre de canaux, 1 pour mono, 2 "
+"pour stéréo\n"
+" (par défaut 2)\n"
+" --channel-map=PLANDESCANAUX Plan des canaux à utiliser au lieu "
+"de celui par défaut\n"
+" --fix-format Prend le format de l'échantillon de "
+"la destination où le flux\n"
+" est en train de se connecter.\n"
+" --fix-rate Prend le taux d'échantillonnage de "
+"la destination où le flux\n"
+" est en train de se connecter.\n"
+" --fix-channels Prend le nombre et le plan des "
+"canaux de la destination \n"
+" où le flux est en train de se "
+"connecter.\n"
+" --no-remix Ne pas augmenter ou diminuer le "
+"nombre de canaux par mixage.\n"
+" --no-remap Créer le plan des canaux par index "
+"et non par nom.\n"
+" --latency=OCTETS Demande la latence indiquée en "
+"octets.\n"
+" --process-time=OCTETS Demande le temps de traitement "
+"indiqué par requête en octets.\n"
+
+#: ../src/utils/pacat.c:591
+#, c-format
+msgid ""
+"pacat %s\n"
+"Compiled with libpulse %s\n"
+"Linked with libpulse %s\n"
+msgstr ""
+"pacat %s\n"
+"Compilé avec libpulse %s\n"
+"Lié avec libpulse %s\n"
+
+#: ../src/utils/pacat.c:647
+#, c-format
+msgid "Invalid channel map '%s'\n"
+msgstr "Plan des canaux invalide « %s »\n"
+
+#: ../src/utils/pacat.c:676
+#, c-format
+msgid "Invalid latency specification '%s'\n"
+msgstr "Spécification de latence invalide « %s »\n"
+
+#: ../src/utils/pacat.c:683
+#, c-format
+msgid "Invalid process time specification '%s'\n"
+msgstr "Spécification de temps de traitement invalide « %s »\n"
+
+#: ../src/utils/pacat.c:694
+#, c-format
+msgid "Invalid sample specification\n"
+msgstr "Spécification d'échantillon invalide\n"
+
+#: ../src/utils/pacat.c:699
+#, c-format
+msgid "Channel map doesn't match sample specification\n"
+msgstr ""
+"Le plan des canaux ne correspond pas à la spécification d'échantillon\n"
+
+#: ../src/utils/pacat.c:706
+#, c-format
+msgid "Opening a %s stream with sample specification '%s'.\n"
+msgstr "Ouverture d'un flux %s avec une spécification d'échantillon « %s ».\n"
+
+#: ../src/utils/pacat.c:706
+msgid "recording"
+msgstr "enregistrement"
+
+#: ../src/utils/pacat.c:706
+msgid "playback"
+msgstr "lecture"
+
+#: ../src/utils/pacat.c:714
+#, c-format
+msgid "open(): %s\n"
+msgstr "open() : %s\n"
+
+#: ../src/utils/pacat.c:719
+#, c-format
+msgid "dup2(): %s\n"
+msgstr "dup2() : %s\n"
+
+#: ../src/utils/pacat.c:729
+#, c-format
+msgid "Too many arguments.\n"
+msgstr "Trop de paramètres.\n"
+
+#: ../src/utils/pacat.c:742 ../src/utils/pasuspender.c:280
+#: ../src/utils/pactl.c:909 ../src/utils/paplay.c:381
+#, c-format
+msgid "pa_mainloop_new() failed.\n"
+msgstr "Échec de pa_mainloop_new().\n"
+
+#: ../src/utils/pacat.c:763
+#, c-format
+msgid "io_new() failed.\n"
+msgstr "Échec de io_new().\n"
+
+#: ../src/utils/pacat.c:769 ../src/utils/pasuspender.c:293
+#: ../src/utils/pactl.c:923 ../src/utils/paplay.c:396
+#, c-format
+msgid "pa_context_new() failed.\n"
+msgstr "Échec de pa_context_new().\n"
+
+#: ../src/utils/pacat.c:785
+#, c-format
+msgid "time_new() failed.\n"
+msgstr "Échec de time_new().\n"
+
+#: ../src/utils/pacat.c:792 ../src/utils/pasuspender.c:301
+#: ../src/utils/pactl.c:931 ../src/utils/paplay.c:407
+#, c-format
+msgid "pa_mainloop_run() failed.\n"
+msgstr "Échec de pa_mainloop_run().\n"
+
+#: ../src/utils/pasuspender.c:81
+#, c-format
+msgid "fork(): %s\n"
+msgstr "fork() : %s\n"
+
+#: ../src/utils/pasuspender.c:92
+#, c-format
+msgid "execvp(): %s\n"
+msgstr "execvp() : %s\n"
+
+#: ../src/utils/pasuspender.c:109
+#, c-format
+msgid "Failure to suspend: %s\n"
+msgstr "Échec lors de la suspension : %s\n"
+
+#: ../src/utils/pasuspender.c:124
+#, c-format
+msgid "Failure to resume: %s\n"
+msgstr "Échec lors de la reprise : %s\n"
+
+#: ../src/utils/pasuspender.c:147
+#, c-format
+msgid "WARNING: Sound server is not local, not suspending.\n"
+msgstr ""
+"AVERTISSEMENT : le serveur de son n'est pas local, suspension annulée.\n"
+
+#: ../src/utils/pasuspender.c:176 ../src/utils/pactl.c:672
+#: ../src/utils/paplay.c:191
+#, c-format
+msgid "Got SIGINT, exiting.\n"
+msgstr "SIGINT reçu, fermeture.\n"
+
+#: ../src/utils/pasuspender.c:194
+#, c-format
+msgid "WARNING: Child process terminated by signal %u\n"
+msgstr "AVERTISSEMENT : le processus fils a été terminé par le signal %u\n"
+
+#: ../src/utils/pasuspender.c:212
+#, c-format
+msgid ""
+"%s [options] ... \n"
+"\n"
+" -h, --help Show this help\n"
+" --version Show version\n"
+" -s, --server=SERVER The name of the server to connect "
+"to\n"
+"\n"
+msgstr ""
+"%s [options] ... \n"
+"\n"
+" -h, --help Affiche cette aide\n"
+" --version Affiche la version\n"
+" -s, --server=SERVEUR Le nom du serveur auquel se "
+"connecter\n"
+"\n"
+
+#: ../src/utils/pasuspender.c:251
+#, c-format
+msgid ""
+"pasuspender %s\n"
+"Compiled with libpulse %s\n"
+"Linked with libpulse %s\n"
+msgstr ""
+"pasuspender %s\n"
+"Compilé avec libpulse %s\n"
+"Lié avec libpulse %s\n"
+
+#: ../src/utils/pactl.c:107
+#, c-format
+msgid "Failed to get statistics: %s\n"
+msgstr "Échec lors de l'obtention des statistiques : %s\n"
+
+#: ../src/utils/pactl.c:113
+#, c-format
+msgid "Currently in use: %u blocks containing %s bytes total.\n"
+msgstr "En cours d'utilisation : %u blocs contenant au total %s octets.\n"
+
+#: ../src/utils/pactl.c:116
+#, c-format
+msgid "Allocated during whole lifetime: %u blocks containing %s bytes total.\n"
+msgstr ""
+"Alloué pendant l'ensemble de la durée d'exécution : %u blocs contenant au "
+"total %s octets.\n"
+
+#: ../src/utils/pactl.c:119
+#, c-format
+msgid "Sample cache size: %s\n"
+msgstr "Taille du cache de l'échantillon : %s\n"
+
+#: ../src/utils/pactl.c:128
+#, c-format
+msgid "Failed to get server information: %s\n"
+msgstr "Échec lors de l'obtention des informations du serveur : %s\n"
+
+#: ../src/utils/pactl.c:135
+#, c-format
+msgid ""
+"User name: %s\n"
+"Host Name: %s\n"
+"Server Name: %s\n"
+"Server Version: %s\n"
+"Default Sample Specification: %s\n"
+"Default Sink: %s\n"
+"Default Source: %s\n"
+"Cookie: %08x\n"
+msgstr ""
+"Nom d'utilisateur : %s\n"
+"Nom d'hôte : %s\n"
+"Nom du serveur : %s\n"
+"Version du serveur : %s\n"
+"Spécification d'échantillon par défaut : %s\n"
+"Destination par défaut : %s\n"
+"Source par défaut : %s\n"
+"Cookie : %08x\n"
+
+#: ../src/utils/pactl.c:160
+#, c-format
+msgid "Failed to get sink information: %s\n"
+msgstr "Échec lors de l'obtention des informations sur la destination : %s\n"
+
+# demander à Lennart s'il s'agit de monitor of source
+#: ../src/utils/pactl.c:176
+#, c-format
+msgid ""
+"*** Sink #%u ***\n"
+"Name: %s\n"
+"Driver: %s\n"
+"Sample Specification: %s\n"
+"Channel Map: %s\n"
+"Owner Module: %u\n"
+"Volume: %s\n"
+"Monitor Source: %s\n"
+"Latency: %0.0f usec, configured %0.0f usec\n"
+"Flags: %s%s%s%s%s%s\n"
+"Properties:\n"
+"%s"
+msgstr ""
+"*** Destination #%u ***\n"
+"Nom : %s\n"
+"Pilote : %s\n"
+"Spécification de l'échantillon : %s\n"
+"Plan des canaux : %s\n"
+"Module propriétaire : %u\n"
+"Volume : %s\n"
+"Moniteur de la source : %s\n"
+"Latence : %0.0f µs, %0.0f µs configurée \n"
+"Drapeaux : %s%s%s%s%s%s\n"
+"Propriétés :\n"
+"%s"
+
+#: ../src/utils/pactl.c:193 ../src/utils/pactl.c:371
+msgid "muted"
+msgstr "en sourdine"
+
+#: ../src/utils/pactl.c:212
+#, c-format
+msgid "Failed to get source information: %s\n"
+msgstr "Échec lors de l'obtention des informations sur la source : %s\n"
+
+#: ../src/utils/pactl.c:228
+#, c-format
+msgid ""
+"*** Source #%u ***\n"
+"Name: %s\n"
+"Driver: %s\n"
+"Sample Specification: %s\n"
+"Channel Map: %s\n"
+"Owner Module: %u\n"
+"Volume: %s\n"
+"Monitor of Sink: %s\n"
+"Latency: %0.0f usec, configured %0.0f usec\n"
+"Flags: %s%s%s%s%s%s\n"
+"Properties:\n"
+"%s"
+msgstr ""
+"*** Source #%u ***\n"
+"Nom : %s\n"
+"Pilote : %s\n"
+"Spécification de l'échantillon : %s\n"
+"Plan des canaux : %s\n"
+"Module propriétaire : %u\n"
+"Volume : %s\n"
+"Moniteur de la destination : %s\n"
+"Latence : %0.0f µs, %0.0f µs configurée \n"
+"Drapeaux : %s%s%s%s%s%s\n"
+"Propriétés :\n"
+"%s"
+
+#: ../src/utils/pactl.c:246 ../src/utils/pactl.c:289 ../src/utils/pactl.c:322
+#: ../src/utils/pactl.c:366 ../src/utils/pactl.c:367 ../src/utils/pactl.c:374
+#: ../src/utils/pactl.c:418 ../src/utils/pactl.c:419 ../src/utils/pactl.c:425
+#: ../src/utils/pactl.c:468 ../src/utils/pactl.c:469 ../src/utils/pactl.c:473
+msgid "n/a"
+msgstr "n/d"
+
+#: ../src/utils/pactl.c:263
+#, c-format
+msgid "Failed to get module information: %s\n"
+msgstr "Échec lors de l'obtention des informations du module : %s\n"
+
+#: ../src/utils/pactl.c:281
+#, c-format
+msgid ""
+"*** Module #%u ***\n"
+"Name: %s\n"
+"Argument: %s\n"
+"Usage counter: %s\n"
+"Auto unload: %s\n"
+msgstr ""
+"*** Module #%u ***\n"
+"Nom : %s\n"
+"Paramètre : %s\n"
+"Nombre d'utilisations : %s\n"
+"Déchargement automatique : %s\n"
+
+#: ../src/utils/pactl.c:298
+#, c-format
+msgid "Failed to get client information: %s\n"
+msgstr "Échec lors de l'obtention des informations du client : %s\n"
+
+#: ../src/utils/pactl.c:316
+#, c-format
+msgid ""
+"*** Client #%u ***\n"
+"Driver: %s\n"
+"Owner Module: %s\n"
+"Properties:\n"
+"%s"
+msgstr ""
+"*** Client #%u ***\n"
+"Pilote : %s\n"
+"Module propriétaire : %s\n"
+"Propriétés :\n"
+"%s"
+
+#: ../src/utils/pactl.c:333
+#, c-format
+msgid "Failed to get sink input information: %s\n"
+msgstr ""
+"Échec lors de l'obtention des informations de l'entrée de la destination : %"
+"s\n"
+
+#: ../src/utils/pactl.c:352
+#, c-format
+msgid ""
+"*** Sink Input #%u ***\n"
+"Driver: %s\n"
+"Owner Module: %s\n"
+"Client: %s\n"
+"Sink: %u\n"
+"Sample Specification: %s\n"
+"Channel Map: %s\n"
+"Volume: %s\n"
+"Buffer Latency: %0.0f usec\n"
+"Sink Latency: %0.0f usec\n"
+"Resample method: %s\n"
+"Properties:\n"
+"%s"
+msgstr ""
+"*** Entrée de la destination #%u ***\n"
+"Pilote : %s\n"
+"Module propriétaire : %s\n"
+"Client : %s\n"
+"Destination : %u\n"
+"Spécification de l'échantillon : %s\n"
+"Plan des canaux : %s\n"
+"Volume : %s\n"
+"Latence du tampon : %0.0f µs\n"
+"Latence de la destination : %0.0f µs\n"
+"Méthode de rééchantillonnage : %s\n"
+"Propriétés :\n"
+"%s"
+
+#: ../src/utils/pactl.c:385
+#, c-format
+msgid "Failed to get source output information: %s\n"
+msgstr ""
+"Échec lors de l'obtention des informations de la sortie de la source : %s\n"
+
+#: ../src/utils/pactl.c:405
+#, c-format
+msgid ""
+"*** Source Output #%u ***\n"
+"Driver: %s\n"
+"Owner Module: %s\n"
+"Client: %s\n"
+"Source: %u\n"
+"Sample Specification: %s\n"
+"Channel Map: %s\n"
+"Buffer Latency: %0.0f usec\n"
+"Source Latency: %0.0f usec\n"
+"Resample method: %s\n"
+"Properties:\n"
+"%s"
+msgstr ""
+"*** Source Output #%u ***\n"
+"Pilote : %s\n"
+"Module propriétaire : %s\n"
+"Client : %s\n"
+"Source : %u\n"
+"Spécification de l'échantillon : %s\n"
+"Plan des canaux : %s\n"
+"Latence du tampon : %0.0f µs\n"
+"Latence de la source : %0.0f µs\n"
+"Méthode de rééchantillonnage : %s\n"
+"Propriétés :\n"
+"%s"
+
+#: ../src/utils/pactl.c:436
+#, c-format
+msgid "Failed to get sample information: %s\n"
+msgstr "Échec lors de l'obtention des informations de l'échantillon : %s\n"
+
+# Lazy ?
+# load-sample-lazy = Create a new entry in the sample cache, but don't load
+# the sample immediately. The sample is loaded only when it is first used
+#: ../src/utils/pactl.c:455
+#, c-format
+msgid ""
+"*** Sample #%u ***\n"
+"Name: %s\n"
+"Volume: %s\n"
+"Sample Specification: %s\n"
+"Channel Map: %s\n"
+"Duration: %0.1fs\n"
+"Size: %s\n"
+"Lazy: %s\n"
+"Filename: %s\n"
+"Properties:\n"
+"%s"
+msgstr ""
+"*** Échantillon #%u ***\n"
+"Nom : %s\n"
+"Volume : %s\n"
+"Spécification de l'échantillon : %s\n"
+"Plan des canaux : %s\n"
+"Durée : %0.1f s\n"
+"Taille : %s\n"
+"Cache retardé : %s\n"
+"Nom de fichier : %s\n"
+"Propriétés :\n"
+"%s"
+
+#: ../src/utils/pactl.c:481
+#, c-format
+msgid "Failed to get autoload information: %s\n"
+msgstr ""
+"Échec lors de l'obtention des informations du chargement automatique : %s\n"
+
+#: ../src/utils/pactl.c:497
+#, c-format
+msgid ""
+"*** Autoload Entry #%u ***\n"
+"Name: %s\n"
+"Type: %s\n"
+"Module: %s\n"
+"Argument: %s\n"
+msgstr ""
+"*** Entrée de chargement automatique #%u ***\n"
+"Nom : %s\n"
+"Type : %s\n"
+"Module : %s\n"
+"Paramètre : %s\n"
+
+#: ../src/utils/pactl.c:504
+msgid "sink"
+msgstr "destination"
+
+#: ../src/utils/pactl.c:504
+msgid "source"
+msgstr "source"
+
+#: ../src/utils/pactl.c:511 ../src/utils/pactl.c:521
+#, c-format
+msgid "Failure: %s\n"
+msgstr "Échec : %s\n"
+
+#: ../src/utils/pactl.c:545
+#, c-format
+msgid "Failed to upload sample: %s\n"
+msgstr "Échec lors de l'envoi de l'échantillon : %s\n"
+
+#: ../src/utils/pactl.c:562
+#, c-format
+msgid "Premature end of file\n"
+msgstr "Fin prématurée du fichier\n"
+
+#: ../src/utils/pactl.c:678
+#, c-format
+msgid ""
+"%s [options] stat\n"
+"%s [options] list\n"
+"%s [options] exit\n"
+"%s [options] upload-sample FILENAME [NAME]\n"
+"%s [options] play-sample NAME [SINK]\n"
+"%s [options] remove-sample NAME\n"
+"%s [options] move-sink-input ID SINK\n"
+"%s [options] move-source-output ID SOURCE\n"
+"%s [options] load-module NAME [ARGS ...]\n"
+"%s [options] unload-module ID\n"
+"%s [options] suspend-sink [SINK] 1|0\n"
+"%s [options] suspend-source [SOURCE] 1|0\n"
+"\n"
+" -h, --help Show this help\n"
+" --version Show version\n"
+"\n"
+" -s, --server=SERVER The name of the server to connect "
+"to\n"
+" -n, --client-name=NAME How to call this client on the "
+"server\n"
+msgstr ""
+"%s [options] stat\n"
+"%s [options] list\n"
+"%s [options] exit\n"
+"%s [options] upload-sample NOMDEFICHIER [NOM]\n"
+"%s [options] play-sample NOM [DEST]\n"
+"%s [options] remove-sample NOM\n"
+"%s [options] move-sink-input ID DEST\n"
+"%s [options] move-source-output ID SOURCE\n"
+"%s [options] load-module NOM [PARAMS ...]\n"
+"%s [options] unload-module ID\n"
+"%s [options] suspend-sink [DEST] 1|0\n"
+"%s [options] suspend-source [SOURCE] 1|0\n"
+"\n"
+" -h, --help Affiche cette aide\n"
+" --version Affiche la version\n"
+"\n"
+" -s, --server=SERVEUR Le nom du serveur auquel se "
+"connecter\n"
+" -n, --client-name=NOM Définit le nom de ce client sur le "
+"serveur\n"
+
+#: ../src/utils/pactl.c:729
+#, c-format
+msgid ""
+"pactl %s\n"
+"Compiled with libpulse %s\n"
+"Linked with libpulse %s\n"
+msgstr ""
+"pactl %s\n"
+"Compilé avec libpulse %s\n"
+"Lié avec libpulse %s\n"
+
+#: ../src/utils/pactl.c:768
+#, c-format
+msgid "Please specify a sample file to load\n"
+msgstr "Veuillez indiquer un fichier d'échantillon à charger\n"
+
+#: ../src/utils/pactl.c:790
+#, c-format
+msgid "Failed to open sound file.\n"
+msgstr "Échec lors de l'ouverture du fichier audio.\n"
+
+#: ../src/utils/pactl.c:802
+#, c-format
+msgid "You have to specify a sample name to play\n"
+msgstr "Vous devez indiquer un nom d'échantillon à lire\n"
+
+#: ../src/utils/pactl.c:814
+#, c-format
+msgid "You have to specify a sample name to remove\n"
+msgstr "Vous devez indiquer un nom d'échantillon à supprimer\n"
+
+#: ../src/utils/pactl.c:822
+#, c-format
+msgid "You have to specify a sink input index and a sink\n"
+msgstr ""
+"Vous devez indiquer un index de sortie de destination et une destination\n"
+
+#: ../src/utils/pactl.c:831
+#, c-format
+msgid "You have to specify a source output index and a source\n"
+msgstr "Vous devez indiquer un index de sortie de source et une source\n"
+
+#: ../src/utils/pactl.c:845
+#, c-format
+msgid "You have to specify a module name and arguments.\n"
+msgstr "Vous devez indiquer un nom de module et des paramètres.\n"
+
+#: ../src/utils/pactl.c:865
+#, c-format
+msgid "You have to specify a module index\n"
+msgstr "Vous devez indiquer un index de module\n"
+
+#: ../src/utils/pactl.c:875
+#, c-format
+msgid ""
+"You may not specify more than one sink. You have to specify at least one "
+"boolean value.\n"
+msgstr ""
+"Vous ne pouvez pas indiquer plus d'une destination. Vous devez indiquer au "
+"moins une valeur booléenne.\n"
+
+#: ../src/utils/pactl.c:888
+#, c-format
+msgid ""
+"You may not specify more than one source. You have to specify at least one "
+"boolean value.\n"
+msgstr ""
+"Vous ne pouvez pas indiquer plus d'une source. Vous devez indiquer au moins "
+"une valeur booléenne.\n"
+
+#: ../src/utils/pactl.c:904
+#, c-format
+msgid "No valid command specified.\n"
+msgstr "Aucune commande valide indiquée.\n"
+
+#: ../src/utils/pax11publish.c:61
+#, c-format
+msgid ""
+"%s [-D display] [-S server] [-O sink] [-I source] [-c file] [-d|-e|-i|-r]\n"
+"\n"
+" -d Show current PulseAudio data attached to X11 display (default)\n"
+" -e Export local PulseAudio data to X11 display\n"
+" -i Import PulseAudio data from X11 display to local environment "
+"variables and cookie file.\n"
+" -r Remove PulseAudio data from X11 display\n"
+msgstr ""
+"%s [-D visuel] [-S serveur] [-O destination] [-I source] [-c fichier] [-d|-"
+"e|-i|-r]\n"
+"\n"
+" -d Affiche les données PulseAudio actuelles attachées au visuel X11 (par "
+"défaut)\n"
+" -e Exporte les données PulseAudio locales vers le visuel X11\n"
+" -i Importe les données PulseAudio depuis le visuel X11 vers les "
+"variables de l'environnement local et le fichier de cookie.\n"
+" -r Enlève les données PulseAudio du visuel X11\n"
+
+#: ../src/utils/pax11publish.c:94
+#, c-format
+msgid "Failed to parse command line.\n"
+msgstr "Échec lors de l'analyse de la ligne de commande.\n"
+
+#: ../src/utils/pax11publish.c:108
+#, c-format
+msgid "Server: %s\n"
+msgstr "Serveur : %s\n"
+
+#: ../src/utils/pax11publish.c:110
+#, c-format
+msgid "Source: %s\n"
+msgstr "Source : %s\n"
+
+#: ../src/utils/pax11publish.c:112
+#, c-format
+msgid "Sink: %s\n"
+msgstr "Destination : %s\n"
+
+#: ../src/utils/pax11publish.c:114
+#, c-format
+msgid "Cookie: %s\n"
+msgstr "Cookie : %s\n"
+
+#: ../src/utils/pax11publish.c:132
+#, c-format
+msgid "Failed to parse cookie data\n"
+msgstr "Échec lors de l'analyse des données du cookie\n"
+
+#: ../src/utils/pax11publish.c:137
+#, c-format
+msgid "Failed to save cookie data\n"
+msgstr "Échec lors de l'enregistrement des données du cookie\n"
+
+#: ../src/utils/pax11publish.c:152
+#, c-format
+msgid "Failed to load client configuration file.\n"
+msgstr "Échec lors du chargement du fichier de configuration du client.\n"
+
+#: ../src/utils/pax11publish.c:157
+#, c-format
+msgid "Failed to read environment configuration data.\n"
+msgstr ""
+"Échec lors de la lecture des données de configuration de l'environnement.\n"
+
+# Fully Qualified Domain Name
+#: ../src/utils/pax11publish.c:174
+#, c-format
+msgid "Failed to get FQDN.\n"
+msgstr "Échec lors de l'obtention du FQDN (« nom de domaine complet »).\n"
+
+#: ../src/utils/pax11publish.c:194
+#, c-format
+msgid "Failed to load cookie data\n"
+msgstr "Échec lors du chargement des données du cookie\n"
+
+#: ../src/utils/pax11publish.c:211
+#, c-format
+msgid "Not yet implemented.\n"
+msgstr "Pas encore implémenté.\n"
+
+#: ../src/utils/pacmd.c:64
+#, c-format
+msgid "socket(PF_UNIX, SOCK_STREAM, 0): %s"
+msgstr "socket(PF_UNIX, SOCK_STREAM, 0) : %s"
+
+#: ../src/utils/pacmd.c:81
+#, c-format
+msgid "connect(): %s"
+msgstr "connect() : %s"
+
+#: ../src/utils/pacmd.c:89
+msgid "Failed to kill PulseAudio daemon."
+msgstr "Impossible de tuer le démon PulseAudio."
+
+#: ../src/utils/pacmd.c:97
+msgid "Daemon not responding."
+msgstr "Le démon ne répond pas."
+
+#: ../src/utils/pacmd.c:112
+#, c-format
+msgid "select(): %s"
+msgstr "select() : %s"
+
+#: ../src/utils/pacmd.c:124 ../src/utils/pacmd.c:140
+#, c-format
+msgid "read(): %s"
+msgstr "read() : %s"
+
+#: ../src/utils/pacmd.c:153 ../src/utils/pacmd.c:167
+#, c-format
+msgid "write(): %s"
+msgstr "write() : %s"
+
+#: ../src/utils/paplay.c:139
+#, c-format
+msgid "Stream successfully created\n"
+msgstr "Création du flux réussie\n"
+
+#: ../src/utils/paplay.c:144
+#, c-format
+msgid "Stream errror: %s\n"
+msgstr "Erreur du flux : %s\n"
+
+#: ../src/utils/paplay.c:165
+#, c-format
+msgid "Connection established.\n"
+msgstr "Connexion établie.\n"
+
+#: ../src/utils/paplay.c:198
+#, c-format
+msgid ""
+"%s [options] [FILE]\n"
+"\n"
+" -h, --help Show this help\n"
+" --version Show version\n"
+"\n"
+" -v, --verbose Enable verbose operation\n"
+"\n"
+" -s, --server=SERVER The name of the server to connect "
+"to\n"
+" -d, --device=DEVICE The name of the sink to connect to\n"
+" -n, --client-name=NAME How to call this client on the "
+"server\n"
+" --stream-name=NAME How to call this stream on the "
+"server\n"
+" --volume=VOLUME Specify the initial (linear) volume "
+"in range 0...65536\n"
+" --channel-map=CHANNELMAP Set the channel map to the use\n"
+msgstr ""
+"%s [options] [FICHIER]\n"
+"\n"
+" -h, --help Affiche cette aide\n"
+" --version Affiche la version\n"
+"\n"
+" -v, --verbose Active le mode verbeux\n"
+"\n"
+" -s, --server=SERVEUR Le nom du serveur auquel se "
+"connecter\n"
+" -d, --device=PÉRIPHÉRIQUE Le nom de la destination à laquelle "
+"se connecter\n"
+" -n, --client-name=NOM Définit le nom de ce client sur le "
+"serveur\n"
+" --stream-name=NOM Définit le nom de ce flux sur le "
+"serveur\n"
+" --volume=VOLUME Définit le volume initial (linéaire) "
+"entre 0 et 65536\n"
+" --channel-map=PLANDESCANAUX Définit le plan des canaux à "
+"utiliser\n"
+
+#: ../src/utils/paplay.c:255
+#, c-format
+msgid ""
+"paplay %s\n"
+"Compiled with libpulse %s\n"
+"Linked with libpulse %s\n"
+msgstr ""
+"paplay %s\n"
+"Compilé avec libpulse %s\n"
+"Lié avec libpulse %s\n"
+
+#: ../src/utils/paplay.c:292
+#, c-format
+msgid "Invalid channel map\n"
+msgstr "Plan des canaux invalide\n"
+
+#: ../src/utils/paplay.c:314
+#, c-format
+msgid "Failed to open file '%s'\n"
+msgstr "Échec lors de l'ouverture du fichier « %s »\n"
+
+#: ../src/utils/paplay.c:350
+#, c-format
+msgid "Channel map doesn't match file.\n"
+msgstr "Le plan des canaux ne correspond pas au fichier.\n"
+
+#: ../src/utils/paplay.c:376
+#, c-format
+msgid "Using sample spec '%s'\n"
+msgstr "Utilisation de la spécification de l'échantillon « %s »\n"
diff --git a/po/sv.po b/po/sv.po
new file mode 100644
index 00000000..11f6e13c
--- /dev/null
+++ b/po/sv.po
@@ -0,0 +1,1799 @@
+# Swedish translation for pulseaudio.
+# Copyright (C) 2008 Free Software Foundation, Inc.
+# This file is distributed under the same license as the pulseaudio package.
+# Daniel Nylander <po@danielnylander.se>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: pulseaudio\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-09-04 19:30+0000\n"
+"PO-Revision-Date: 2008-09-05 18:24+0100\n"
+"Last-Translator: Daniel Nylander <po@danielnylander.se>\n"
+"Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../src/daemon/ltdl-bind-now.c:177
+#: ../src/daemon/ltdl-bind-now.c:197
+msgid "Failed to add bind-now-loader."
+msgstr ""
+
+#: ../src/daemon/ltdl-bind-now.c:184
+msgid "Failed to find original dlopen loader."
+msgstr ""
+
+#: ../src/daemon/polkit.c:55
+#, c-format
+msgid "Cannot connect to system bus: %s"
+msgstr ""
+
+#: ../src/daemon/polkit.c:65
+#, c-format
+msgid "Cannot get caller from PID: %s"
+msgstr ""
+
+#: ../src/daemon/polkit.c:77
+msgid "Cannot set UID on caller object."
+msgstr ""
+
+#: ../src/daemon/polkit.c:82
+msgid "Failed to get CK session."
+msgstr ""
+
+#: ../src/daemon/polkit.c:90
+msgid "Cannot set UID on session object."
+msgstr ""
+
+#: ../src/daemon/polkit.c:95
+msgid "Cannot allocate PolKitAction."
+msgstr ""
+
+#: ../src/daemon/polkit.c:100
+msgid "Cannot set action_id"
+msgstr ""
+
+#: ../src/daemon/polkit.c:105
+msgid "Cannot allocate PolKitContext."
+msgstr ""
+
+#: ../src/daemon/polkit.c:110
+#, c-format
+msgid "Cannot initialize PolKitContext: %s"
+msgstr ""
+
+#: ../src/daemon/polkit.c:119
+#, c-format
+msgid "Could not determine whether caller is authorized: %s"
+msgstr ""
+
+#: ../src/daemon/polkit.c:139
+#, c-format
+msgid "Cannot obtain auth: %s"
+msgstr ""
+
+#: ../src/daemon/polkit.c:148
+#, c-format
+msgid "PolicyKit responded with '%s'"
+msgstr "PolicyKit svarade med \"%s\""
+
+#: ../src/daemon/main.c:134
+#, c-format
+msgid "Got signal %s."
+msgstr "Fick signal %s."
+
+#: ../src/daemon/main.c:161
+msgid "Exiting."
+msgstr "Avslutar."
+
+#: ../src/daemon/main.c:179
+#, c-format
+msgid "Failed to find user '%s'."
+msgstr "Misslyckades med att hitta användaren \"%s\"."
+
+#: ../src/daemon/main.c:184
+#, c-format
+msgid "Failed to find group '%s'."
+msgstr "Misslyckades med att hitta gruppen \"%s\"."
+
+#: ../src/daemon/main.c:188
+#, c-format
+msgid "Found user '%s' (UID %lu) and group '%s' (GID %lu)."
+msgstr ""
+
+#: ../src/daemon/main.c:193
+#, c-format
+msgid "GID of user '%s' and of group '%s' don't match."
+msgstr ""
+
+#: ../src/daemon/main.c:198
+#, c-format
+msgid "Home directory of user '%s' is not '%s', ignoring."
+msgstr "Hemkatalogen för användaren \"%s\" är inte \"%s\", ignorerar."
+
+#: ../src/daemon/main.c:201
+#: ../src/daemon/main.c:206
+#, c-format
+msgid "Failed to create '%s': %s"
+msgstr "Misslyckades med att skapa \"%s\": %s"
+
+#: ../src/daemon/main.c:213
+#, c-format
+msgid "Failed to change group list: %s"
+msgstr ""
+
+#: ../src/daemon/main.c:229
+#, c-format
+msgid "Failed to change GID: %s"
+msgstr ""
+
+#: ../src/daemon/main.c:245
+#, c-format
+msgid "Failed to change UID: %s"
+msgstr ""
+
+#: ../src/daemon/main.c:259
+msgid "Successfully dropped root privileges."
+msgstr ""
+
+#: ../src/daemon/main.c:267
+msgid "System wide mode unsupported on this platform."
+msgstr ""
+
+#: ../src/daemon/main.c:285
+#, c-format
+msgid "setrlimit(%s, (%u, %u)) failed: %s"
+msgstr "setrlimit(%s, (%u, %u)) misslyckades: %s"
+
+#: ../src/daemon/main.c:425
+msgid "Failed to parse command line."
+msgstr ""
+
+#: ../src/daemon/main.c:441
+#, c-format
+msgid "We're in the group '%s', allowing high-priority scheduling."
+msgstr ""
+
+#: ../src/daemon/main.c:448
+#, c-format
+msgid "We're in the group '%s', allowing real-time scheduling."
+msgstr ""
+
+#: ../src/daemon/main.c:456
+msgid "PolicyKit grants us acquire-high-priority privilege."
+msgstr ""
+
+#: ../src/daemon/main.c:459
+msgid "PolicyKit refuses acquire-high-priority privilege."
+msgstr ""
+
+#: ../src/daemon/main.c:464
+msgid "PolicyKit grants us acquire-real-time privilege."
+msgstr ""
+
+#: ../src/daemon/main.c:467
+msgid "PolicyKit refuses acquire-real-time privilege."
+msgstr ""
+
+#: ../src/daemon/main.c:479
+msgid ""
+"Called SUID root and real-time/high-priority scheduling was requested in the configuration. However, we lack the necessary priviliges:\n"
+"We are not in group '"
+msgstr ""
+
+#: ../src/daemon/main.c:480
+msgid ""
+"' and PolicyKit refuse to grant us priviliges. Dropping SUID again.\n"
+"For enabling real-time scheduling please acquire the appropriate PolicyKit priviliges, or become a member of '"
+msgstr ""
+
+#: ../src/daemon/main.c:481
+msgid "', or increase the RLIMIT_NICE/RLIMIT_RTPRIO resource limits for this user."
+msgstr ""
+
+#: ../src/daemon/main.c:497
+msgid "High-priority scheduling enabled in configuration but not allowed by policy."
+msgstr ""
+
+#: ../src/daemon/main.c:522
+msgid "Successfully increased RLIMIT_RTPRIO"
+msgstr ""
+
+#: ../src/daemon/main.c:525
+#, c-format
+msgid "RLIMIT_RTPRIO failed: %s"
+msgstr "RLIMIT_RTPRIO misslyckades: %s"
+
+#: ../src/daemon/main.c:532
+msgid "Giving up CAP_NICE"
+msgstr ""
+
+#: ../src/daemon/main.c:539
+msgid "Real-time scheduling enabled in configuration but not allowed by policy."
+msgstr ""
+
+#: ../src/daemon/main.c:597
+msgid "Daemon not running"
+msgstr ""
+
+#: ../src/daemon/main.c:599
+#, c-format
+msgid "Daemon running as PID %u"
+msgstr ""
+
+#: ../src/daemon/main.c:609
+#, c-format
+msgid "Failed to kill daemon: %s"
+msgstr ""
+
+#: ../src/daemon/main.c:627
+msgid "This program is not intended to be run as root (unless --system is specified)."
+msgstr "Detta program är inte tänkt att köras som root (såvida inte --system har angivits)."
+
+#: ../src/daemon/main.c:629
+msgid "Root priviliges required."
+msgstr "Root-behörighet krävs."
+
+#: ../src/daemon/main.c:634
+msgid "--start not supported for system instances."
+msgstr "--start stöds inte för systeminstanser."
+
+#: ../src/daemon/main.c:639
+msgid "Running in system mode, but --disallow-exit not set!"
+msgstr ""
+
+#: ../src/daemon/main.c:642
+msgid "Running in system mode, but --disallow-module-loading not set!"
+msgstr ""
+
+#: ../src/daemon/main.c:645
+msgid "Running in system mode, forcibly disabling SHM mode!"
+msgstr ""
+
+#: ../src/daemon/main.c:650
+msgid "Running in system mode, forcibly disabling exit idle time!"
+msgstr ""
+
+#: ../src/daemon/main.c:677
+msgid "Failed to acquire stdio."
+msgstr ""
+
+#: ../src/daemon/main.c:683
+#, c-format
+msgid "pipe failed: %s"
+msgstr "pipe misslyckades: %s"
+
+#: ../src/daemon/main.c:688
+#, c-format
+msgid "fork() failed: %s"
+msgstr "fork() misslyckades: %s"
+
+#: ../src/daemon/main.c:702
+#, c-format
+msgid "read() failed: %s"
+msgstr "read() misslyckades: %s"
+
+#: ../src/daemon/main.c:708
+msgid "Daemon startup failed."
+msgstr ""
+
+#: ../src/daemon/main.c:710
+msgid "Daemon startup successful."
+msgstr ""
+
+#: ../src/daemon/main.c:780
+#, c-format
+msgid "This is PulseAudio %s"
+msgstr "Detta är PulseAudio %s"
+
+#: ../src/daemon/main.c:781
+#, c-format
+msgid "Compilation CFLAGS: %s"
+msgstr ""
+
+#: ../src/daemon/main.c:784
+msgid "Compiled with Valgrind support: yes"
+msgstr ""
+
+#: ../src/daemon/main.c:786
+msgid "Compiled with Valgrind support: no"
+msgstr ""
+
+#: ../src/daemon/main.c:790
+msgid "Optimized build: yes"
+msgstr ""
+
+#: ../src/daemon/main.c:792
+msgid "Optimized build: no"
+msgstr ""
+
+#: ../src/daemon/main.c:795
+#, c-format
+msgid "Page size is %lu bytes"
+msgstr ""
+
+#: ../src/daemon/main.c:798
+msgid "Failed to get machine ID"
+msgstr ""
+
+#: ../src/daemon/main.c:801
+#, c-format
+msgid "Machine ID is %s."
+msgstr ""
+
+#: ../src/daemon/main.c:806
+#, c-format
+msgid "Using runtime directory %s."
+msgstr ""
+
+#: ../src/daemon/main.c:811
+#, c-format
+msgid "Using state directory %s."
+msgstr ""
+
+#: ../src/daemon/main.c:814
+#, c-format
+msgid "Running in system mode: %s"
+msgstr ""
+
+#: ../src/daemon/main.c:829
+msgid "pa_pid_file_create() failed."
+msgstr "pa_pid_file_create() misslyckades."
+
+#: ../src/daemon/main.c:841
+msgid "Fresh high-resolution timers available! Bon appetit!"
+msgstr ""
+
+#: ../src/daemon/main.c:843
+msgid "Dude, your kernel stinks! The chef's recommendation today is Linux with high-resolution timers enabled!"
+msgstr ""
+
+#: ../src/daemon/main.c:853
+msgid "pa_core_new() failed."
+msgstr "pa_core_new() misslyckades."
+
+#: ../src/daemon/main.c:913
+msgid "Failed to initialize daemon."
+msgstr ""
+
+#: ../src/daemon/main.c:918
+msgid "Daemon startup without any loaded modules, refusing to work."
+msgstr ""
+
+#: ../src/daemon/main.c:923
+#, c-format
+msgid "Default sink name (%s) does not exist in name register."
+msgstr ""
+
+#: ../src/daemon/main.c:936
+msgid "Daemon startup complete."
+msgstr ""
+
+#: ../src/daemon/main.c:942
+msgid "Daemon shutdown initiated."
+msgstr ""
+
+#: ../src/daemon/main.c:963
+msgid "Daemon terminated."
+msgstr ""
+
+#: ../src/daemon/cmdline.c:117
+#, c-format
+msgid ""
+"%s [options]\n"
+"\n"
+"COMMANDS:\n"
+" -h, --help Show this help\n"
+" --version Show version\n"
+" --dump-conf Dump default configuration\n"
+" --dump-modules Dump list of available modules\n"
+" --dump-resample-methods Dump available resample methods\n"
+" --cleanup-shm Cleanup stale shared memory segments\n"
+" --start Start the daemon if it is not running\n"
+" -k --kill Kill a running daemon\n"
+" --check Check for a running daemon\n"
+"\n"
+"OPTIONS:\n"
+" --system[=BOOL] Run as system-wide instance\n"
+" -D, --daemonize[=BOOL] Daemonize after startup\n"
+" --fail[=BOOL] Quit when startup fails\n"
+" --high-priority[=BOOL] Try to set high nice level\n"
+" (only available as root, when SUID or\n"
+" with elevated RLIMIT_NICE)\n"
+" --realtime[=BOOL] Try to enable realtime scheduling\n"
+" (only available as root, when SUID or\n"
+" with elevated RLIMIT_RTPRIO)\n"
+" --disallow-module-loading[=BOOL] Disallow module user requested module\n"
+" loading/unloading after startup\n"
+" --disallow-exit[=BOOL] Disallow user requested exit\n"
+" --exit-idle-time=SECS Terminate the daemon when idle and this\n"
+" time passed\n"
+" --module-idle-time=SECS Unload autoloaded modules when idle and\n"
+" this time passed\n"
+" --scache-idle-time=SECS Unload autoloaded samples when idle and\n"
+" this time passed\n"
+" --log-level[=LEVEL] Increase or set verbosity level\n"
+" -v Increase the verbosity level\n"
+" --log-target={auto,syslog,stderr} Specify the log target\n"
+" -p, --dl-search-path=PATH Set the search path for dynamic shared\n"
+" objects (plugins)\n"
+" --resample-method=METHOD Use the specified resampling method\n"
+" (See --dump-resample-methods for\n"
+" possible values)\n"
+" --use-pid-file[=BOOL] Create a PID file\n"
+" --no-cpu-limit[=BOOL] Do not install CPU load limiter on\n"
+" platforms that support it.\n"
+" --disable-shm[=BOOL] Disable shared memory support.\n"
+"\n"
+"STARTUP SCRIPT:\n"
+" -L, --load=\"MODULE ARGUMENTS\" Load the specified plugin module with\n"
+" the specified argument\n"
+" -F, --file=FILENAME Run the specified script\n"
+" -C Open a command line on the running TTY\n"
+" after startup\n"
+"\n"
+" -n Don't load default script file\n"
+msgstr ""
+
+#: ../src/daemon/cmdline.c:245
+msgid "--daemonize expects boolean argument"
+msgstr "--daemonize förväntar sig ett booleskt argument"
+
+#: ../src/daemon/cmdline.c:252
+msgid "--fail expects boolean argument"
+msgstr "--fail förväntar sig ett booleskt argument"
+
+#: ../src/daemon/cmdline.c:262
+msgid "--log-level expects log level argument (either numeric in range 0..4 or one of debug, info, notice, warn, error)."
+msgstr ""
+
+#: ../src/daemon/cmdline.c:274
+msgid "--high-priority expects boolean argument"
+msgstr "--high-priority förväntar sig ett booleskt argument"
+
+#: ../src/daemon/cmdline.c:281
+msgid "--realtime expects boolean argument"
+msgstr "--realtime förväntar sig ett booleskt argument"
+
+#: ../src/daemon/cmdline.c:288
+msgid "--disallow-module-loading expects boolean argument"
+msgstr "--disallow-module-loading förväntar sig ett booleskt argument"
+
+#: ../src/daemon/cmdline.c:295
+msgid "--disallow-exit boolean argument"
+msgstr "--disallow-exit booleskt argument"
+
+#: ../src/daemon/cmdline.c:302
+msgid "--use-pid-file expects boolean argument"
+msgstr "--use-pid-file förväntar sig ett booleskt argument"
+
+#: ../src/daemon/cmdline.c:319
+msgid "Invalid log target: use either 'syslog', 'stderr' or 'auto'."
+msgstr ""
+
+#: ../src/daemon/cmdline.c:338
+#, c-format
+msgid "Invalid resample method '%s'."
+msgstr ""
+
+#: ../src/daemon/cmdline.c:345
+msgid "--system expects boolean argument"
+msgstr "--system förväntar sig ett booleskt argument"
+
+#: ../src/daemon/cmdline.c:352
+msgid "--no-cpu-limit expects boolean argument"
+msgstr "--no-cpu-limit förväntar sig ett booleskt argument"
+
+#: ../src/daemon/cmdline.c:359
+msgid "--disable-shm expects boolean argument"
+msgstr "--disable-shm förväntar sig ett booleskt argument"
+
+#: ../src/daemon/dumpmodules.c:60
+#, c-format
+msgid "Name: %s\n"
+msgstr "Namn: %s\n"
+
+#: ../src/daemon/dumpmodules.c:63
+#, c-format
+msgid "No module information available\n"
+msgstr ""
+
+#: ../src/daemon/dumpmodules.c:66
+#, c-format
+msgid "Version: %s\n"
+msgstr "Version: %s\n"
+
+#: ../src/daemon/dumpmodules.c:68
+#, c-format
+msgid "Description: %s\n"
+msgstr "Beskrivning: %s\n"
+
+#: ../src/daemon/dumpmodules.c:70
+#, c-format
+msgid "Author: %s\n"
+msgstr "Upphovsman: %s\n"
+
+#: ../src/daemon/dumpmodules.c:72
+#, c-format
+msgid "Usage: %s\n"
+msgstr "Användning: %s\n"
+
+#: ../src/daemon/dumpmodules.c:73
+#, c-format
+msgid "Load Once: %s\n"
+msgstr ""
+
+#: ../src/daemon/dumpmodules.c:77
+#, c-format
+msgid "Path: %s\n"
+msgstr "Sökväg: %s\n"
+
+#: ../src/daemon/daemon-conf.c:203
+#, c-format
+msgid "[%s:%u] Invalid log target '%s'."
+msgstr ""
+
+#: ../src/daemon/daemon-conf.c:219
+#, c-format
+msgid "[%s:%u] Invalid log level '%s'."
+msgstr ""
+
+#: ../src/daemon/daemon-conf.c:235
+#, c-format
+msgid "[%s:%u] Invalid resample method '%s'."
+msgstr ""
+
+#: ../src/daemon/daemon-conf.c:258
+#, c-format
+msgid "[%s:%u] Invalid rlimit '%s'."
+msgstr ""
+
+#: ../src/daemon/daemon-conf.c:265
+#, c-format
+msgid "[%s:%u] rlimit not supported on this platform."
+msgstr ""
+
+#: ../src/daemon/daemon-conf.c:281
+#, c-format
+msgid "[%s:%u] Invalid sample format '%s'."
+msgstr ""
+
+#: ../src/daemon/daemon-conf.c:299
+#, c-format
+msgid "[%s:%u] Invalid sample rate '%s'."
+msgstr ""
+
+#: ../src/daemon/daemon-conf.c:317
+#, c-format
+msgid "[%s:%u] Invalid sample channels '%s'."
+msgstr ""
+
+#: ../src/daemon/daemon-conf.c:335
+#, c-format
+msgid "[%s:%u] Invalid number of fragments '%s'."
+msgstr ""
+
+#: ../src/daemon/daemon-conf.c:353
+#, c-format
+msgid "[%s:%u] Invalid fragment size '%s'."
+msgstr ""
+
+#: ../src/daemon/daemon-conf.c:371
+#, c-format
+msgid "[%s:%u] Invalid nice level '%s'."
+msgstr ""
+
+#: ../src/daemon/daemon-conf.c:564
+#, c-format
+msgid "Failed to open configuration file: %s"
+msgstr "Misslyckades med att öppna konfigurationsfil: %s"
+
+#: ../src/daemon/daemon-conf.c:638
+#, c-format
+msgid "### Read from configuration file: %s ###\n"
+msgstr ""
+
+#: ../src/daemon/caps.c:62
+msgid "Dropping root priviliges."
+msgstr "Släpper root-behörighet."
+
+#: ../src/daemon/caps.c:102
+msgid "Limited capabilities successfully to CAP_SYS_NICE."
+msgstr ""
+
+#: ../src/pulse/channelmap.c:102
+msgid "Mono"
+msgstr "Mono"
+
+#: ../src/pulse/channelmap.c:104
+msgid "Front Center"
+msgstr "Center fram"
+
+#: ../src/pulse/channelmap.c:105
+msgid "Front Left"
+msgstr "Vänster fram"
+
+#: ../src/pulse/channelmap.c:106
+msgid "Front Right"
+msgstr "Höger fram"
+
+#: ../src/pulse/channelmap.c:108
+msgid "Rear Center"
+msgstr "Center bak"
+
+#: ../src/pulse/channelmap.c:109
+msgid "Rear Left"
+msgstr "Vänster bak"
+
+#: ../src/pulse/channelmap.c:110
+msgid "Rear Right"
+msgstr "Höger bak"
+
+#: ../src/pulse/channelmap.c:112
+msgid "Low Frequency Emmiter"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:114
+msgid "Front Left-of-center"
+msgstr "Vänster-om-center fram"
+
+#: ../src/pulse/channelmap.c:115
+msgid "Front Right-of-center"
+msgstr "Höger-om-center fram"
+
+#: ../src/pulse/channelmap.c:117
+msgid "Side Left"
+msgstr "Vänster sida"
+
+#: ../src/pulse/channelmap.c:118
+msgid "Side Right"
+msgstr "Höger sida"
+
+#: ../src/pulse/channelmap.c:120
+msgid "Auxiliary 0"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:121
+msgid "Auxiliary 1"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:122
+msgid "Auxiliary 2"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:123
+msgid "Auxiliary 3"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:124
+msgid "Auxiliary 4"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:125
+msgid "Auxiliary 5"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:126
+msgid "Auxiliary 6"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:127
+msgid "Auxiliary 7"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:128
+msgid "Auxiliary 8"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:129
+msgid "Auxiliary 9"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:130
+msgid "Auxiliary 10"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:131
+msgid "Auxiliary 11"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:132
+msgid "Auxiliary 12"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:133
+msgid "Auxiliary 13"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:134
+msgid "Auxiliary 14"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:135
+msgid "Auxiliary 15"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:136
+msgid "Auxiliary 16"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:137
+msgid "Auxiliary 17"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:138
+msgid "Auxiliary 18"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:139
+msgid "Auxiliary 19"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:140
+msgid "Auxiliary 20"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:141
+msgid "Auxiliary 21"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:142
+msgid "Auxiliary 22"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:143
+msgid "Auxiliary 23"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:144
+msgid "Auxiliary 24"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:145
+msgid "Auxiliary 25"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:146
+msgid "Auxiliary 26"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:147
+msgid "Auxiliary 27"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:148
+msgid "Auxiliary 28"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:149
+msgid "Auxiliary 29"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:150
+msgid "Auxiliary 30"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:151
+msgid "Auxiliary 31"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:153
+msgid "Top Center"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:155
+msgid "Top Front Center"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:156
+msgid "Top Front Left"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:157
+msgid "Top Front Right"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:159
+msgid "Top Rear Center"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:160
+msgid "Top Rear Left"
+msgstr ""
+
+#: ../src/pulse/channelmap.c:161
+msgid "Top Rear Right"
+msgstr ""
+
+#: ../src/pulse/error.c:43
+msgid "OK"
+msgstr "OK"
+
+#: ../src/pulse/error.c:44
+msgid "Access denied"
+msgstr "Åtkomst nekad"
+
+#: ../src/pulse/error.c:45
+msgid "Unknown command"
+msgstr "Okänt kommando"
+
+#: ../src/pulse/error.c:46
+msgid "Invalid argument"
+msgstr "Ogiltigt argument"
+
+#: ../src/pulse/error.c:47
+msgid "Entity exists"
+msgstr "Entiteten finns"
+
+#: ../src/pulse/error.c:48
+msgid "No such entity"
+msgstr "Ingen sådan entitet"
+
+#: ../src/pulse/error.c:49
+msgid "Connection refused"
+msgstr "Anslutning nekades"
+
+#: ../src/pulse/error.c:50
+msgid "Protocol error"
+msgstr "Protokollfel"
+
+#: ../src/pulse/error.c:51
+msgid "Timeout"
+msgstr "Tidsgräns nåddes"
+
+#: ../src/pulse/error.c:52
+msgid "No authorization key"
+msgstr ""
+
+#: ../src/pulse/error.c:53
+msgid "Internal error"
+msgstr "Internt fel"
+
+#: ../src/pulse/error.c:54
+msgid "Connection terminated"
+msgstr "Anslutningen terminerad"
+
+#: ../src/pulse/error.c:55
+msgid "Entity killed"
+msgstr ""
+
+#: ../src/pulse/error.c:56
+msgid "Invalid server"
+msgstr "Ogiltig server"
+
+#: ../src/pulse/error.c:57
+msgid "Module initalization failed"
+msgstr ""
+
+#: ../src/pulse/error.c:58
+msgid "Bad state"
+msgstr "Felaktigt tillstånd"
+
+#: ../src/pulse/error.c:59
+msgid "No data"
+msgstr "Inget data"
+
+#: ../src/pulse/error.c:60
+msgid "Incompatible protocol version"
+msgstr ""
+
+#: ../src/pulse/error.c:61
+msgid "Too large"
+msgstr "För stor"
+
+#: ../src/pulse/error.c:62
+msgid "Not supported"
+msgstr "Stöds inte"
+
+#: ../src/pulse/error.c:63
+msgid "Unknown error code"
+msgstr "Okänd felkod"
+
+#: ../src/pulse/error.c:64
+msgid "No such extension"
+msgstr ""
+
+#: ../src/pulse/sample.c:134
+msgid "Invalid"
+msgstr "Ogiltig"
+
+#: ../src/pulse/client-conf-x11.c:55
+#: ../src/utils/pax11publish.c:100
+msgid "XOpenDisplay() failed"
+msgstr "XOpenDisplay() misslyckades"
+
+#: ../src/pulse/client-conf-x11.c:78
+msgid "Failed to parse cookie data"
+msgstr ""
+
+#: ../src/pulse/client-conf.c:117
+#, c-format
+msgid "Failed to open configuration file '%s': %s"
+msgstr "Misslyckades med att öppna konfigurationsfilen \"%s\": %s"
+
+#: ../src/pulse/context.c:542
+msgid "No cookie loaded. Attempting to connect without."
+msgstr ""
+
+#: ../src/pulse/context.c:596
+#, c-format
+msgid "socketpair(): %s"
+msgstr "socketpair(): %s"
+
+#: ../src/pulse/context.c:610
+#, c-format
+msgid "fork(): %s"
+msgstr "fork(): %s"
+
+#: ../src/pulse/context.c:673
+#, c-format
+msgid "waitpid(): %s"
+msgstr "waitpid(): %s"
+
+#: ../src/pulse/context.c:1354
+#, c-format
+msgid "Received message for unknown extension '%s'"
+msgstr ""
+
+#: ../src/utils/pacat.c:93
+#, c-format
+msgid "pa_stream_write() failed: %s\n"
+msgstr "pa_stream_write() misslyckades: %s\n"
+
+#: ../src/utils/pacat.c:132
+#, c-format
+msgid "pa_stream_peek() failed: %s\n"
+msgstr "pa_stream_peek() misslyckades: %s\n"
+
+#: ../src/utils/pacat.c:141
+#, c-format
+msgid "Buffer overrun, dropping incoming data\n"
+msgstr ""
+
+#: ../src/utils/pacat.c:143
+#, c-format
+msgid "pa_stream_drop() failed: %s\n"
+msgstr "pa_stream_drop() misslyckades: %s\n"
+
+#: ../src/utils/pacat.c:169
+#, c-format
+msgid "Stream successfully created.\n"
+msgstr ""
+
+#: ../src/utils/pacat.c:172
+#, c-format
+msgid "pa_stream_get_buffer_attr() failed: %s\n"
+msgstr "pa_stream_get_buffer_attr() misslyckades: %s\n"
+
+#: ../src/utils/pacat.c:176
+#, c-format
+msgid "Buffer metrics: maxlength=%u, tlength=%u, prebuf=%u, minreq=%u\n"
+msgstr ""
+
+#: ../src/utils/pacat.c:179
+#, c-format
+msgid "Buffer metrics: maxlength=%u, fragsize=%u\n"
+msgstr ""
+
+#: ../src/utils/pacat.c:183
+#, c-format
+msgid "Using sample spec '%s', channel map '%s'.\n"
+msgstr ""
+
+#: ../src/utils/pacat.c:187
+#, c-format
+msgid "Connected to device %s (%u, %ssuspended).\n"
+msgstr ""
+
+#: ../src/utils/pacat.c:197
+#, c-format
+msgid "Stream error: %s\n"
+msgstr "Strömfel: %s\n"
+
+#: ../src/utils/pacat.c:207
+#, c-format
+msgid "Stream device suspended.%s \n"
+msgstr ""
+
+#: ../src/utils/pacat.c:209
+#, c-format
+msgid "Stream device resumed.%s \n"
+msgstr ""
+
+#: ../src/utils/pacat.c:217
+#, c-format
+msgid "Stream underrun.%s \n"
+msgstr ""
+
+#: ../src/utils/pacat.c:224
+#, c-format
+msgid "Stream overrun.%s \n"
+msgstr ""
+
+#: ../src/utils/pacat.c:231
+#, c-format
+msgid "Stream started.%s \n"
+msgstr ""
+
+#: ../src/utils/pacat.c:238
+#, c-format
+msgid "Stream moved to device %s (%u, %ssuspended).%s \n"
+msgstr ""
+
+#: ../src/utils/pacat.c:238
+msgid "not "
+msgstr "inte "
+
+#: ../src/utils/pacat.c:259
+#, c-format
+msgid "Connection established.%s \n"
+msgstr ""
+
+#: ../src/utils/pacat.c:262
+#, c-format
+msgid "pa_stream_new() failed: %s\n"
+msgstr "pa_stream_new() misslyckades: %s\n"
+
+#: ../src/utils/pacat.c:287
+#, c-format
+msgid "pa_stream_connect_playback() failed: %s\n"
+msgstr "pa_stream_connect_playback() misslyckades: %s\n"
+
+#: ../src/utils/pacat.c:293
+#, c-format
+msgid "pa_stream_connect_record() failed: %s\n"
+msgstr "pa_stream_connect_record() misslyckades: %s\n"
+
+#: ../src/utils/pacat.c:307
+#: ../src/utils/pasuspender.c:159
+#: ../src/utils/pactl.c:666
+#: ../src/utils/paplay.c:183
+#, c-format
+msgid "Connection failure: %s\n"
+msgstr "Anslutningsfel: %s\n"
+
+#: ../src/utils/pacat.c:328
+#: ../src/utils/paplay.c:75
+#, c-format
+msgid "Failed to drain stream: %s\n"
+msgstr ""
+
+#: ../src/utils/pacat.c:333
+#: ../src/utils/paplay.c:80
+#, c-format
+msgid "Playback stream drained.\n"
+msgstr ""
+
+#: ../src/utils/pacat.c:343
+#: ../src/utils/paplay.c:92
+#, c-format
+msgid "Draining connection to server.\n"
+msgstr ""
+
+#: ../src/utils/pacat.c:369
+#, c-format
+msgid "Got EOF.\n"
+msgstr "Fick filslut.\n"
+
+#: ../src/utils/pacat.c:375
+#, c-format
+msgid "pa_stream_drain(): %s\n"
+msgstr "pa_stream_drain(): %s\n"
+
+#: ../src/utils/pacat.c:385
+#, c-format
+msgid "read() failed: %s\n"
+msgstr "read() misslyckades: %s\n"
+
+#: ../src/utils/pacat.c:417
+#, c-format
+msgid "write() failed: %s\n"
+msgstr "write() misslyckades: %s\n"
+
+#: ../src/utils/pacat.c:438
+#, c-format
+msgid "Got signal, exiting.\n"
+msgstr ""
+
+#: ../src/utils/pacat.c:452
+#, c-format
+msgid "Failed to get latency: %s\n"
+msgstr ""
+
+#: ../src/utils/pacat.c:457
+#, c-format
+msgid "Time: %0.3f sec; Latency: %0.0f usec. \r"
+msgstr "Tid: %0.3f sec; Latens: %0.0f ms \r"
+
+#: ../src/utils/pacat.c:477
+#, c-format
+msgid "pa_stream_update_timing_info() failed: %s\n"
+msgstr "pa_stream_update_timing_info() misslyckades: %s\n"
+
+#: ../src/utils/pacat.c:490
+#, c-format
+msgid ""
+"%s [options]\n"
+"\n"
+" -h, --help Show this help\n"
+" --version Show version\n"
+"\n"
+" -r, --record Create a connection for recording\n"
+" -p, --playback Create a connection for playback\n"
+"\n"
+" -v, --verbose Enable verbose operations\n"
+"\n"
+" -s, --server=SERVER The name of the server to connect to\n"
+" -d, --device=DEVICE The name of the sink/source to connect to\n"
+" -n, --client-name=NAME How to call this client on the server\n"
+" --stream-name=NAME How to call this stream on the server\n"
+" --volume=VOLUME Specify the initial (linear) volume in range 0...65536\n"
+" --rate=SAMPLERATE The sample rate in Hz (defaults to 44100)\n"
+" --format=SAMPLEFORMAT The sample type, one of s16le, s16be, u8, float32le,\n"
+" float32be, ulaw, alaw (defaults to s16ne)\n"
+" --channels=CHANNELS The number of channels, 1 for mono, 2 for stereo\n"
+" (defaults to 2)\n"
+" --channel-map=CHANNELMAP Channel map to use instead of the default\n"
+" --fix-format Take the sample format from the sink the stream is\n"
+" being connected to.\n"
+" --fix-rate Take the sampling rate from the sink the stream is\n"
+" being connected to.\n"
+" --fix-channels Take the number of channels and the channel map\n"
+" from the sink the stream is being connected to.\n"
+" --no-remix Don't upmix or downmix channels.\n"
+" --no-remap Map channels by index instead of name.\n"
+" --latency=BYTES Request the specified latency in bytes.\n"
+" --process-time=BYTES Request the specified process time per request in bytes.\n"
+msgstr ""
+
+#: ../src/utils/pacat.c:591
+#, c-format
+msgid ""
+"pacat %s\n"
+"Compiled with libpulse %s\n"
+"Linked with libpulse %s\n"
+msgstr ""
+
+#: ../src/utils/pacat.c:647
+#, c-format
+msgid "Invalid channel map '%s'\n"
+msgstr ""
+
+#: ../src/utils/pacat.c:676
+#, c-format
+msgid "Invalid latency specification '%s'\n"
+msgstr ""
+
+#: ../src/utils/pacat.c:683
+#, c-format
+msgid "Invalid process time specification '%s'\n"
+msgstr ""
+
+#: ../src/utils/pacat.c:694
+#, c-format
+msgid "Invalid sample specification\n"
+msgstr ""
+
+#: ../src/utils/pacat.c:699
+#, c-format
+msgid "Channel map doesn't match sample specification\n"
+msgstr ""
+
+#: ../src/utils/pacat.c:706
+#, c-format
+msgid "Opening a %s stream with sample specification '%s'.\n"
+msgstr ""
+
+#: ../src/utils/pacat.c:706
+msgid "recording"
+msgstr ""
+
+#: ../src/utils/pacat.c:706
+msgid "playback"
+msgstr ""
+
+#: ../src/utils/pacat.c:714
+#, c-format
+msgid "open(): %s\n"
+msgstr "open(): %s\n"
+
+#: ../src/utils/pacat.c:719
+#, c-format
+msgid "dup2(): %s\n"
+msgstr "dup2(): %s\n"
+
+#: ../src/utils/pacat.c:729
+#, c-format
+msgid "Too many arguments.\n"
+msgstr "För många argument.\n"
+
+#: ../src/utils/pacat.c:742
+#: ../src/utils/pasuspender.c:280
+#: ../src/utils/pactl.c:909
+#: ../src/utils/paplay.c:381
+#, c-format
+msgid "pa_mainloop_new() failed.\n"
+msgstr "pa_mainloop_new() misslyckades.\n"
+
+#: ../src/utils/pacat.c:763
+#, c-format
+msgid "io_new() failed.\n"
+msgstr "io_new() misslyckades.\n"
+
+#: ../src/utils/pacat.c:769
+#: ../src/utils/pasuspender.c:293
+#: ../src/utils/pactl.c:923
+#: ../src/utils/paplay.c:396
+#, c-format
+msgid "pa_context_new() failed.\n"
+msgstr "pa_context_new() misslyckades.\n"
+
+#: ../src/utils/pacat.c:785
+#, c-format
+msgid "time_new() failed.\n"
+msgstr "time_new() misslyckades.\n"
+
+#: ../src/utils/pacat.c:792
+#: ../src/utils/pasuspender.c:301
+#: ../src/utils/pactl.c:931
+#: ../src/utils/paplay.c:407
+#, c-format
+msgid "pa_mainloop_run() failed.\n"
+msgstr "pa_mainloop_run() misslyckades.\n"
+
+#: ../src/utils/pasuspender.c:81
+#, c-format
+msgid "fork(): %s\n"
+msgstr "fork(): %s\n"
+
+#: ../src/utils/pasuspender.c:92
+#, c-format
+msgid "execvp(): %s\n"
+msgstr "execvp(): %s\n"
+
+#: ../src/utils/pasuspender.c:109
+#, c-format
+msgid "Failure to suspend: %s\n"
+msgstr ""
+
+#: ../src/utils/pasuspender.c:124
+#, c-format
+msgid "Failure to resume: %s\n"
+msgstr ""
+
+#: ../src/utils/pasuspender.c:147
+#, c-format
+msgid "WARNING: Sound server is not local, not suspending.\n"
+msgstr ""
+
+#: ../src/utils/pasuspender.c:176
+#: ../src/utils/pactl.c:672
+#: ../src/utils/paplay.c:191
+#, c-format
+msgid "Got SIGINT, exiting.\n"
+msgstr ""
+
+#: ../src/utils/pasuspender.c:194
+#, c-format
+msgid "WARNING: Child process terminated by signal %u\n"
+msgstr ""
+
+#: ../src/utils/pasuspender.c:212
+#, c-format
+msgid ""
+"%s [options] ... \n"
+"\n"
+" -h, --help Show this help\n"
+" --version Show version\n"
+" -s, --server=SERVER The name of the server to connect to\n"
+"\n"
+msgstr ""
+
+#: ../src/utils/pasuspender.c:251
+#, c-format
+msgid ""
+"pasuspender %s\n"
+"Compiled with libpulse %s\n"
+"Linked with libpulse %s\n"
+msgstr ""
+"pasuspender %s\n"
+"Kompilerad med libpulse %s\n"
+"Länkad med libpulse %s\n"
+
+#: ../src/utils/pactl.c:107
+#, c-format
+msgid "Failed to get statistics: %s\n"
+msgstr "Misslyckades med att få statistik: %s\n"
+
+#: ../src/utils/pactl.c:113
+#, c-format
+msgid "Currently in use: %u blocks containing %s bytes total.\n"
+msgstr ""
+
+#: ../src/utils/pactl.c:116
+#, c-format
+msgid "Allocated during whole lifetime: %u blocks containing %s bytes total.\n"
+msgstr ""
+
+#: ../src/utils/pactl.c:119
+#, c-format
+msgid "Sample cache size: %s\n"
+msgstr ""
+
+#: ../src/utils/pactl.c:128
+#, c-format
+msgid "Failed to get server information: %s\n"
+msgstr ""
+
+#: ../src/utils/pactl.c:135
+#, c-format
+msgid ""
+"User name: %s\n"
+"Host Name: %s\n"
+"Server Name: %s\n"
+"Server Version: %s\n"
+"Default Sample Specification: %s\n"
+"Default Sink: %s\n"
+"Default Source: %s\n"
+"Cookie: %08x\n"
+msgstr ""
+
+#: ../src/utils/pactl.c:160
+#, c-format
+msgid "Failed to get sink information: %s\n"
+msgstr ""
+
+#: ../src/utils/pactl.c:176
+#, c-format
+msgid ""
+"*** Sink #%u ***\n"
+"Name: %s\n"
+"Driver: %s\n"
+"Sample Specification: %s\n"
+"Channel Map: %s\n"
+"Owner Module: %u\n"
+"Volume: %s\n"
+"Monitor Source: %s\n"
+"Latency: %0.0f usec, configured %0.0f usec\n"
+"Flags: %s%s%s%s%s%s\n"
+"Properties:\n"
+"%s"
+msgstr ""
+
+#: ../src/utils/pactl.c:193
+#: ../src/utils/pactl.c:371
+msgid "muted"
+msgstr "tystad"
+
+#: ../src/utils/pactl.c:212
+#, c-format
+msgid "Failed to get source information: %s\n"
+msgstr ""
+
+#: ../src/utils/pactl.c:228
+#, c-format
+msgid ""
+"*** Source #%u ***\n"
+"Name: %s\n"
+"Driver: %s\n"
+"Sample Specification: %s\n"
+"Channel Map: %s\n"
+"Owner Module: %u\n"
+"Volume: %s\n"
+"Monitor of Sink: %s\n"
+"Latency: %0.0f usec, configured %0.0f usec\n"
+"Flags: %s%s%s%s%s%s\n"
+"Properties:\n"
+"%s"
+msgstr ""
+
+#: ../src/utils/pactl.c:246
+#: ../src/utils/pactl.c:289
+#: ../src/utils/pactl.c:322
+#: ../src/utils/pactl.c:366
+#: ../src/utils/pactl.c:367
+#: ../src/utils/pactl.c:374
+#: ../src/utils/pactl.c:418
+#: ../src/utils/pactl.c:419
+#: ../src/utils/pactl.c:425
+#: ../src/utils/pactl.c:468
+#: ../src/utils/pactl.c:469
+#: ../src/utils/pactl.c:473
+msgid "n/a"
+msgstr ""
+
+#: ../src/utils/pactl.c:263
+#, c-format
+msgid "Failed to get module information: %s\n"
+msgstr "Misslyckades med att få modulinformation: %s\n"
+
+#: ../src/utils/pactl.c:281
+#, c-format
+msgid ""
+"*** Module #%u ***\n"
+"Name: %s\n"
+"Argument: %s\n"
+"Usage counter: %s\n"
+"Auto unload: %s\n"
+msgstr ""
+
+#: ../src/utils/pactl.c:298
+#, c-format
+msgid "Failed to get client information: %s\n"
+msgstr "Misslyckades med att få klientinformation: %s\n"
+
+#: ../src/utils/pactl.c:316
+#, c-format
+msgid ""
+"*** Client #%u ***\n"
+"Driver: %s\n"
+"Owner Module: %s\n"
+"Properties:\n"
+"%s"
+msgstr ""
+
+#: ../src/utils/pactl.c:333
+#, c-format
+msgid "Failed to get sink input information: %s\n"
+msgstr ""
+
+#: ../src/utils/pactl.c:352
+#, c-format
+msgid ""
+"*** Sink Input #%u ***\n"
+"Driver: %s\n"
+"Owner Module: %s\n"
+"Client: %s\n"
+"Sink: %u\n"
+"Sample Specification: %s\n"
+"Channel Map: %s\n"
+"Volume: %s\n"
+"Buffer Latency: %0.0f usec\n"
+"Sink Latency: %0.0f usec\n"
+"Resample method: %s\n"
+"Properties:\n"
+"%s"
+msgstr ""
+
+#: ../src/utils/pactl.c:385
+#, c-format
+msgid "Failed to get source output information: %s\n"
+msgstr ""
+
+#: ../src/utils/pactl.c:405
+#, c-format
+msgid ""
+"*** Source Output #%u ***\n"
+"Driver: %s\n"
+"Owner Module: %s\n"
+"Client: %s\n"
+"Source: %u\n"
+"Sample Specification: %s\n"
+"Channel Map: %s\n"
+"Buffer Latency: %0.0f usec\n"
+"Source Latency: %0.0f usec\n"
+"Resample method: %s\n"
+"Properties:\n"
+"%s"
+msgstr ""
+
+#: ../src/utils/pactl.c:436
+#, c-format
+msgid "Failed to get sample information: %s\n"
+msgstr ""
+
+#: ../src/utils/pactl.c:455
+#, c-format
+msgid ""
+"*** Sample #%u ***\n"
+"Name: %s\n"
+"Volume: %s\n"
+"Sample Specification: %s\n"
+"Channel Map: %s\n"
+"Duration: %0.1fs\n"
+"Size: %s\n"
+"Lazy: %s\n"
+"Filename: %s\n"
+"Properties:\n"
+"%s"
+msgstr ""
+
+#: ../src/utils/pactl.c:481
+#, c-format
+msgid "Failed to get autoload information: %s\n"
+msgstr ""
+
+#: ../src/utils/pactl.c:497
+#, c-format
+msgid ""
+"*** Autoload Entry #%u ***\n"
+"Name: %s\n"
+"Type: %s\n"
+"Module: %s\n"
+"Argument: %s\n"
+msgstr ""
+
+#: ../src/utils/pactl.c:504
+msgid "sink"
+msgstr "sink"
+
+#: ../src/utils/pactl.c:504
+msgid "source"
+msgstr "källa"
+
+#: ../src/utils/pactl.c:511
+#: ../src/utils/pactl.c:521
+#, c-format
+msgid "Failure: %s\n"
+msgstr "Fel: %s\n"
+
+#: ../src/utils/pactl.c:545
+#, c-format
+msgid "Failed to upload sample: %s\n"
+msgstr ""
+
+#: ../src/utils/pactl.c:562
+#, c-format
+msgid "Premature end of file\n"
+msgstr ""
+
+#: ../src/utils/pactl.c:678
+#, c-format
+msgid ""
+"%s [options] stat\n"
+"%s [options] list\n"
+"%s [options] exit\n"
+"%s [options] upload-sample FILENAME [NAME]\n"
+"%s [options] play-sample NAME [SINK]\n"
+"%s [options] remove-sample NAME\n"
+"%s [options] move-sink-input ID SINK\n"
+"%s [options] move-source-output ID SOURCE\n"
+"%s [options] load-module NAME [ARGS ...]\n"
+"%s [options] unload-module ID\n"
+"%s [options] suspend-sink [SINK] 1|0\n"
+"%s [options] suspend-source [SOURCE] 1|0\n"
+"\n"
+" -h, --help Show this help\n"
+" --version Show version\n"
+"\n"
+" -s, --server=SERVER The name of the server to connect to\n"
+" -n, --client-name=NAME How to call this client on the server\n"
+msgstr ""
+
+#: ../src/utils/pactl.c:729
+#, c-format
+msgid ""
+"pactl %s\n"
+"Compiled with libpulse %s\n"
+"Linked with libpulse %s\n"
+msgstr ""
+"pactl %s\n"
+"Kompilerad med libpulse %s\n"
+"Länkad med libpulse %s\n"
+
+#: ../src/utils/pactl.c:768
+#, c-format
+msgid "Please specify a sample file to load\n"
+msgstr ""
+
+#: ../src/utils/pactl.c:790
+#, c-format
+msgid "Failed to open sound file.\n"
+msgstr "Misslyckades med att öppna ljudfil.\n"
+
+#: ../src/utils/pactl.c:802
+#, c-format
+msgid "You have to specify a sample name to play\n"
+msgstr ""
+
+#: ../src/utils/pactl.c:814
+#, c-format
+msgid "You have to specify a sample name to remove\n"
+msgstr ""
+
+#: ../src/utils/pactl.c:822
+#, c-format
+msgid "You have to specify a sink input index and a sink\n"
+msgstr ""
+
+#: ../src/utils/pactl.c:831
+#, c-format
+msgid "You have to specify a source output index and a source\n"
+msgstr ""
+
+#: ../src/utils/pactl.c:845
+#, c-format
+msgid "You have to specify a module name and arguments.\n"
+msgstr ""
+
+#: ../src/utils/pactl.c:865
+#, c-format
+msgid "You have to specify a module index\n"
+msgstr ""
+
+#: ../src/utils/pactl.c:875
+#, c-format
+msgid "You may not specify more than one sink. You have to specify at least one boolean value.\n"
+msgstr ""
+
+#: ../src/utils/pactl.c:888
+#, c-format
+msgid "You may not specify more than one source. You have to specify at least one boolean value.\n"
+msgstr ""
+
+#: ../src/utils/pactl.c:904
+#, c-format
+msgid "No valid command specified.\n"
+msgstr ""
+
+#: ../src/utils/pax11publish.c:61
+#, c-format
+msgid ""
+"%s [-D display] [-S server] [-O sink] [-I source] [-c file] [-d|-e|-i|-r]\n"
+"\n"
+" -d Show current PulseAudio data attached to X11 display (default)\n"
+" -e Export local PulseAudio data to X11 display\n"
+" -i Import PulseAudio data from X11 display to local environment variables and cookie file.\n"
+" -r Remove PulseAudio data from X11 display\n"
+msgstr ""
+
+#: ../src/utils/pax11publish.c:94
+#, c-format
+msgid "Failed to parse command line.\n"
+msgstr "Misslyckades med att tolka kommandorad.\n"
+
+#: ../src/utils/pax11publish.c:108
+#, c-format
+msgid "Server: %s\n"
+msgstr "Server: %s\n"
+
+#: ../src/utils/pax11publish.c:110
+#, c-format
+msgid "Source: %s\n"
+msgstr "Källa: %s\n"
+
+#: ../src/utils/pax11publish.c:112
+#, c-format
+msgid "Sink: %s\n"
+msgstr "Sink: %s\n"
+
+#: ../src/utils/pax11publish.c:114
+#, c-format
+msgid "Cookie: %s\n"
+msgstr "Kaka: %s\n"
+
+#: ../src/utils/pax11publish.c:132
+#, c-format
+msgid "Failed to parse cookie data\n"
+msgstr ""
+
+#: ../src/utils/pax11publish.c:137
+#, c-format
+msgid "Failed to save cookie data\n"
+msgstr ""
+
+#: ../src/utils/pax11publish.c:152
+#, c-format
+msgid "Failed to load client configuration file.\n"
+msgstr ""
+
+#: ../src/utils/pax11publish.c:157
+#, c-format
+msgid "Failed to read environment configuration data.\n"
+msgstr ""
+
+#: ../src/utils/pax11publish.c:174
+#, c-format
+msgid "Failed to get FQDN.\n"
+msgstr ""
+
+#: ../src/utils/pax11publish.c:194
+#, c-format
+msgid "Failed to load cookie data\n"
+msgstr ""
+
+#: ../src/utils/pax11publish.c:211
+#, c-format
+msgid "Not yet implemented.\n"
+msgstr "Ännu inte implementerad.\n"
+
+#: ../src/utils/pacmd.c:64
+#, c-format
+msgid "socket(PF_UNIX, SOCK_STREAM, 0): %s"
+msgstr ""
+
+#: ../src/utils/pacmd.c:81
+#, c-format
+msgid "connect(): %s"
+msgstr "connect(): %s"
+
+#: ../src/utils/pacmd.c:89
+msgid "Failed to kill PulseAudio daemon."
+msgstr ""
+
+#: ../src/utils/pacmd.c:97
+msgid "Daemon not responding."
+msgstr ""
+
+#: ../src/utils/pacmd.c:112
+#, c-format
+msgid "select(): %s"
+msgstr "select(): %s"
+
+#: ../src/utils/pacmd.c:124
+#: ../src/utils/pacmd.c:140
+#, c-format
+msgid "read(): %s"
+msgstr "read(): %s"
+
+#: ../src/utils/pacmd.c:153
+#: ../src/utils/pacmd.c:167
+#, c-format
+msgid "write(): %s"
+msgstr "write(): %s"
+
+#: ../src/utils/paplay.c:139
+#, c-format
+msgid "Stream successfully created\n"
+msgstr ""
+
+#: ../src/utils/paplay.c:144
+#, c-format
+msgid "Stream errror: %s\n"
+msgstr ""
+
+#: ../src/utils/paplay.c:165
+#, c-format
+msgid "Connection established.\n"
+msgstr "Anslutning etablerad.\n"
+
+#: ../src/utils/paplay.c:198
+#, c-format
+msgid ""
+"%s [options] [FILE]\n"
+"\n"
+" -h, --help Show this help\n"
+" --version Show version\n"
+"\n"
+" -v, --verbose Enable verbose operation\n"
+"\n"
+" -s, --server=SERVER The name of the server to connect to\n"
+" -d, --device=DEVICE The name of the sink to connect to\n"
+" -n, --client-name=NAME How to call this client on the server\n"
+" --stream-name=NAME How to call this stream on the server\n"
+" --volume=VOLUME Specify the initial (linear) volume in range 0...65536\n"
+" --channel-map=CHANNELMAP Set the channel map to the use\n"
+msgstr ""
+
+#: ../src/utils/paplay.c:255
+#, c-format
+msgid ""
+"paplay %s\n"
+"Compiled with libpulse %s\n"
+"Linked with libpulse %s\n"
+msgstr ""
+"paplay %s\n"
+"Kompilerad med libpulse %s\n"
+"Länkad med libpulse %s\n"
+
+#: ../src/utils/paplay.c:292
+#, c-format
+msgid "Invalid channel map\n"
+msgstr ""
+
+#: ../src/utils/paplay.c:314
+#, c-format
+msgid "Failed to open file '%s'\n"
+msgstr "Misslyckades med att öppna filen \"%s\"\n"
+
+#: ../src/utils/paplay.c:350
+#, c-format
+msgid "Channel map doesn't match file.\n"
+msgstr ""
+
+#: ../src/utils/paplay.c:376
+#, c-format
+msgid "Using sample spec '%s'\n"
+msgstr ""
+
diff --git a/src/.gitignore b/src/.gitignore
index 543f4e8e..72c38cc6 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -1,3 +1,4 @@
+prioq-test
lock-autospawn-test
*.lo
*.o
@@ -8,7 +9,7 @@ Makefile
Makefile.in
asyncmsgq-test
asyncq-test
-bt-proximity-helper
+proximity-helper
channelmap-test
client.conf
close-test
diff --git a/src/Makefile.am b/src/Makefile.am
index 22e691fa..9cbb9c70 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -45,7 +45,7 @@ endif
# Compiler/linker flags #
###################################
-AM_CFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src/modules -I$(top_builddir)/src/modules/rtp -I$(top_builddir)/src/modules/gconf
+AM_CFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src/modules -I$(top_builddir)/src/modules/rtp -I$(top_builddir)/src/modules/gconf -I$(top_builddir)/src/modules/bluetooth
AM_CFLAGS += $(PTHREAD_CFLAGS) -D_POSIX_PTHREAD_SEMANTICS
AM_CFLAGS += $(LTDLINCL)
AM_CFLAGS += $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) $(LIBSPEEX_CFLAGS)
@@ -62,8 +62,8 @@ AM_CFLAGS += -DPA_MACHINE_ID=\"$(localstatedir)/lib/dbus/machine-id\"
# This cool debug trap works on i386/gcc only
AM_CFLAGS += '-DDEBUG_TRAP=__asm__("int $$3")'
-AM_LIBADD = $(PTHREAD_LIBS)
-AM_LDADD = $(PTHREAD_LIBS)
+AM_LIBADD = $(PTHREAD_LIBS) $(INTLLIBS)
+AM_LDADD = $(PTHREAD_LIBS) $(INTLLIBS)
# Only required on some platforms but defined for all to avoid errors
AM_LDFLAGS = -Wl,-no-undefined -Wl,--gc-sections
@@ -263,7 +263,8 @@ noinst_PROGRAMS = \
proplist-test \
rtstutter \
stripnul \
- lock-autospawn-test
+ lock-autospawn-test \
+ prioq-test
if HAVE_SIGXCPU
noinst_PROGRAMS += \
@@ -458,6 +459,11 @@ lock_autospawn_test_LDADD = $(AM_LDADD) libpulsecore.la
lock_autospawn_test_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS)
lock_autospawn_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) $(LIBOIL_LIBS)
+prioq_test_SOURCES = tests/prioq-test.c
+prioq_test_LDADD = $(AM_LDADD) libpulsecore.la
+prioq_test_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS)
+prioq_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) $(LIBOIL_LIBS)
+
###################################
# Client library #
###################################
@@ -541,8 +547,7 @@ libpulse_la_SOURCES = \
pulse/xmalloc.c pulse/xmalloc.h \
pulse/proplist.c pulse/proplist.h \
pulse/ext-stream-restore.c pulse/ext-stream-restore.h \
- pulse/i18n.c pulse/i18n.h \
- pulse/lock-autospawn.c pulse/lock-autospawn.h
+ pulse/i18n.c pulse/i18n.h
# Internal stuff that is shared with libpulsecore
libpulse_la_SOURCES += \
@@ -740,8 +745,7 @@ libpulsecore_la_SOURCES = \
pulse/volume.c pulse/volume.h \
pulse/xmalloc.c pulse/xmalloc.h \
pulse/proplist.c pulse/proplist.h \
- pulse/i18n.c pulse/i18n.h \
- pulse/lock-autospawn.c pulse/lock-autospawn.h
+ pulse/i18n.c pulse/i18n.h
# Pure core stuff (some are shared in libpulse though).
libpulsecore_la_SOURCES += \
@@ -759,6 +763,7 @@ libpulsecore_la_SOURCES += \
pulsecore/g711.c pulsecore/g711.h \
pulsecore/hashmap.c pulsecore/hashmap.h \
pulsecore/idxset.c pulsecore/idxset.h \
+ pulsecore/prioq.c pulsecore/prioq.h \
pulsecore/log.c pulsecore/log.h \
pulsecore/mcalign.c pulsecore/mcalign.h \
pulsecore/memblock.c pulsecore/memblock.h \
@@ -811,6 +816,7 @@ libpulsecore_la_SOURCES += \
pulsecore/start-child.c pulsecore/start-child.h \
pulsecore/envelope.c pulsecore/envelope.h \
pulsecore/proplist-util.c pulsecore/proplist-util.h \
+ pulsecore/lock-autospawn.c pulsecore/lock-autospawn.h \
$(PA_THREAD_OBJS)
if OS_IS_WIN32
@@ -1161,10 +1167,14 @@ endif
if HAVE_BLUEZ
modlibexec_LTLIBRARIES += \
- module-bt-proximity.la
+ module-bluetooth-proximity.la \
+ module-bluetooth-discover.la \
+ libbluetooth-ipc.la \
+ libbluetooth-sbc.la \
+ module-bluetooth-device.la
pulselibexec_PROGRAMS += \
- bt-proximity-helper
+ proximity-helper
endif
# These are generated by a M4 script
@@ -1220,7 +1230,9 @@ SYMDEF_FILES = \
modules/module-rescue-streams-symdef.h \
modules/module-suspend-on-idle-symdef.h \
modules/module-hal-detect-symdef.h \
- modules/module-bt-proximity-symdef.h \
+ modules/bluetooth/module-bluetooth-proximity-symdef.h \
+ modules/bluetooth/module-bluetooth-discover-symdef.h \
+ modules/bluetooth/module-bluetooth-device-symdef.h \
modules/gconf/module-gconf-symdef.h \
modules/module-position-event-sounds-symdef.h \
modules/module-console-kit-symdef.h
@@ -1232,6 +1244,7 @@ $(SYMDEF_FILES): modules/module-defs.h.m4
$(MKDIR_P) modules
$(MKDIR_P) modules/gconf
$(MKDIR_P) modules/rtp
+ $(MKDIR_P) modules/bluetooth
$(M4) -Dfname="$@" $< > $@
# Simple protocol
@@ -1551,15 +1564,36 @@ gconf_helper_CFLAGS = $(AM_CFLAGS) $(GCONF_CFLAGS)
gconf_helper_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
# Bluetooth proximity
-module_bt_proximity_la_SOURCES = modules/module-bt-proximity.c
-module_bt_proximity_la_LDFLAGS = -module -avoid-version
-module_bt_proximity_la_LIBADD = $(AM_LIBADD) $(DBUS_LIBS) libpulsecore.la libdbus-util.la
-module_bt_proximity_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS) -DPA_BT_PROXIMITY_HELPER=\"$(pulselibexecdir)/bt-proximity-helper\"
-
-bt_proximity_helper_SOURCES = modules/bt-proximity-helper.c
-bt_proximity_helper_LDADD = $(AM_LDADD) $(BLUEZ_LIBS)
-bt_proximity_helper_CFLAGS = $(AM_CFLAGS) $(BLUEZ_CFLAGS)
-bt_proximity_helper_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
+module_bluetooth_proximity_la_SOURCES = modules/bluetooth/module-bluetooth-proximity.c
+module_bluetooth_proximity_la_LDFLAGS = -module -avoid-version
+module_bluetooth_proximity_la_LIBADD = $(AM_LIBADD) $(DBUS_LIBS) libpulsecore.la libdbus-util.la
+module_bluetooth_proximity_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS) -DPA_BT_PROXIMITY_HELPER=\"$(pulselibexecdir)/proximity-helper\"
+
+proximity_helper_SOURCES = modules/bluetooth/proximity-helper.c
+proximity_helper_LDADD = $(AM_LDADD) $(BLUEZ_LIBS)
+proximity_helper_CFLAGS = $(AM_CFLAGS) $(BLUEZ_CFLAGS)
+proximity_helper_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
+
+# Bluetooth sink / source
+module_bluetooth_discover_la_SOURCES = modules/bluetooth/module-bluetooth-discover.c
+module_bluetooth_discover_la_LDFLAGS = -module -avoid-version
+module_bluetooth_discover_la_LIBADD = $(AM_LIBADD) $(DBUS_LIBS) libpulsecore.la libdbus-util.la
+module_bluetooth_discover_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS)
+
+libbluetooth_sbc_la_SOURCES = modules/bluetooth/sbc.c modules/bluetooth/sbc.h modules/bluetooth/sbc_tables.h modules/bluetooth/sbc_math.h
+libbluetooth_sbc_la_LDFLAGS = -avoid-version
+libbluetooth_sbc_la_LIBADD = $(AM_LIBADD)
+libbluetooth_sbc_la_CFLAGS = $(AM_CFLAGS)
+
+libbluetooth_ipc_la_SOURCES = modules/bluetooth/ipc.c modules/bluetooth/ipc.h
+libbluetooth_ipc_la_LDFLAGS = -avoid-version
+libbluetooth_ipc_la_LIBADD = $(AM_LIBADD)
+libbluetooth_ipc_la_CFLAGS = $(AM_CFLAGS)
+
+module_bluetooth_device_la_SOURCES = modules/bluetooth/module-bluetooth-device.c
+module_bluetooth_device_la_LDFLAGS = -module -avoid-version
+module_bluetooth_device_la_LIBADD = $(AM_LIBADD) $(DBUS_LIBS) libpulsecore.la libdbus-util.la libbluetooth-ipc.la libbluetooth-sbc.la libsocket-util.la
+module_bluetooth_device_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS)
###################################
# Some minor stuff #
@@ -1608,7 +1642,7 @@ daemon.conf: daemon/daemon.conf.in Makefile
install-exec-hook:
chown root $(DESTDIR)$(bindir)/pulseaudio ; true
chmod u+s $(DESTDIR)$(bindir)/pulseaudio
- -chmod u+s $(DESTDIR)$(pulselibexecdir)/bt-proximity-helper
+ -chmod u+s $(DESTDIR)$(pulselibexecdir)/proximity-helper
ln -sf pacat $(DESTDIR)$(bindir)/parec
rm -f $(DESTDIR)$(modlibexecdir)/*.a
rm -f $(DESTDIR)$(libdir)/libpulsedsp.a
diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c
index 40e0a170..939b25d7 100644
--- a/src/daemon/daemon-conf.c
+++ b/src/daemon/daemon-conf.c
@@ -76,6 +76,7 @@ static const pa_daemon_conf default_conf = {
.log_level = PA_LOG_NOTICE,
.resample_method = PA_RESAMPLER_AUTO,
.disable_remixing = FALSE,
+ .disable_lfe_remixing = TRUE,
.config_file = NULL,
.use_pid_file = TRUE,
.system_instance = FALSE,
@@ -83,7 +84,8 @@ static const pa_daemon_conf default_conf = {
.disable_shm = FALSE,
.default_n_fragments = 4,
.default_fragment_size_msec = 25,
- .default_sample_spec = { .format = PA_SAMPLE_S16NE, .rate = 44100, .channels = 2 }
+ .default_sample_spec = { .format = PA_SAMPLE_S16NE, .rate = 44100, .channels = 2 },
+ .shm_size = 0
#ifdef HAVE_SYS_RESOURCE_H
,.rlimit_fsize = { .value = 0, .is_set = FALSE },
.rlimit_data = { .value = 0, .is_set = FALSE },
@@ -426,7 +428,9 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) {
{ "default-fragment-size-msec", parse_fragment_size_msec, NULL },
{ "nice-level", parse_nice_level, NULL },
{ "disable-remixing", pa_config_parse_bool, NULL },
+ { "disable-lfe-remixing", pa_config_parse_bool, NULL },
{ "load-default-script-file", pa_config_parse_bool, NULL },
+ { "shm-size-bytes", pa_config_parse_size, NULL },
#ifdef HAVE_SYS_RESOURCE_H
{ "rlimit-fsize", parse_rlimit, NULL },
{ "rlimit-data", parse_rlimit, NULL },
@@ -490,66 +494,68 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) {
table[24].data = c;
table[25].data = c;
table[26].data = &c->disable_remixing;
- table[27].data = &c->load_default_script_file;
+ table[27].data = &c->disable_lfe_remixing;
+ table[28].data = &c->load_default_script_file;
+ table[29].data = &c->shm_size;
#ifdef HAVE_SYS_RESOURCE_H
- table[28].data = &c->rlimit_fsize;
- table[29].data = &c->rlimit_data;
- table[30].data = &c->rlimit_stack;
- table[31].data = &c->rlimit_as;
- table[32].data = &c->rlimit_core;
- table[33].data = &c->rlimit_nofile;
- table[34].data = &c->rlimit_as;
+ table[30].data = &c->rlimit_fsize;
+ table[31].data = &c->rlimit_data;
+ table[32].data = &c->rlimit_stack;
+ table[33].data = &c->rlimit_as;
+ table[34].data = &c->rlimit_core;
+ table[35].data = &c->rlimit_nofile;
+ table[36].data = &c->rlimit_as;
#ifdef RLIMIT_NPROC
- table[35].data = &c->rlimit_nproc;
+ table[37].data = &c->rlimit_nproc;
#endif
#ifdef RLIMIT_MEMLOCK
#ifndef RLIMIT_NPROC
#error "Houston, we have a numbering problem!"
#endif
- table[36].data = &c->rlimit_memlock;
+ table[38].data = &c->rlimit_memlock;
#endif
#ifdef RLIMIT_LOCKS
#ifndef RLIMIT_MEMLOCK
#error "Houston, we have a numbering problem!"
#endif
- table[37].data = &c->rlimit_locks;
+ table[39].data = &c->rlimit_locks;
#endif
#ifdef RLIMIT_SIGPENDING
#ifndef RLIMIT_LOCKS
#error "Houston, we have a numbering problem!"
#endif
- table[38].data = &c->rlimit_sigpending;
+ table[40].data = &c->rlimit_sigpending;
#endif
#ifdef RLIMIT_MSGQUEUE
#ifndef RLIMIT_SIGPENDING
#error "Houston, we have a numbering problem!"
#endif
- table[39].data = &c->rlimit_msgqueue;
+ table[41].data = &c->rlimit_msgqueue;
#endif
#ifdef RLIMIT_NICE
#ifndef RLIMIT_MSGQUEUE
#error "Houston, we have a numbering problem!"
#endif
- table[40].data = &c->rlimit_nice;
+ table[42].data = &c->rlimit_nice;
#endif
#ifdef RLIMIT_RTPRIO
#ifndef RLIMIT_NICE
#error "Houston, we have a numbering problem!"
#endif
- table[41].data = &c->rlimit_rtprio;
+ table[43].data = &c->rlimit_rtprio;
#endif
#ifdef RLIMIT_RTTIME
#ifndef RLIMIT_RTTIME
#error "Houston, we have a numbering problem!"
#endif
- table[42].data = &c->rlimit_rttime;
+ table[44].data = &c->rlimit_rttime;
#endif
#endif
@@ -661,11 +667,13 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) {
pa_strbuf_printf(s, "log-level = %s\n", log_level_to_string[c->log_level]);
pa_strbuf_printf(s, "resample-method = %s\n", pa_resample_method_to_string(c->resample_method));
pa_strbuf_printf(s, "disable-remixing = %s\n", pa_yes_no(c->disable_remixing));
+ pa_strbuf_printf(s, "disable-lfe-remixing = %s\n", pa_yes_no(c->disable_lfe_remixing));
pa_strbuf_printf(s, "default-sample-format = %s\n", pa_sample_format_to_string(c->default_sample_spec.format));
pa_strbuf_printf(s, "default-sample-rate = %u\n", c->default_sample_spec.rate);
pa_strbuf_printf(s, "default-sample-channels = %u\n", c->default_sample_spec.channels);
pa_strbuf_printf(s, "default-fragments = %u\n", c->default_n_fragments);
pa_strbuf_printf(s, "default-fragment-size-msec = %u\n", c->default_fragment_size_msec);
+ pa_strbuf_printf(s, "shm-size-bytes = %lu\n", (unsigned long) c->shm_size);
#ifdef HAVE_SYS_RESOURCE_H
pa_strbuf_printf(s, "rlimit-fsize = %li\n", c->rlimit_fsize.is_set ? (long int) c->rlimit_fsize.value : -1);
pa_strbuf_printf(s, "rlimit-data = %li\n", c->rlimit_data.is_set ? (long int) c->rlimit_data.value : -1);
diff --git a/src/daemon/daemon-conf.h b/src/daemon/daemon-conf.h
index c42984f9..90329268 100644
--- a/src/daemon/daemon-conf.h
+++ b/src/daemon/daemon-conf.h
@@ -66,6 +66,7 @@ typedef struct pa_daemon_conf {
no_cpu_limit,
disable_shm,
disable_remixing,
+ disable_lfe_remixing,
load_default_script_file,
disallow_exit;
int exit_idle_time,
@@ -110,6 +111,7 @@ typedef struct pa_daemon_conf {
unsigned default_n_fragments, default_fragment_size_msec;
pa_sample_spec default_sample_spec;
+ size_t shm_size;
} pa_daemon_conf;
/* Allocate a new structure and fill it with sane defaults */
diff --git a/src/daemon/daemon.conf.in b/src/daemon/daemon.conf.in
index 33b1d61d..c672d420 100644
--- a/src/daemon/daemon.conf.in
+++ b/src/daemon/daemon.conf.in
@@ -26,6 +26,7 @@
; use-pid-file = yes
; system-instance = no
; disable-shm = no
+; shm-size-bytes = 0 # setting this 0 will use the system-default, usually 64 MiB
; high-priority = yes
; nice-level = -11
@@ -39,7 +40,7 @@
; dl-search-path = (depends on architecture)
-; load-defaul-script-file = yes
+; load-default-script-file = yes
; default-script-file = @PA_DEFAULT_CONFIG_FILE@
; log-target = auto
@@ -47,6 +48,7 @@
; resample-method = speex-float-3
; disable-remixing = no
+; disable-lfe-remixing = yes
; no-cpu-limit = no
diff --git a/src/daemon/default.pa.in b/src/daemon/default.pa.in
index 5f35e3ec..7032038d 100755
--- a/src/daemon/default.pa.in
+++ b/src/daemon/default.pa.in
@@ -48,6 +48,11 @@ load-module module-hal-detect
load-module module-detect
.endif
+### Automatically load driver modules for Bluetooth hardware
+#.ifexists module-bluetooth-discover@PA_SOEXT@
+#load-module module-bluetooth-discover
+#.endif
+
### Load several protocols
.ifexists module-esound-protocol-unix@PA_SOEXT@
load-module module-esound-protocol-unix
diff --git a/src/daemon/main.c b/src/daemon/main.c
index c8eda398..53f5d193 100644
--- a/src/daemon/main.c
+++ b/src/daemon/main.c
@@ -65,8 +65,8 @@
#include <pulse/timeval.h>
#include <pulse/xmalloc.h>
#include <pulse/i18n.h>
-#include <pulse/lock-autospawn.h>
+#include <pulsecore/lock-autospawn.h>
#include <pulsecore/winsock.h>
#include <pulsecore/core-error.h>
#include <pulsecore/core.h>
@@ -778,8 +778,15 @@ int main(int argc, char *argv[]) {
pa_set_env("PULSE_SYSTEM", conf->system_instance ? "1" : "0");
pa_log_info(_("This is PulseAudio %s"), PACKAGE_VERSION);
+ pa_log_debug(_("Compilation host: %s"), CANONICAL_HOST);
pa_log_debug(_("Compilation CFLAGS: %s"), PA_CFLAGS);
+ s = pa_uname_string();
+ pa_log_debug(_("Running on host: %s"), s);
+ pa_xfree(s);
+
+ pa_log_info(_("Page size is %lu bytes"), (unsigned long) PA_PAGE_SIZE);
+
#ifdef HAVE_VALGRIND_MEMCHECK_H
pa_log_debug(_("Compiled with Valgrind support: yes"));
#else
@@ -792,8 +799,6 @@ int main(int argc, char *argv[]) {
pa_log_debug(_("Optimized build: no"));
#endif
- pa_log_info(_("Page size is %lu bytes"), (unsigned long) PA_PAGE_SIZE);
-
if (!(s = pa_machine_id())) {
pa_log(_("Failed to get machine ID"));
goto finish;
@@ -849,7 +854,7 @@ int main(int argc, char *argv[]) {
pa_assert_se(mainloop = pa_mainloop_new());
- if (!(c = pa_core_new(pa_mainloop_get_api(mainloop), !conf->disable_shm))) {
+ if (!(c = pa_core_new(pa_mainloop_get_api(mainloop), !conf->disable_shm, conf->shm_size))) {
pa_log(_("pa_core_new() failed."));
goto finish;
}
@@ -864,6 +869,7 @@ int main(int argc, char *argv[]) {
c->realtime_priority = conf->realtime_priority;
c->realtime_scheduling = !!conf->realtime_scheduling;
c->disable_remixing = !!conf->disable_remixing;
+ c->disable_lfe_remixing = !!conf->disable_lfe_remixing;
c->running_as_daemon = !!conf->daemonize;
c->disallow_exit = conf->disallow_exit;
diff --git a/src/daemon/system.pa.in b/src/daemon/system.pa.in
index f6052c4b..27e42815 100755
--- a/src/daemon/system.pa.in
+++ b/src/daemon/system.pa.in
@@ -34,8 +34,9 @@ load-module module-esound-protocol-unix
.endif
load-module module-native-protocol-unix
-### Automatically restore the volume of playback streams
-load-module module-volume-restore
+### Automatically restore the volume of streams and devices
+load-module module-stream-restore
+load-module module-device-restore
### Automatically restore the default sink/source when changed by the user during runtime
load-module module-default-device-restore
diff --git a/src/modules/alsa-util.c b/src/modules/alsa-util.c
index 8fa405dd..c3eb72f5 100644
--- a/src/modules/alsa-util.c
+++ b/src/modules/alsa-util.c
@@ -370,11 +370,18 @@ int pa_alsa_set_hw_params(
goto finish;
if (_periods > 0) {
- dir = 1;
+
+ /* First we pass 0 as direction to get exactly what we asked
+ * for. That this is necessary is presumably a bug in ALSA */
+
+ dir = 0;
if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &_periods, &dir)) < 0) {
- dir = -1;
- if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &_periods, &dir)) < 0)
- goto finish;
+ dir = 1;
+ if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &_periods, &dir)) < 0) {
+ dir = -1;
+ if ((ret = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &_periods, &dir)) < 0)
+ goto finish;
+ }
}
}
diff --git a/src/modules/bluetooth/Makefile b/src/modules/bluetooth/Makefile
new file mode 120000
index 00000000..efe5a336
--- /dev/null
+++ b/src/modules/bluetooth/Makefile
@@ -0,0 +1 @@
+../../pulse/Makefile \ No newline at end of file
diff --git a/src/modules/bluetooth/ipc.c b/src/modules/bluetooth/ipc.c
new file mode 100644
index 00000000..98256998
--- /dev/null
+++ b/src/modules/bluetooth/ipc.c
@@ -0,0 +1,118 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "ipc.h"
+
+/* This table contains the string representation for messages */
+static const char *strmsg[] = {
+ "BT_GETCAPABILITIES_REQ",
+ "BT_GETCAPABILITIES_RSP",
+ "BT_SETCONFIGURATION_REQ",
+ "BT_SETCONFIGURATION_RSP",
+ "BT_STREAMSTART_REQ",
+ "BT_STREAMSTART_RSP",
+ "BT_STREAMSTOP_REQ",
+ "BT_STREAMSTOP_RSP",
+ "BT_STREAMSUSPEND_IND",
+ "BT_STREAMRESUME_IND",
+ "BT_CONTROL_REQ",
+ "BT_CONTROL_RSP",
+ "BT_CONTROL_IND",
+ "BT_STREAMFD_IND",
+};
+
+int bt_audio_service_open(void)
+{
+ int sk;
+ int err;
+ struct sockaddr_un addr = {
+ AF_UNIX, BT_IPC_SOCKET_NAME
+ };
+
+ sk = socket(PF_LOCAL, SOCK_STREAM, 0);
+ if (sk < 0) {
+ err = errno;
+ fprintf(stderr, "%s: Cannot open socket: %s (%d)\n",
+ __FUNCTION__, strerror(err), err);
+ errno = err;
+ return -1;
+ }
+
+ if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ err = errno;
+ fprintf(stderr, "%s: connect() failed: %s (%d)\n",
+ __FUNCTION__, strerror(err), err);
+ close(sk);
+ errno = err;
+ return -1;
+ }
+
+ return sk;
+}
+
+int bt_audio_service_close(int sk)
+{
+ return close(sk);
+}
+
+int bt_audio_service_get_data_fd(int sk)
+{
+ char cmsg_b[CMSG_SPACE(sizeof(int))], m;
+ int err, ret;
+ struct iovec iov = { &m, sizeof(m) };
+ struct msghdr msgh;
+ struct cmsghdr *cmsg;
+
+ memset(&msgh, 0, sizeof(msgh));
+ msgh.msg_iov = &iov;
+ msgh.msg_iovlen = 1;
+ msgh.msg_control = &cmsg_b;
+ msgh.msg_controllen = CMSG_LEN(sizeof(int));
+
+ ret = (int) recvmsg(sk, &msgh, 0);
+ if (ret < 0) {
+ err = errno;
+ fprintf(stderr, "%s: Unable to receive fd: %s (%d)\n",
+ __FUNCTION__, strerror(err), err);
+ errno = err;
+ return -1;
+ }
+
+ /* Receive auxiliary data in msgh */
+ for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL;
+ cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
+ if (cmsg->cmsg_level == SOL_SOCKET
+ && cmsg->cmsg_type == SCM_RIGHTS)
+ return (*(int *) CMSG_DATA(cmsg));
+ }
+
+ errno = EINVAL;
+ return -1;
+}
+
+const char *bt_audio_strmsg(int type)
+{
+ if (type < 0 || (size_t) type > (sizeof(strmsg) / sizeof(strmsg[0])))
+ return NULL;
+
+ return strmsg[type];
+}
diff --git a/src/modules/bluetooth/ipc.h b/src/modules/bluetooth/ipc.h
new file mode 100644
index 00000000..ae85e727
--- /dev/null
+++ b/src/modules/bluetooth/ipc.h
@@ -0,0 +1,308 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+/*
+ Message sequence chart of streaming sequence for A2DP transport
+
+ Audio daemon User
+ on snd_pcm_open
+ <--BT_GETCAPABILITIES_REQ
+
+ BT_GETCAPABILITIES_RSP-->
+
+ on snd_pcm_hw_params
+ <--BT_SETCONFIGURATION_REQ
+
+ BT_SETCONFIGURATION_RSP-->
+
+ on snd_pcm_prepare
+ <--BT_STREAMSTART_REQ
+
+ <Moves to streaming state>
+ BT_STREAMSTART_RSP-->
+
+ BT_STREAMFD_IND -->
+
+ < streams data >
+ ..........
+
+ on snd_pcm_drop/snd_pcm_drain
+
+ <--BT_STREAMSTOP_REQ
+
+ <Moves to open state>
+ BT_STREAMSTOP_RSP-->
+
+ on IPC close or appl crash
+ <Moves to idle>
+
+ */
+
+#ifndef BT_AUDIOCLIENT_H
+#define BT_AUDIOCLIENT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <errno.h>
+
+#define BT_AUDIO_IPC_PACKET_SIZE 128
+#define BT_IPC_SOCKET_NAME "\0/org/bluez/audio"
+
+/* Generic message header definition, except for RSP messages */
+typedef struct {
+ uint8_t msg_type;
+} __attribute__ ((packed)) bt_audio_msg_header_t;
+
+/* Generic message header definition, for all RSP messages */
+typedef struct {
+ bt_audio_msg_header_t msg_h;
+ uint8_t posix_errno;
+} __attribute__ ((packed)) bt_audio_rsp_msg_header_t;
+
+/* Messages list */
+#define BT_GETCAPABILITIES_REQ 0
+#define BT_GETCAPABILITIES_RSP 1
+
+#define BT_SETCONFIGURATION_REQ 2
+#define BT_SETCONFIGURATION_RSP 3
+
+#define BT_STREAMSTART_REQ 4
+#define BT_STREAMSTART_RSP 5
+
+#define BT_STREAMSTOP_REQ 6
+#define BT_STREAMSTOP_RSP 7
+
+#define BT_STREAMSUSPEND_IND 8
+#define BT_STREAMRESUME_IND 9
+
+#define BT_CONTROL_REQ 10
+#define BT_CONTROL_RSP 11
+#define BT_CONTROL_IND 12
+
+#define BT_STREAMFD_IND 13
+
+/* BT_GETCAPABILITIES_REQ */
+
+#define BT_CAPABILITIES_TRANSPORT_A2DP 0
+#define BT_CAPABILITIES_TRANSPORT_SCO 1
+#define BT_CAPABILITIES_TRANSPORT_ANY 2
+
+#define BT_CAPABILITIES_ACCESS_MODE_READ 1
+#define BT_CAPABILITIES_ACCESS_MODE_WRITE 2
+#define BT_CAPABILITIES_ACCESS_MODE_READWRITE 3
+
+#define BT_FLAG_AUTOCONNECT 1
+
+struct bt_getcapabilities_req {
+ bt_audio_msg_header_t h;
+ char device[18]; /* Address of the remote Device */
+ uint8_t transport; /* Requested transport */
+ uint8_t flags; /* Requested flags */
+} __attribute__ ((packed));
+
+/* BT_GETCAPABILITIES_RSP */
+
+/**
+ * SBC Codec parameters as per A2DP profile 1.0 § 4.3
+ */
+
+#define BT_SBC_SAMPLING_FREQ_16000 (1 << 3)
+#define BT_SBC_SAMPLING_FREQ_32000 (1 << 2)
+#define BT_SBC_SAMPLING_FREQ_44100 (1 << 1)
+#define BT_SBC_SAMPLING_FREQ_48000 1
+
+#define BT_A2DP_CHANNEL_MODE_MONO (1 << 3)
+#define BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL (1 << 2)
+#define BT_A2DP_CHANNEL_MODE_STEREO (1 << 1)
+#define BT_A2DP_CHANNEL_MODE_JOINT_STEREO 1
+
+#define BT_A2DP_BLOCK_LENGTH_4 (1 << 3)
+#define BT_A2DP_BLOCK_LENGTH_8 (1 << 2)
+#define BT_A2DP_BLOCK_LENGTH_12 (1 << 1)
+#define BT_A2DP_BLOCK_LENGTH_16 1
+
+#define BT_A2DP_SUBBANDS_4 (1 << 1)
+#define BT_A2DP_SUBBANDS_8 1
+
+#define BT_A2DP_ALLOCATION_SNR (1 << 1)
+#define BT_A2DP_ALLOCATION_LOUDNESS 1
+
+#define BT_MPEG_SAMPLING_FREQ_16000 (1 << 5)
+#define BT_MPEG_SAMPLING_FREQ_22050 (1 << 4)
+#define BT_MPEG_SAMPLING_FREQ_24000 (1 << 3)
+#define BT_MPEG_SAMPLING_FREQ_32000 (1 << 2)
+#define BT_MPEG_SAMPLING_FREQ_44100 (1 << 1)
+#define BT_MPEG_SAMPLING_FREQ_48000 1
+
+#define BT_MPEG_LAYER_1 (1 << 2)
+#define BT_MPEG_LAYER_2 (1 << 1)
+#define BT_MPEG_LAYER_3 1
+
+typedef struct {
+ uint8_t channel_mode;
+ uint8_t frequency;
+ uint8_t allocation_method;
+ uint8_t subbands;
+ uint8_t block_length;
+ uint8_t min_bitpool;
+ uint8_t max_bitpool;
+} __attribute__ ((packed)) sbc_capabilities_t;
+
+typedef struct {
+ uint8_t channel_mode;
+ uint8_t crc;
+ uint8_t layer;
+ uint8_t frequency;
+ uint8_t mpf;
+ uint16_t bitrate;
+} __attribute__ ((packed)) mpeg_capabilities_t;
+
+struct bt_getcapabilities_rsp {
+ bt_audio_rsp_msg_header_t rsp_h;
+ uint8_t transport; /* Granted transport */
+ sbc_capabilities_t sbc_capabilities; /* A2DP only */
+ mpeg_capabilities_t mpeg_capabilities; /* A2DP only */
+ uint16_t sampling_rate; /* SCO only */
+} __attribute__ ((packed));
+
+/* BT_SETCONFIGURATION_REQ */
+struct bt_setconfiguration_req {
+ bt_audio_msg_header_t h;
+ char device[18]; /* Address of the remote Device */
+ uint8_t transport; /* Requested transport */
+ uint8_t access_mode; /* Requested access mode */
+ sbc_capabilities_t sbc_capabilities; /* A2DP only - only one of this field
+ and next one must be filled */
+ mpeg_capabilities_t mpeg_capabilities; /* A2DP only */
+} __attribute__ ((packed));
+
+/* BT_SETCONFIGURATION_RSP */
+struct bt_setconfiguration_rsp {
+ bt_audio_rsp_msg_header_t rsp_h;
+ uint8_t transport; /* Granted transport */
+ uint8_t access_mode; /* Granted access mode */
+ uint16_t link_mtu; /* Max length that transport supports */
+} __attribute__ ((packed));
+
+/* BT_STREAMSTART_REQ */
+#define BT_STREAM_ACCESS_READ 0
+#define BT_STREAM_ACCESS_WRITE 1
+#define BT_STREAM_ACCESS_READWRITE 2
+struct bt_streamstart_req {
+ bt_audio_msg_header_t h;
+} __attribute__ ((packed));
+
+/* BT_STREAMSTART_RSP */
+struct bt_streamstart_rsp {
+ bt_audio_rsp_msg_header_t rsp_h;
+} __attribute__ ((packed));
+
+/* BT_STREAMFD_IND */
+/* This message is followed by one byte of data containing the stream data fd
+ as ancilliary data */
+struct bt_streamfd_ind {
+ bt_audio_msg_header_t h;
+} __attribute__ ((packed));
+
+/* BT_STREAMSTOP_REQ */
+struct bt_streamstop_req {
+ bt_audio_msg_header_t h;
+} __attribute__ ((packed));
+
+/* BT_STREAMSTOP_RSP */
+struct bt_streamstop_rsp {
+ bt_audio_rsp_msg_header_t rsp_h;
+} __attribute__ ((packed));
+
+/* BT_STREAMSUSPEND_IND */
+struct bt_streamsuspend_ind {
+ bt_audio_msg_header_t h;
+} __attribute__ ((packed));
+
+/* BT_STREAMRESUME_IND */
+struct bt_streamresume_ind {
+ bt_audio_msg_header_t h;
+} __attribute__ ((packed));
+
+/* BT_CONTROL_REQ */
+
+#define BT_CONTROL_KEY_POWER 0x40
+#define BT_CONTROL_KEY_VOL_UP 0x41
+#define BT_CONTROL_KEY_VOL_DOWN 0x42
+#define BT_CONTROL_KEY_MUTE 0x43
+#define BT_CONTROL_KEY_PLAY 0x44
+#define BT_CONTROL_KEY_STOP 0x45
+#define BT_CONTROL_KEY_PAUSE 0x46
+#define BT_CONTROL_KEY_RECORD 0x47
+#define BT_CONTROL_KEY_REWIND 0x48
+#define BT_CONTROL_KEY_FAST_FORWARD 0x49
+#define BT_CONTROL_KEY_EJECT 0x4A
+#define BT_CONTROL_KEY_FORWARD 0x4B
+#define BT_CONTROL_KEY_BACKWARD 0x4C
+
+struct bt_control_req {
+ bt_audio_msg_header_t h;
+ uint8_t mode; /* Control Mode */
+ uint8_t key; /* Control Key */
+} __attribute__ ((packed));
+
+/* BT_CONTROL_RSP */
+struct bt_control_rsp {
+ bt_audio_rsp_msg_header_t rsp_h;
+ uint8_t mode; /* Control Mode */
+ uint8_t key; /* Control Key */
+} __attribute__ ((packed));
+
+/* BT_CONTROL_IND */
+struct bt_control_ind {
+ bt_audio_msg_header_t h;
+ uint8_t mode; /* Control Mode */
+ uint8_t key; /* Control Key */
+} __attribute__ ((packed));
+
+/* Function declaration */
+
+/* Opens a connection to the audio service: return a socket descriptor */
+int bt_audio_service_open(void);
+
+/* Closes a connection to the audio service */
+int bt_audio_service_close(int sk);
+
+/* Receives stream data file descriptor : must be called after a
+BT_STREAMFD_IND message is returned */
+int bt_audio_service_get_data_fd(int sk);
+
+/* Human readable message type string */
+const char *bt_audio_strmsg(int type);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BT_AUDIOCLIENT_H */
diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c
new file mode 100644
index 00000000..395d54f1
--- /dev/null
+++ b/src/modules/bluetooth/module-bluetooth-device.c
@@ -0,0 +1,929 @@
+/***
+ This file is part of PulseAudio.
+
+ Copyright 2008 Joao Paulo Rechi Vita
+
+ PulseAudio is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ PulseAudio is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PulseAudio; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <errno.h>
+#include <poll.h>
+#include <sys/ioctl.h>
+#include <linux/sockios.h>
+#include <arpa/inet.h>
+
+#include <pulse/xmalloc.h>
+#include <pulse/timeval.h>
+#include <pulse/sample.h>
+#include <pulsecore/module.h>
+#include <pulsecore/modargs.h>
+#include <pulsecore/core-util.h>
+#include <pulsecore/core-error.h>
+#include <pulsecore/socket-util.h>
+#include <pulsecore/thread.h>
+#include <pulsecore/thread-mq.h>
+#include <pulsecore/rtpoll.h>
+#include <pulsecore/time-smoother.h>
+#include <pulsecore/rtclock.h>
+
+#include "dbus-util.h"
+#include "module-bluetooth-device-symdef.h"
+#include "ipc.h"
+#include "sbc.h"
+#include "rtp.h"
+
+#define DEFAULT_SINK_NAME "bluetooth_sink"
+#define BUFFER_SIZE 2048
+#define MAX_BITPOOL 64
+#define MIN_BITPOOL 2U
+#define SOL_SCO 17
+#define SCO_TXBUFS 0x03
+#define SCO_RXBUFS 0x04
+
+PA_MODULE_AUTHOR("Joao Paulo Rechi Vita");
+PA_MODULE_DESCRIPTION("Bluetooth audio sink and source");
+PA_MODULE_VERSION(PACKAGE_VERSION);
+PA_MODULE_LOAD_ONCE(FALSE);
+PA_MODULE_USAGE(
+ "sink_name=<name of the device> "
+ "address=<address of the device> "
+ "profile=<a2dp|hsp>");
+
+struct bt_a2dp {
+ sbc_capabilities_t sbc_capabilities;
+ sbc_t sbc; /* Codec data */
+ pa_bool_t sbc_initialized; /* Keep track if the encoder is initialized */
+ size_t codesize; /* SBC codesize */
+ unsigned samples; /* Number of encoded samples */
+ uint8_t buffer[BUFFER_SIZE]; /* Codec transfer buffer */
+ size_t count; /* Codec transfer buffer counter */
+
+ unsigned total_samples; /* Cumulative number of codec samples */
+ uint16_t seq_num; /* Cumulative packet sequence */
+ unsigned frame_count; /* Current frames in buffer*/
+};
+
+struct userdata {
+ pa_core *core;
+ pa_module *module;
+ pa_sink *sink;
+
+ pa_thread_mq thread_mq;
+ pa_rtpoll *rtpoll;
+ pa_rtpoll_item *rtpoll_item;
+ pa_thread *thread;
+
+ uint64_t offset;
+ pa_smoother *smoother;
+
+ char *name;
+ char *addr;
+ char *profile;
+ pa_sample_spec ss;
+
+ int audioservice_fd;
+ int stream_fd;
+
+ uint8_t transport;
+ char *strtransport;
+ size_t link_mtu;
+ size_t block_size;
+ pa_usec_t latency;
+
+ struct bt_a2dp a2dp;
+};
+
+static const char* const valid_modargs[] = {
+ "sink_name",
+ "address",
+ "profile",
+ "rate",
+ "channels",
+ NULL
+};
+
+static int bt_audioservice_send(int sk, const bt_audio_msg_header_t *msg) {
+ int e;
+ pa_log_debug("sending %s", bt_audio_strmsg(msg->msg_type));
+ if (send(sk, msg, BT_AUDIO_IPC_PACKET_SIZE, 0) > 0)
+ e = 0;
+ else {
+ e = -errno;
+ pa_log_error("Error sending data to audio service: %s(%d)", pa_cstrerror(errno), errno);
+ }
+ return e;
+}
+
+static int bt_audioservice_recv(int sk, bt_audio_msg_header_t *inmsg) {
+ int e;
+ const char *type;
+
+ pa_log_debug("trying to receive msg from audio service...");
+ if (recv(sk, inmsg, BT_AUDIO_IPC_PACKET_SIZE, 0) > 0) {
+ type = bt_audio_strmsg(inmsg->msg_type);
+ if (type) {
+ pa_log_debug("Received %s", type);
+ e = 0;
+ }
+ else {
+ e = -EINVAL;
+ pa_log_error("Bogus message type %d received from audio service", inmsg->msg_type);
+ }
+ }
+ else {
+ e = -errno;
+ pa_log_error("Error receiving data from audio service: %s(%d)", pa_cstrerror(errno), errno);
+ }
+
+ return e;
+}
+
+static int bt_audioservice_expect(int sk, bt_audio_msg_header_t *rsp_hdr, int expected_type) {
+ int e = bt_audioservice_recv(sk, rsp_hdr);
+ if (e == 0) {
+ if (rsp_hdr->msg_type != expected_type) {
+ e = -EINVAL;
+ pa_log_error("Bogus message %s received while %s was expected", bt_audio_strmsg(rsp_hdr->msg_type),
+ bt_audio_strmsg(expected_type));
+ }
+ }
+ return e;
+}
+
+static int bt_getcaps(struct userdata *u) {
+ int e;
+ union {
+ bt_audio_rsp_msg_header_t rsp_hdr;
+ struct bt_getcapabilities_req getcaps_req;
+ struct bt_getcapabilities_rsp getcaps_rsp;
+ uint8_t buf[BT_AUDIO_IPC_PACKET_SIZE];
+ } msg;
+
+ memset(msg.buf, 0, BT_AUDIO_IPC_PACKET_SIZE);
+ msg.getcaps_req.h.msg_type = BT_GETCAPABILITIES_REQ;
+ strncpy(msg.getcaps_req.device, u->addr, 18);
+ if (strcasecmp(u->profile, "a2dp") == 0)
+ msg.getcaps_req.transport = BT_CAPABILITIES_TRANSPORT_A2DP;
+ else if (strcasecmp(u->profile, "hsp") == 0)
+ msg.getcaps_req.transport = BT_CAPABILITIES_TRANSPORT_SCO;
+ else {
+ pa_log_error("Invalid profile argument: %s", u->profile);
+ return -1;
+ }
+ msg.getcaps_req.flags = BT_FLAG_AUTOCONNECT;
+
+ e = bt_audioservice_send(u->audioservice_fd, &msg.getcaps_req.h);
+ if (e < 0) {
+ pa_log_error("Failed to send GETCAPABILITIES_REQ");
+ return e;
+ }
+
+ e = bt_audioservice_expect(u->audioservice_fd, &msg.rsp_hdr.msg_h, BT_GETCAPABILITIES_RSP);
+ if (e < 0) {
+ pa_log_error("Failed to expect for GETCAPABILITIES_RSP");
+ return e;
+ }
+ if (msg.rsp_hdr.posix_errno != 0) {
+ pa_log_error("BT_GETCAPABILITIES failed : %s (%d)", pa_cstrerror(msg.rsp_hdr.posix_errno), msg.rsp_hdr.posix_errno);
+ return -msg.rsp_hdr.posix_errno;
+ }
+
+ if ((u->transport = msg.getcaps_rsp.transport) == BT_CAPABILITIES_TRANSPORT_A2DP)
+ u->a2dp.sbc_capabilities = msg.getcaps_rsp.sbc_capabilities;
+
+ return 0;
+}
+
+static uint8_t default_bitpool(uint8_t freq, uint8_t mode) {
+ switch (freq) {
+ case BT_SBC_SAMPLING_FREQ_16000:
+ case BT_SBC_SAMPLING_FREQ_32000:
+ return 53;
+ case BT_SBC_SAMPLING_FREQ_44100:
+ switch (mode) {
+ case BT_A2DP_CHANNEL_MODE_MONO:
+ case BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL:
+ return 31;
+ case BT_A2DP_CHANNEL_MODE_STEREO:
+ case BT_A2DP_CHANNEL_MODE_JOINT_STEREO:
+ return 53;
+ default:
+ pa_log_warn("Invalid channel mode %u", mode);
+ return 53;
+ }
+ case BT_SBC_SAMPLING_FREQ_48000:
+ switch (mode) {
+ case BT_A2DP_CHANNEL_MODE_MONO:
+ case BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL:
+ return 29;
+ case BT_A2DP_CHANNEL_MODE_STEREO:
+ case BT_A2DP_CHANNEL_MODE_JOINT_STEREO:
+ return 51;
+ default:
+ pa_log_warn("Invalid channel mode %u", mode);
+ return 51;
+ }
+ default:
+ pa_log_warn("Invalid sampling freq %u", freq);
+ return 53;
+ }
+}
+
+static int bt_a2dp_init(struct userdata *u) {
+ sbc_capabilities_t *cap = &u->a2dp.sbc_capabilities;
+ uint8_t max_bitpool, min_bitpool;
+ unsigned i;
+
+ static const struct {
+ uint32_t rate;
+ uint8_t cap;
+ } freq_table[] = {
+ { 16000U, BT_SBC_SAMPLING_FREQ_16000 },
+ { 32000U, BT_SBC_SAMPLING_FREQ_32000 },
+ { 44100U, BT_SBC_SAMPLING_FREQ_44100 },
+ { 48000U, BT_SBC_SAMPLING_FREQ_48000 }
+ };
+
+ /* Find the lowest freq that is at least as high as the requested
+ * sampling rate */
+ for (i = 0; i < PA_ELEMENTSOF(freq_table); i++)
+ if (freq_table[i].rate >= u->ss.rate || i == PA_ELEMENTSOF(freq_table)-1 ) {
+ u->ss.rate = freq_table[i].rate;
+ cap->frequency = freq_table[i].cap;
+ break;
+ }
+
+ if (u->ss.channels >= 2) {
+ if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_JOINT_STEREO)
+ cap->channel_mode = BT_A2DP_CHANNEL_MODE_JOINT_STEREO;
+ else if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO)
+ cap->channel_mode = BT_A2DP_CHANNEL_MODE_STEREO;
+ else if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL)
+ cap->channel_mode = BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL;
+
+ u->ss.channels = 2;
+ } else {
+ if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_MONO)
+ cap->channel_mode = BT_A2DP_CHANNEL_MODE_MONO;
+ }
+
+ if (!cap->channel_mode) {
+ pa_log_error("No supported channel modes");
+ return -1;
+ }
+
+ if (cap->block_length & BT_A2DP_BLOCK_LENGTH_16)
+ cap->block_length = BT_A2DP_BLOCK_LENGTH_16;
+ else if (cap->block_length & BT_A2DP_BLOCK_LENGTH_12)
+ cap->block_length = BT_A2DP_BLOCK_LENGTH_12;
+ else if (cap->block_length & BT_A2DP_BLOCK_LENGTH_8)
+ cap->block_length = BT_A2DP_BLOCK_LENGTH_8;
+ else if (cap->block_length & BT_A2DP_BLOCK_LENGTH_4)
+ cap->block_length = BT_A2DP_BLOCK_LENGTH_4;
+ else {
+ pa_log_error("No supported block lengths");
+ return -1;
+ }
+
+ if (cap->subbands & BT_A2DP_SUBBANDS_8)
+ cap->subbands = BT_A2DP_SUBBANDS_8;
+ else if (cap->subbands & BT_A2DP_SUBBANDS_4)
+ cap->subbands = BT_A2DP_SUBBANDS_4;
+ else {
+ pa_log_error("No supported subbands");
+ return -1;
+ }
+
+ if (cap->allocation_method & BT_A2DP_ALLOCATION_LOUDNESS)
+ cap->allocation_method = BT_A2DP_ALLOCATION_LOUDNESS;
+ else if (cap->allocation_method & BT_A2DP_ALLOCATION_SNR)
+ cap->allocation_method = BT_A2DP_ALLOCATION_SNR;
+
+ min_bitpool = (uint8_t) PA_MAX(MIN_BITPOOL, cap->min_bitpool);
+ max_bitpool = (uint8_t) PA_MIN(default_bitpool(cap->frequency, cap->channel_mode), cap->max_bitpool);
+
+ cap->min_bitpool = (uint8_t) min_bitpool;
+ cap->max_bitpool = (uint8_t) max_bitpool;
+
+ return 0;
+}
+
+static void bt_a2dp_setup(struct bt_a2dp *a2dp) {
+ sbc_capabilities_t active_capabilities = a2dp->sbc_capabilities;
+
+ if (a2dp->sbc_initialized)
+ sbc_reinit(&a2dp->sbc, 0);
+ else
+ sbc_init(&a2dp->sbc, 0);
+ a2dp->sbc_initialized = TRUE;
+
+ if (active_capabilities.frequency & BT_SBC_SAMPLING_FREQ_16000)
+ a2dp->sbc.frequency = SBC_FREQ_16000;
+
+ if (active_capabilities.frequency & BT_SBC_SAMPLING_FREQ_32000)
+ a2dp->sbc.frequency = SBC_FREQ_32000;
+
+ if (active_capabilities.frequency & BT_SBC_SAMPLING_FREQ_44100)
+ a2dp->sbc.frequency = SBC_FREQ_44100;
+
+ if (active_capabilities.frequency & BT_SBC_SAMPLING_FREQ_48000)
+ a2dp->sbc.frequency = SBC_FREQ_48000;
+
+ if (active_capabilities.channel_mode & BT_A2DP_CHANNEL_MODE_MONO)
+ a2dp->sbc.mode = SBC_MODE_MONO;
+
+ if (active_capabilities.channel_mode & BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL)
+ a2dp->sbc.mode = SBC_MODE_DUAL_CHANNEL;
+
+ if (active_capabilities.channel_mode & BT_A2DP_CHANNEL_MODE_STEREO)
+ a2dp->sbc.mode = SBC_MODE_STEREO;
+
+ if (active_capabilities.channel_mode & BT_A2DP_CHANNEL_MODE_JOINT_STEREO)
+ a2dp->sbc.mode = SBC_MODE_JOINT_STEREO;
+
+ a2dp->sbc.allocation = (uint8_t) (active_capabilities.allocation_method == BT_A2DP_ALLOCATION_SNR ? SBC_AM_SNR : SBC_AM_LOUDNESS);
+
+ switch (active_capabilities.subbands) {
+ case BT_A2DP_SUBBANDS_4:
+ a2dp->sbc.subbands = SBC_SB_4;
+ break;
+ case BT_A2DP_SUBBANDS_8:
+ a2dp->sbc.subbands = SBC_SB_8;
+ break;
+ }
+
+ switch (active_capabilities.block_length) {
+ case BT_A2DP_BLOCK_LENGTH_4:
+ a2dp->sbc.blocks = SBC_BLK_4;
+ break;
+ case BT_A2DP_BLOCK_LENGTH_8:
+ a2dp->sbc.blocks = SBC_BLK_8;
+ break;
+ case BT_A2DP_BLOCK_LENGTH_12:
+ a2dp->sbc.blocks = SBC_BLK_12;
+ break;
+ case BT_A2DP_BLOCK_LENGTH_16:
+ a2dp->sbc.blocks = SBC_BLK_16;
+ break;
+ }
+
+ a2dp->sbc.bitpool = active_capabilities.max_bitpool;
+ a2dp->codesize = (uint16_t) sbc_get_codesize(&a2dp->sbc);
+ a2dp->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload);
+}
+
+static int bt_setconf(struct userdata *u) {
+ int e;
+ union {
+ bt_audio_rsp_msg_header_t rsp_hdr;
+ struct bt_setconfiguration_req setconf_req;
+ struct bt_setconfiguration_rsp setconf_rsp;
+ uint8_t buf[BT_AUDIO_IPC_PACKET_SIZE];
+ } msg;
+
+ if (u->transport == BT_CAPABILITIES_TRANSPORT_A2DP) {
+ e = bt_a2dp_init(u);
+ if (e < 0) {
+ pa_log_error("a2dp_init error");
+ return e;
+ }
+ u->ss.format = PA_SAMPLE_S16LE;
+ }
+ else
+ u->ss.format = PA_SAMPLE_U8;
+
+ memset(msg.buf, 0, BT_AUDIO_IPC_PACKET_SIZE);
+ msg.setconf_req.h.msg_type = BT_SETCONFIGURATION_REQ;
+ strncpy(msg.setconf_req.device, u->addr, 18);
+ msg.setconf_req.transport = u->transport;
+ if (u->transport == BT_CAPABILITIES_TRANSPORT_A2DP)
+ msg.setconf_req.sbc_capabilities = u->a2dp.sbc_capabilities;
+ msg.setconf_req.access_mode = BT_CAPABILITIES_ACCESS_MODE_WRITE;
+
+ e = bt_audioservice_send(u->audioservice_fd, &msg.setconf_req.h);
+ if (e < 0) {
+ pa_log_error("Failed to send BT_SETCONFIGURATION_REQ");
+ return e;
+ }
+
+ e = bt_audioservice_expect(u->audioservice_fd, &msg.rsp_hdr.msg_h, BT_SETCONFIGURATION_RSP);
+ if (e < 0) {
+ pa_log_error("Failed to expect BT_SETCONFIGURATION_RSP");
+ return e;
+ }
+
+ if (msg.rsp_hdr.posix_errno != 0) {
+ pa_log_error("BT_SETCONFIGURATION failed : %s(%d)", pa_cstrerror(msg.rsp_hdr.posix_errno), msg.rsp_hdr.posix_errno);
+ return -msg.rsp_hdr.posix_errno;
+ }
+
+ u->transport = msg.setconf_rsp.transport;
+ u->strtransport = (u->transport == BT_CAPABILITIES_TRANSPORT_A2DP ? pa_xstrdup("A2DP") : pa_xstrdup("SCO"));
+ u->link_mtu = msg.setconf_rsp.link_mtu;
+
+ /* setup SBC encoder now we agree on parameters */
+ if (u->transport == BT_CAPABILITIES_TRANSPORT_A2DP) {
+ bt_a2dp_setup(&u->a2dp);
+ u->block_size = u->a2dp.codesize;
+ pa_log_info("sbc parameters:\n\tallocation=%u\n\tsubbands=%u\n\tblocks=%u\n\tbitpool=%u\n",
+ u->a2dp.sbc.allocation, u->a2dp.sbc.subbands, u->a2dp.sbc.blocks, u->a2dp.sbc.bitpool);
+ }
+ else
+ u->block_size = u->link_mtu;
+
+ return 0;
+}
+
+static int bt_getstreamfd(struct userdata *u) {
+ int e;
+// uint32_t period_count = io->buffer_size / io->period_size;
+ union {
+ bt_audio_rsp_msg_header_t rsp_hdr;
+ struct bt_streamstart_req start_req;
+ struct bt_streamfd_ind streamfd_ind;
+ uint8_t buf[BT_AUDIO_IPC_PACKET_SIZE];
+ } msg;
+
+ memset(msg.buf, 0, BT_AUDIO_IPC_PACKET_SIZE);
+ msg.start_req.h.msg_type = BT_STREAMSTART_REQ;
+
+ e = bt_audioservice_send(u->audioservice_fd, &msg.start_req.h);
+ if (e < 0) {
+ pa_log_error("Failed to send BT_STREAMSTART_REQ");
+ return e;
+ }
+
+ e = bt_audioservice_expect(u->audioservice_fd, &msg.rsp_hdr.msg_h, BT_STREAMSTART_RSP);
+ if (e < 0) {
+ pa_log_error("Failed to expect BT_STREAMSTART_RSP");
+ return e;
+ }
+
+ if (msg.rsp_hdr.posix_errno != 0) {
+ pa_log_error("BT_START failed : %s(%d)", pa_cstrerror(msg.rsp_hdr.posix_errno), msg.rsp_hdr.posix_errno);
+ return -msg.rsp_hdr.posix_errno;
+ }
+
+ e = bt_audioservice_expect(u->audioservice_fd, &msg.streamfd_ind.h, BT_STREAMFD_IND);
+ if (e < 0) {
+ pa_log_error("Failed to expect BT_STREAMFD_IND");
+ return e;
+ }
+
+ if (u->stream_fd >= 0)
+ pa_close(u->stream_fd);
+
+ u->stream_fd = bt_audio_service_get_data_fd(u->audioservice_fd);
+ if (u->stream_fd < 0) {
+ pa_log_error("Failed to get data fd: %s (%d)",pa_cstrerror(errno), errno);
+ return -errno;
+ }
+
+ if (u->transport == BT_CAPABILITIES_TRANSPORT_A2DP) {
+ if (pa_socket_set_sndbuf(u->stream_fd, 10U*u->link_mtu) < 0) {
+ pa_log_error("Failed to set socket options for A2DP: %s (%d)",pa_cstrerror(errno), errno);
+ return -errno;
+ }
+ }
+
+// if (setsockopt(u->stream_fd, SOL_SCO, SCO_TXBUFS, &period_count, sizeof(period_count)) == 0)
+// return 0;
+// if (setsockopt(u->stream_fd, SOL_SCO, SO_SNDBUF, &period_count, sizeof(period_count)) == 0)
+// return 0;
+// /* FIXME : handle error codes */
+ pa_make_fd_nonblock(u->stream_fd);
+// pa_make_socket_low_delay(u->stream_fd);
+
+ return 0;
+}
+
+static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
+ struct userdata *u = PA_SINK(o)->userdata;
+
+ pa_log_debug("got message: %d", code);
+ switch (code) {
+
+ case PA_SINK_MESSAGE_SET_STATE:
+ switch ((pa_sink_state_t) PA_PTR_TO_UINT(data)) {
+ case PA_SINK_SUSPENDED:
+ pa_assert(PA_SINK_IS_OPENED(u->sink->thread_info.state));
+ pa_smoother_pause(u->smoother, pa_rtclock_usec());
+ break;
+ case PA_SINK_IDLE:
+ case PA_SINK_RUNNING:
+ if (u->sink->thread_info.state == PA_SINK_SUSPENDED)
+ pa_smoother_resume(u->smoother, pa_rtclock_usec());
+ break;
+ case PA_SINK_UNLINKED:
+ case PA_SINK_INIT:
+ ;
+ }
+ break;
+
+ case PA_SINK_MESSAGE_GET_LATENCY: {
+ pa_usec_t w, r;
+/* r = pa_smoother_get(u->smoother, pa_rtclock_usec()); */
+/* /\* w = pa_bytes_to_usec(u->offset + (uint64_t) u->memchunk.length, &u->sink->sample_spec); *\/ */
+ *((pa_usec_t*) data) = /*w > r ? w - r :*/ 0;
+ return 0;
+ }
+
+ }
+
+ return pa_sink_process_msg(o, code, data, offset, chunk);
+}
+
+static int sco_process_render(struct userdata *u) {
+ void *p;
+ int ret = 0;
+ pa_memchunk memchunk;
+
+ pa_sink_render_full(u->sink, u->block_size, &memchunk);
+
+ p = pa_memblock_acquire(memchunk.memblock);
+
+ for (;;) {
+ ssize_t l;
+
+ l = pa_loop_write(u->stream_fd, (uint8_t*) p, memchunk.length, NULL);
+ pa_log_debug("Memblock written to socket: %li bytes", (long) l);
+
+ pa_assert(l != 0);
+
+ if (l > 0) {
+ u->offset += (uint64_t) l;
+ break;
+ }
+
+ if (errno == EINTR)
+ pa_log_debug("EINTR");
+ else if (errno == EAGAIN)
+ pa_log_debug("EAGAIN");
+ else {
+ pa_log_error("Failed to write data to FIFO: %s", pa_cstrerror(errno));
+ ret = -1;
+ break;
+ }
+ }
+
+ pa_memblock_release(memchunk.memblock);
+ pa_memblock_unref(memchunk.memblock);
+
+ return ret;
+}
+
+static int a2dp_process_render(struct userdata *u) {
+ int written;
+
+ struct bt_a2dp *a2dp = &u->a2dp;
+ struct rtp_header *header = (void *) a2dp->buffer;
+ struct rtp_payload *payload = (void *) (a2dp->buffer + sizeof(*header));
+
+ pa_assert(u);
+
+ do {
+ /* Render some data */
+ int frame_size, encoded;
+ void *p;
+ pa_memchunk memchunk;
+
+ pa_sink_render_full(u->sink, u->block_size, &memchunk);
+
+ p = pa_memblock_acquire(memchunk.memblock);
+
+ frame_size = (uint16_t) sbc_get_frame_length(&a2dp->sbc);
+ pa_log_debug("SBC frame_size: %d", frame_size);
+
+ encoded = sbc_encode(&a2dp->sbc, p, (int) a2dp->codesize, a2dp->buffer + a2dp->count,
+ (int) (sizeof(a2dp->buffer) - a2dp->count), &written);
+ pa_log_debug("SBC: encoded: %d; written: %d", encoded, written);
+
+ pa_memblock_release(memchunk.memblock);
+ pa_memblock_unref(memchunk.memblock);
+
+ if (encoded <= 0) {
+ pa_log_error("SBC encoding error (%d)", encoded);
+ return -1;
+ }
+
+ a2dp->count += (size_t) written;
+ a2dp->frame_count++;
+ a2dp->samples += (unsigned) encoded / frame_size;
+ a2dp->total_samples += (unsigned) encoded / frame_size;
+
+ } while (a2dp->count + (size_t) written <= u->link_mtu);
+
+ /* write it to the fifo */
+ memset(a2dp->buffer, 0, sizeof(*header) + sizeof(*payload));
+ payload->frame_count = a2dp->frame_count;
+ header->v = 2;
+ header->pt = 1;
+ header->sequence_number = htons(a2dp->seq_num);
+ header->timestamp = htonl(a2dp->total_samples);
+ header->ssrc = htonl(1);
+
+ for (;;) {
+ ssize_t l;
+
+ l = pa_loop_write(u->stream_fd, a2dp->buffer, a2dp->count, NULL);
+ pa_log_debug("avdtp_write: requested %lu bytes; written %li bytes", (unsigned long) a2dp->count, (long) l);
+
+ pa_assert(l != 0);
+
+ if (l > 0)
+ break;
+
+ if (errno == EINTR)
+ pa_log_debug("EINTR");
+ else if (errno == EAGAIN)
+ pa_log_debug("EAGAIN");
+ else {
+ pa_log_error("Failed to write data to FIFO: %s", pa_cstrerror(errno));
+ return -1;
+ }
+ }
+
+ u->offset += a2dp->codesize*a2dp->frame_count;
+
+ /* Reset buffer of data to send */
+ a2dp->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload);
+ a2dp->frame_count = 0;
+ a2dp->samples = 0;
+ a2dp->seq_num++;
+
+ return 0;
+}
+
+static void thread_func(void *userdata) {
+ struct userdata *u = userdata;
+
+ pa_assert(u);
+
+ pa_log_debug("IO Thread starting up");
+
+ if (u->core->realtime_scheduling)
+ pa_make_realtime(u->core->realtime_priority);
+
+ pa_thread_mq_install(&u->thread_mq);
+ pa_rtpoll_install(u->rtpoll);
+
+ pa_smoother_set_time_offset(u->smoother, pa_rtclock_usec());
+
+ for (;;) {
+ int ret, l;
+ struct pollfd *pollfd;
+ uint64_t n;
+ pa_usec_t usec;
+
+ if (PA_SINK_IS_OPENED(u->sink->thread_info.state))
+ if (u->sink->thread_info.rewind_requested)
+ pa_sink_process_rewind(u->sink, 0);
+
+ pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
+
+ if (PA_SINK_IS_OPENED(u->sink->thread_info.state) && pollfd->revents) {
+ if (u->transport == BT_CAPABILITIES_TRANSPORT_A2DP) {
+ if ((l = a2dp_process_render(u)) < 0)
+ goto fail;
+ } else {
+ if ((l = sco_process_render(u)) < 0)
+ goto fail;
+ }
+ pollfd->revents = 0;
+
+ /* feed the time smoother */
+ n = u->offset;
+ if (ioctl(u->stream_fd, SIOCOUTQ, &l) >= 0 && l > 0)
+ n -= (uint64_t) l;
+ usec = pa_bytes_to_usec(n, &u->sink->sample_spec);
+ if (usec > u->latency)
+ usec -= u->latency;
+ else
+ usec = 0;
+ pa_smoother_put(u->smoother, pa_rtclock_usec(), usec);
+ }
+
+ /* Hmm, nothing to do. Let's sleep */
+ pa_log_debug("IO thread going to sleep");
+ pollfd->events = (short) (PA_SINK_IS_OPENED(u->sink->thread_info.state) ? POLLOUT : 0);
+ if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0) {
+ pa_log_error("rtpoll_run < 0");
+ goto fail;
+ }
+ pa_log_debug("IO thread waking up");
+
+ if (ret == 0) {
+ pa_log_debug("rtpoll_run == 0");
+ goto finish;
+ }
+
+ pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
+ if (pollfd->revents & ~POLLOUT) {
+ pa_log_error("FIFO shutdown.");
+ goto fail;
+ }
+ }
+
+fail:
+ /* If this was no regular exit from the loop we have to continue processing messages until we receive PA_MESSAGE_SHUTDOWN */
+ pa_log_debug("IO thread failed");
+ pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
+ pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
+
+finish:
+ pa_log_debug("IO thread shutting down");
+}
+
+int pa__init(pa_module* m) {
+ int e;
+ pa_modargs *ma;
+ uint32_t channels;
+ pa_sink_new_data data;
+ struct pollfd *pollfd;
+ struct userdata *u;
+
+ pa_assert(m);
+ m->userdata = u = pa_xnew0(struct userdata, 1);
+ u->module = m;
+ u->core = m->core;
+ u->audioservice_fd = -1;
+ u->stream_fd = -1;
+ u->transport = (uint8_t) -1;
+ u->offset = 0;
+ u->latency = 0;
+ u->a2dp.sbc_initialized = FALSE;
+ u->smoother = pa_smoother_new(PA_USEC_PER_SEC, PA_USEC_PER_SEC*2, TRUE, 10);
+ u->rtpoll = pa_rtpoll_new();
+ pa_thread_mq_init(&u->thread_mq, u->core->mainloop, u->rtpoll);
+ u->rtpoll_item = NULL;
+ u->ss = m->core->default_sample_spec;
+
+ if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
+ pa_log_error("Failed to parse module arguments");
+ goto fail;
+ }
+ if (!(u->name = pa_xstrdup(pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME)))) {
+ pa_log_error("Failed to get device name from module arguments");
+ goto fail;
+ }
+ if (!(u->addr = pa_xstrdup(pa_modargs_get_value(ma, "address", NULL)))) {
+ pa_log_error("Failed to get device address from module arguments");
+ goto fail;
+ }
+ if (!(u->profile = pa_xstrdup(pa_modargs_get_value(ma, "profile", NULL)))) {
+ pa_log_error("Failed to get profile from module arguments");
+ goto fail;
+ }
+ if (pa_modargs_get_value_u32(ma, "rate", &u->ss.rate) < 0) {
+ pa_log_error("Failed to get rate from module arguments");
+ goto fail;
+ }
+
+ channels = u->ss.channels;
+ if (pa_modargs_get_value_u32(ma, "channels", &channels) < 0) {
+ pa_log_error("Failed to get channels from module arguments");
+ goto fail;
+ }
+ u->ss.channels = (uint8_t) channels;
+
+ /* connect to the bluez audio service */
+ u->audioservice_fd = bt_audio_service_open();
+ if (u->audioservice_fd <= 0) {
+ pa_log_error("Couldn't connect to bluetooth audio service");
+ goto fail;
+ }
+ pa_log_debug("Connected to the bluetooth audio service");
+
+ /* queries device capabilities */
+ e = bt_getcaps(u);
+ if (e < 0) {
+ pa_log_error("Failed to get device capabilities");
+ goto fail;
+ }
+ pa_log_debug("Got device capabilities");
+
+ /* configures the connection */
+ e = bt_setconf(u);
+ if (e < 0) {
+ pa_log_error("Failed to set config");
+ goto fail;
+ }
+ pa_log_debug("Connection to the device configured");
+
+ /* gets the device socket */
+ e = bt_getstreamfd(u);
+ if (e < 0) {
+ pa_log_error("Failed to get stream fd (%d)", e);
+ goto fail;
+ }
+ pa_log_debug("Got the device socket");
+
+ /* create sink */
+ pa_sink_new_data_init(&data);
+ data.driver = __FILE__;
+ data.module = m;
+ pa_sink_new_data_set_name(&data, u->name);
+ pa_sink_new_data_set_sample_spec(&data, &u->ss);
+ pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->name);
+ pa_proplist_setf(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Bluetooth %s '%s' (%s)", u->strtransport, u->name, u->addr);
+ pa_proplist_sets(data.proplist, "bluetooth.protocol", u->profile);
+ pa_proplist_setf(data.proplist, PA_PROP_DEVICE_API, "bluez");
+ pa_proplist_setf(data.proplist, PA_PROP_DEVICE_CLASS, "sound");
+ pa_proplist_setf(data.proplist, PA_PROP_DEVICE_CONNECTOR, "bluetooth");
+/* pa_proplist_setf(data.proplist, PA_PROP_DEVICE_FORM_FACTOR, "headset"); /\*FIXME*\/ */
+/* pa_proplist_setf(data.proplist, PA_PROP_DEVICE_VENDOR_PRODUCT_ID, "product_id"); /\*FIXME*\/ */
+/* pa_proplist_setf(data.proplist, PA_PROP_DEVICE_SERIAL, "serial"); /\*FIXME*\/ */
+ u->sink = pa_sink_new(m->core, &data, PA_SINK_HARDWARE|PA_SINK_LATENCY);
+ pa_sink_new_data_done(&data);
+ if (!u->sink) {
+ pa_log_error("Failed to create sink");
+ goto fail;
+ }
+ u->sink->userdata = u;
+ u->sink->parent.process_msg = sink_process_msg;
+ pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
+ pa_sink_set_rtpoll(u->sink, u->rtpoll);
+
+ u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1);
+ pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
+ pollfd->fd = u->stream_fd;
+ pollfd->events = pollfd->revents = 0;
+
+ /* start rt thread */
+ if (!(u->thread = pa_thread_new(thread_func, u))) {
+ pa_log_error("Failed to create IO thread");
+ goto fail;
+ }
+ pa_sink_put(u->sink);
+
+ pa_modargs_free(ma);
+ return 0;
+
+fail:
+ if (ma)
+ pa_modargs_free(ma);
+
+ pa__done(m);
+ return -1;
+}
+
+void pa__done(pa_module *m) {
+ struct userdata *u;
+ pa_assert(m);
+
+ if (!(u = m->userdata))
+ return;
+
+ if (u->sink)
+ pa_sink_unlink(u->sink);
+
+ if (u->thread) {
+ pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
+ pa_thread_free(u->thread);
+ }
+
+ if (u->sink)
+ pa_sink_unref(u->sink);
+
+ pa_thread_mq_done(&u->thread_mq);
+
+ if (u->rtpoll_item)
+ pa_rtpoll_item_free(u->rtpoll_item);
+
+ if (u->rtpoll)
+ pa_rtpoll_free(u->rtpoll);
+
+ if (u->smoother)
+ pa_smoother_free(u->smoother);
+
+ pa_xfree(u->name);
+ pa_xfree(u->addr);
+ pa_xfree(u->profile);
+ pa_xfree(u->strtransport);
+
+ if (u->stream_fd >= 0)
+ pa_close(u->stream_fd);
+
+ if (u->audioservice_fd >= 0)
+ pa_close(u->audioservice_fd);
+
+ pa_xfree(u);
+}
diff --git a/src/modules/bluetooth/module-bluetooth-discover.c b/src/modules/bluetooth/module-bluetooth-discover.c
new file mode 100644
index 00000000..14944318
--- /dev/null
+++ b/src/modules/bluetooth/module-bluetooth-discover.c
@@ -0,0 +1,928 @@
+/***
+ This file is part of PulseAudio.
+
+ Copyright 2008 Joao Paulo Rechi Vita
+
+ PulseAudio is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ PulseAudio is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PulseAudio; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <pulse/xmalloc.h>
+#include <pulsecore/module.h>
+#include <pulsecore/modargs.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/llist.h>
+#include <pulsecore/core-util.h>
+
+#include "dbus-util.h"
+#include "module-bluetooth-discover-symdef.h"
+
+PA_MODULE_AUTHOR("Joao Paulo Rechi Vita");
+PA_MODULE_DESCRIPTION("Detect available bluetooth audio devices and load bluetooth audio drivers");
+PA_MODULE_VERSION(PACKAGE_VERSION);
+PA_MODULE_USAGE("");
+
+#define HSP_HS_UUID "00001108-0000-1000-8000-00805F9B34FB"
+#define HFP_HS_UUID "0000111E-0000-1000-8000-00805F9B34FB"
+#define A2DP_SOURCE_UUID "0000110A-0000-1000-8000-00805F9B34FB"
+#define A2DP_SINK_UUID "0000110B-0000-1000-8000-00805F9B34FB"
+
+struct uuid {
+ char *uuid;
+ PA_LLIST_FIELDS(struct uuid);
+};
+
+struct device {
+ char *name;
+ char *object_path;
+ int paired;
+ struct adapter *adapter;
+ char *alias;
+ int connected;
+ PA_LLIST_HEAD(struct uuid, uuid_list);
+ char *address;
+ int class;
+ int trusted;
+ const char *audio_profile;
+ uint32_t module_index;
+ PA_LLIST_FIELDS(struct device);
+};
+
+struct adapter {
+ char *object_path;
+ char *name;
+ char *mode;
+ char *address;
+ PA_LLIST_HEAD(struct device, device_list);
+ PA_LLIST_FIELDS(struct adapter);
+};
+
+struct userdata {
+ pa_module *module;
+ pa_dbus_connection *conn;
+ PA_LLIST_HEAD(struct adapter, adapter_list);
+};
+
+static struct uuid *uuid_new(const char *uuid) {
+ struct uuid *node;
+
+ node = pa_xnew(struct uuid, 1);
+ node->uuid = pa_xstrdup(uuid);
+ PA_LLIST_INIT(struct uuid, node);
+
+ return node;
+}
+
+static void uuid_free(struct uuid *uuid) {
+ pa_assert(uuid);
+
+ pa_xfree(uuid->uuid);
+ pa_xfree(uuid);
+}
+
+static struct device *device_new(struct adapter *adapter, const char *object_path) {
+ struct device *node;
+
+ node = pa_xnew(struct device, 1);
+ node->name = NULL;
+ node->object_path = pa_xstrdup(object_path);
+ node->paired = -1;
+ node->adapter = adapter;
+ node->alias = NULL;
+ node->connected = -1;
+ PA_LLIST_HEAD_INIT(struct uuid, node->uuid_list);
+ node->address = NULL;
+ node->class = -1;
+ node->trusted = -1;
+ node->audio_profile = NULL;
+ node->module_index = PA_INVALID_INDEX;
+ PA_LLIST_INIT(struct device, node);
+
+ return node;
+}
+
+static void device_free(struct device *device) {
+ struct uuid *i;
+
+ pa_assert(device);
+
+ while ((i = device->uuid_list)) {
+ PA_LLIST_REMOVE(struct uuid, device->uuid_list, i);
+ uuid_free(i);
+ }
+
+ pa_xfree(device->name);
+ pa_xfree(device->object_path);
+ pa_xfree(device->alias);
+ pa_xfree(device->address);
+ pa_xfree(device);
+}
+
+static struct adapter *adapter_new(const char *object_path) {
+ struct adapter *node;
+
+ node = pa_xnew(struct adapter, 1);
+ node->object_path = pa_xstrdup(object_path);
+ node->mode = NULL;
+ node->address = NULL;
+ node->name = NULL;
+
+ PA_LLIST_HEAD_INIT(struct device, node->device_list);
+ PA_LLIST_INIT(struct adapter, node);
+
+ return node;
+}
+
+static void adapter_free(struct adapter *adapter) {
+ struct device *i;
+
+ pa_assert(adapter);
+
+ while ((i = adapter->device_list)) {
+ PA_LLIST_REMOVE(struct device, adapter->device_list, i);
+ device_free(i);
+ }
+
+ pa_xfree(adapter->object_path);
+ pa_xfree(adapter->mode);
+ pa_xfree(adapter->address);
+ pa_xfree(adapter->name);
+ pa_xfree(adapter);
+}
+
+static struct adapter* adapter_find(struct userdata *u, const char *path) {
+ struct adapter *i;
+
+ for (i = u->adapter_list; i; i = i->next)
+ if (pa_streq(i->object_path, path))
+ return i;
+
+ return NULL;
+}
+
+static struct device* device_find(struct userdata *u, const char *path) {
+ struct adapter *j;
+ struct device *i;
+
+ for (j = u->adapter_list; j; j = j->next)
+ for (i = j->device_list; i; i = i->next)
+ if (pa_streq(i->object_path, path))
+ return i;
+
+ return NULL;
+}
+
+static const char *yes_no_na(int b) {
+ if (b < 0)
+ return "n/a";
+
+ return pa_yes_no(b);
+}
+
+static void print_devices(struct adapter *a) {
+ struct device *i;
+
+ pa_assert(a);
+
+ for (i = a->device_list; i; i = i->next) {
+ struct uuid *j;
+
+ if (pa_streq(i->object_path, "/DEVICE_HEAD"))
+ continue;
+
+ pa_log_debug("\t[ %s ]\n"
+ "\t\tName = %s\n"
+ "\t\tPaired = %s\n"
+ "\t\tAdapter = %s\n"
+ "\t\tAlias = %s\n"
+ "\t\tConnected = %s\n"
+ "\t\tAudio = %s\n",
+ i->object_path,
+ pa_strnull(i->name),
+ yes_no_na(i->paired),
+ i->adapter->object_path,
+ pa_strnull(i->alias),
+ yes_no_na(i->connected),
+ pa_strnull(i->audio_profile));
+
+ pa_log_debug("\t\tUUIDs = ");
+ for (j = i->uuid_list; j; j = j->next) {
+
+ if (pa_streq(j->uuid, "UUID_HEAD"))
+ continue;
+
+ pa_log_debug("\t\t %s", j->uuid);
+ }
+
+ pa_log_debug("\t\tAddress = %s\n"
+ "\t\tClass = 0x%x\n"
+ "\t\tTrusted = %s",
+ i->address,
+ i->class,
+ yes_no_na(i->trusted));
+ }
+}
+
+static void print_adapters(struct userdata *u) {
+ struct adapter *i;
+
+ pa_assert(u);
+
+ for (i = u->adapter_list; i; i = i->next) {
+
+ if (pa_streq(i->object_path, "/ADAPTER_HEAD"))
+ continue;
+
+ pa_log_debug(
+ "[ %s ]\n"
+ "\tName = %s\n"
+ "\tMode = %s\n"
+ "\tAddress = %s\n",
+ i->object_path,
+ pa_strnull(i->name),
+ pa_strnull(i->mode),
+ pa_strnull(i->address));
+
+ print_devices(i);
+ }
+}
+
+static const char *strip_object_path(const char *op) {
+ const char *slash;
+
+ if ((slash = strrchr(op, '/')))
+ return slash+1;
+
+ return op;
+}
+
+static void load_module_for_device(struct userdata *u, struct device *d) {
+ char *args;
+ pa_module *m;
+
+ pa_assert(u);
+ pa_assert(d);
+
+ /* Check whether we already loaded a module for this device */
+ if (d->module_index != PA_INVALID_INDEX &&
+ pa_idxset_get_by_index(u->module->core->modules, d->module_index))
+ return;
+
+ /* Check whether this is an audio device */
+ if (!d->audio_profile) {
+ pa_log_debug("Ignoring %s since it is not an audio device.", d->object_path);
+ return;
+ }
+
+ args = pa_sprintf_malloc("sink_name=%s address=%s profile=%s", strip_object_path(d->object_path), d->address, d->audio_profile);
+ m = pa_module_load(u->module->core, "module-bluetooth-device", args);
+ pa_xfree(args);
+
+ if (!m) {
+ pa_log_debug("Failed to load module for device %s", d->object_path);
+ return;
+ }
+
+ d->module_index = m->index;
+}
+
+static void load_modules(struct userdata *u) {
+ struct device *d;
+ struct adapter *a;
+
+ pa_assert(u);
+
+ for (a = u->adapter_list; a; a = a->next)
+ for (d = a->device_list; d; d = d->next)
+ load_module_for_device(u, d);
+}
+
+static int parse_adapter_property(struct userdata *u, struct adapter *a, DBusMessageIter *i) {
+ const char *key;
+ DBusMessageIter variant_i;
+
+ pa_assert(u);
+ pa_assert(a);
+ pa_assert(i);
+
+ if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING) {
+ pa_log("Property name not a string.");
+ return -1;
+ }
+
+ dbus_message_iter_get_basic(i, &key);
+
+ if (!dbus_message_iter_next(i)) {
+ pa_log("Property value missing");
+ return -1;
+ }
+
+ if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_VARIANT) {
+ pa_log("Property value not a variant.");
+ return -1;
+ }
+
+ dbus_message_iter_recurse(i, &variant_i);
+
+ if (dbus_message_iter_get_arg_type(&variant_i) == DBUS_TYPE_STRING) {
+ const char *value;
+ dbus_message_iter_get_basic(&variant_i, &value);
+
+ if (pa_streq(key, "Mode")) {
+ pa_xfree(a->mode);
+ a->mode = pa_xstrdup(value);
+ } else if (pa_streq(key, "Address")) {
+ pa_xstrdup(a->address);
+ a->address = pa_xstrdup(value);
+ } else if (pa_streq(key, "Name")) {
+ pa_xfree(a->name);
+ a->name = pa_xstrdup(value);
+ }
+ }
+
+ return 0;
+}
+
+static int get_adapter_properties(struct userdata *u, struct adapter *a) {
+ DBusError e;
+ DBusMessage *m = NULL, *r = NULL;
+ DBusMessageIter arg_i, element_i;
+ int ret = -1;
+
+ pa_assert(u);
+ pa_assert(a);
+ dbus_error_init(&e);
+
+ pa_assert_se(m = dbus_message_new_method_call("org.bluez", a->object_path, "org.bluez.Adapter", "GetProperties"));
+
+ r = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(u->conn), m, -1, &e);
+
+ if (!r) {
+ pa_log("org.bluez.Adapter.GetProperties failed: %s", e.message);
+ goto finish;
+ }
+
+ if (!dbus_message_iter_init(r, &arg_i)) {
+ pa_log("org.bluez.Adapter.GetProperties reply has no arguments");
+ goto finish;
+ }
+
+ if (dbus_message_iter_get_arg_type(&arg_i) != DBUS_TYPE_ARRAY) {
+ pa_log("org.bluez.Adapter.GetProperties argument is not an array");
+ goto finish;
+ }
+
+ dbus_message_iter_recurse(&arg_i, &element_i);
+ while (dbus_message_iter_get_arg_type(&element_i) != DBUS_TYPE_INVALID) {
+
+ if (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter dict_i;
+
+ dbus_message_iter_recurse(&element_i, &dict_i);
+
+ if (parse_adapter_property(u, a, &dict_i) < 0)
+ goto finish;
+ }
+
+ if (!dbus_message_iter_next(&element_i))
+ break;
+ }
+
+ ret = 0;
+
+finish:
+ if (m)
+ dbus_message_unref(m);
+ if (r)
+ dbus_message_unref(r);
+
+ dbus_error_free(&e);
+
+ return ret;
+}
+
+static int detect_adapters(struct userdata *u) {
+ DBusError e;
+ DBusMessage *m = NULL, *r = NULL;
+ DBusMessageIter arg_i, element_i;
+ struct adapter *adapter_list_i;
+ int ret = -1;
+
+ pa_assert(u);
+ dbus_error_init(&e);
+
+ /* get adapters */
+ pa_assert_se(m = dbus_message_new_method_call("org.bluez", "/", "org.bluez.Manager", "ListAdapters"));
+ r = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(u->conn), m, -1, &e);
+
+ if (!r) {
+ pa_log("org.bluez.Manager.ListAdapters failed: %s", e.message);
+ goto finish;
+ }
+
+ if (!dbus_message_iter_init(r, &arg_i)) {
+ pa_log("org.bluez.Manager.ListAdapters reply has no arguments");
+ goto finish;
+ }
+
+ if (dbus_message_iter_get_arg_type(&arg_i) != DBUS_TYPE_ARRAY) {
+ pa_log("org.bluez.Manager.ListAdapters argument is not an array");
+ goto finish;
+ }
+
+ dbus_message_iter_recurse(&arg_i, &element_i);
+ while (dbus_message_iter_get_arg_type(&element_i) != DBUS_TYPE_INVALID) {
+ if (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_OBJECT_PATH) {
+
+ struct adapter *node;
+ const char *value;
+
+ dbus_message_iter_get_basic(&element_i, &value);
+ node = adapter_new(value);
+ PA_LLIST_PREPEND(struct adapter, u->adapter_list, node);
+ }
+
+ if (!dbus_message_iter_next(&element_i))
+ break;
+ }
+
+ ret = 0;
+
+ /* get adapter properties */
+ for (adapter_list_i = u->adapter_list; adapter_list_i; adapter_list_i = adapter_list_i->next)
+ get_adapter_properties(u, adapter_list_i);
+
+finish:
+ if (m)
+ dbus_message_unref(m);
+ if (r)
+ dbus_message_unref(r);
+
+ dbus_error_free(&e);
+ return ret;
+}
+
+static int parse_device_property(struct userdata *u, struct device *d, DBusMessageIter *i) {
+ const char *key;
+ DBusMessageIter variant_i;
+
+ pa_assert(u);
+ pa_assert(d);
+ pa_assert(i);
+
+ if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING) {
+ pa_log("Property name not a string.");
+ return -1;
+ }
+
+ dbus_message_iter_get_basic(i, &key);
+
+ if (!dbus_message_iter_next(i)) {
+ pa_log("Property value missing");
+ return -1;
+ }
+
+ if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_VARIANT) {
+ pa_log("Property value not a variant.");
+ return -1;
+ }
+
+ dbus_message_iter_recurse(i, &variant_i);
+
+ pa_log_debug("Parsing device property %s", key);
+
+ switch (dbus_message_iter_get_arg_type(&variant_i)) {
+
+ case DBUS_TYPE_STRING: {
+
+ const char *value;
+ dbus_message_iter_get_basic(&variant_i, &value);
+
+ if (pa_streq(key, "Name")) {
+ pa_xfree(d->name);
+ d->name = pa_xstrdup(value);
+ } else if (pa_streq(key, "Alias")) {
+ pa_xfree(d->alias);
+ d->alias = pa_xstrdup(value);
+ } else if (pa_streq(key, "Address")) {
+ pa_xfree(d->address);
+ d->address = pa_xstrdup(value);
+ }
+
+ break;
+ }
+
+ case DBUS_TYPE_BOOLEAN: {
+
+ dbus_bool_t value;
+ dbus_message_iter_get_basic(&variant_i, &value);
+
+ if (pa_streq(key, "Paired"))
+ d->paired = !!value;
+ else if (pa_streq(key, "Connected"))
+ d->connected = !!value;
+ else if (pa_streq(key, "Trusted"))
+ d->trusted = !!value;
+
+ break;
+ }
+
+ case DBUS_TYPE_UINT32: {
+
+ uint32_t value;
+ dbus_message_iter_get_basic(&variant_i, &value);
+
+ if (pa_streq(key, "Class"))
+ d->class = (int) value;
+
+ break;
+ }
+
+ case DBUS_TYPE_ARRAY: {
+
+ DBusMessageIter ai;
+ dbus_message_iter_recurse(&variant_i, &ai);
+
+ if (dbus_message_iter_get_arg_type(&ai) == DBUS_TYPE_STRING &&
+ pa_streq(key, "UUIDs")) {
+
+ d->audio_profile = NULL;
+
+ while (dbus_message_iter_get_arg_type(&ai) != DBUS_TYPE_INVALID) {
+ struct uuid *node;
+ const char *value;
+
+ dbus_message_iter_get_basic(&ai, &value);
+ node = uuid_new(value);
+ PA_LLIST_PREPEND(struct uuid, d->uuid_list, node);
+
+ if ((strcasecmp(value, A2DP_SOURCE_UUID) == 0) ||
+ (strcasecmp(value, A2DP_SINK_UUID) == 0))
+ d->audio_profile = "a2dp";
+ else if (((strcasecmp(value, HSP_HS_UUID) == 0) ||
+ (strcasecmp(value, HFP_HS_UUID) == 0)) &&
+ !d->audio_profile)
+ d->audio_profile = "hsp";
+
+ if (!dbus_message_iter_next(&ai))
+ break;
+ }
+ }
+
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int get_device_properties(struct userdata *u, struct device *d) {
+ DBusError e;
+ DBusMessage *m = NULL, *r = NULL;
+ DBusMessageIter arg_i, element_i;
+ int ret = -1;
+
+ pa_assert(u);
+ pa_assert(d);
+
+ dbus_error_init(&e);
+
+ pa_assert_se(m = dbus_message_new_method_call("org.bluez", d->object_path, "org.bluez.Device", "GetProperties"));
+
+ r = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(u->conn), m, -1, &e);
+
+ if (!r) {
+ pa_log("org.bluez.Device.GetProperties failed: %s", e.message);
+ goto finish;
+ }
+
+ if (!dbus_message_iter_init(r, &arg_i)) {
+ pa_log("org.bluez.Device.GetProperties reply has no arguments");
+ goto finish;
+ }
+
+ if (dbus_message_iter_get_arg_type(&arg_i) != DBUS_TYPE_ARRAY) {
+ pa_log("org.bluez.Device.GetProperties argument is not an array");
+ goto finish;
+ }
+
+ dbus_message_iter_recurse(&arg_i, &element_i);
+ while (dbus_message_iter_get_arg_type(&element_i) != DBUS_TYPE_INVALID) {
+
+ if (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_DICT_ENTRY) {
+ DBusMessageIter dict_i;
+
+ dbus_message_iter_recurse(&element_i, &dict_i);
+
+ if (parse_device_property(u, d, &dict_i) < 0)
+ goto finish;
+ }
+
+ if (!dbus_message_iter_next(&element_i))
+ break;
+ }
+
+ ret = 0;
+
+finish:
+ if (m)
+ dbus_message_unref(m);
+ if (r)
+ dbus_message_unref(r);
+
+ dbus_error_free(&e);
+
+ return ret;
+}
+
+static int detect_devices(struct userdata *u) {
+ DBusError e;
+ DBusMessage *m = NULL, *r = NULL;
+ DBusMessageIter arg_i, element_i;
+ struct adapter *adapter_list_i;
+ struct device *device_list_i;
+ const char *value;
+ int ret = -1;
+
+ pa_assert(u);
+ dbus_error_init(&e);
+
+ /* get devices of each adapter */
+ for (adapter_list_i = u->adapter_list; adapter_list_i; adapter_list_i = adapter_list_i->next) {
+
+ pa_assert_se(m = dbus_message_new_method_call("org.bluez", adapter_list_i->object_path, "org.bluez.Adapter", "ListDevices"));
+
+ r = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(u->conn), m, -1, &e);
+
+ if (!r) {
+ pa_log("org.bluez.Adapter.ListDevices failed: %s", e.message);
+ goto finish;
+ }
+
+ if (!dbus_message_iter_init(r, &arg_i)) {
+ pa_log("org.bluez.Adapter.ListDevices reply has no arguments");
+ goto finish;
+ }
+
+ if (dbus_message_iter_get_arg_type(&arg_i) != DBUS_TYPE_ARRAY) {
+ pa_log("org.bluez.Adapter.ListDevices argument is not an array");
+ goto finish;
+ }
+
+ dbus_message_iter_recurse(&arg_i, &element_i);
+ while (dbus_message_iter_get_arg_type(&element_i) != DBUS_TYPE_INVALID) {
+ if (dbus_message_iter_get_arg_type(&element_i) == DBUS_TYPE_OBJECT_PATH) {
+ struct device *node;
+ dbus_message_iter_get_basic(&element_i, &value);
+ node = device_new(adapter_list_i, value);
+ PA_LLIST_PREPEND(struct device, adapter_list_i->device_list, node);
+ }
+
+ if (!dbus_message_iter_next(&element_i))
+ break;
+ }
+ }
+
+ /* get device properties */
+ for (adapter_list_i = u->adapter_list; adapter_list_i; adapter_list_i = adapter_list_i->next)
+ for (device_list_i = adapter_list_i->device_list; device_list_i; device_list_i = device_list_i->next)
+ get_device_properties(u, device_list_i);
+
+ ret = 0;
+
+finish:
+ if (m)
+ dbus_message_unref(m);
+ if (r)
+ dbus_message_unref(r);
+
+ dbus_error_free(&e);
+
+ return ret;
+}
+
+static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *msg, void *userdata) {
+ DBusMessageIter arg_i;
+ DBusError err;
+ const char *value;
+ struct userdata *u;
+
+ pa_assert(bus);
+ pa_assert(msg);
+ pa_assert(userdata);
+ u = userdata;
+
+ dbus_error_init(&err);
+
+ pa_log_debug("dbus: interface=%s, path=%s, member=%s\n",
+ dbus_message_get_interface(msg),
+ dbus_message_get_path(msg),
+ dbus_message_get_member(msg));
+
+ if (dbus_message_is_signal(msg, "org.bluez.Manager", "AdapterAdded")) {
+
+ if (!dbus_message_iter_init(msg, &arg_i))
+ pa_log("dbus: message has no parameters");
+ else if (dbus_message_iter_get_arg_type(&arg_i) != DBUS_TYPE_OBJECT_PATH)
+ pa_log("dbus: argument is not object path");
+ else {
+ struct adapter *node;
+
+ dbus_message_iter_get_basic(&arg_i, &value);
+ pa_log_debug("hcid: adapter %s added", value);
+
+ node = adapter_new(value);
+ PA_LLIST_PREPEND(struct adapter, u->adapter_list, node);
+
+ get_adapter_properties(u, node);
+ }
+
+ } else if (dbus_message_is_signal(msg, "org.bluez.Manager", "AdapterRemoved")) {
+ if (!dbus_message_iter_init(msg, &arg_i))
+ pa_log("dbus: message has no parameters");
+ else if (dbus_message_iter_get_arg_type(&arg_i) != DBUS_TYPE_OBJECT_PATH)
+ pa_log("dbus: argument is not object path");
+ else {
+ struct adapter *a;
+
+ dbus_message_iter_get_basic(&arg_i, &value);
+ pa_log_debug("hcid: adapter %s removed", value);
+
+ if ((a = adapter_find(u, value))) {
+ PA_LLIST_REMOVE(struct adapter, u->adapter_list, a);
+ adapter_free(a);
+ }
+ }
+
+ } else if (dbus_message_is_signal(msg, "org.bluez.Adapter", "PropertyChanged")) {
+
+ if (!dbus_message_iter_init(msg, &arg_i))
+ pa_log("dbus: message has no parameters");
+ else {
+ struct adapter *a;
+
+ if ((a = adapter_find(u, dbus_message_get_path(msg))))
+ parse_adapter_property(u, a, &arg_i);
+ }
+
+ } else if (dbus_message_is_signal(msg, "org.bluez.Adapter", "DeviceCreated")) {
+
+ if (!dbus_message_iter_init(msg, &arg_i))
+ pa_log("dbus: message has no parameters");
+ else if (dbus_message_iter_get_arg_type(&arg_i) != DBUS_TYPE_OBJECT_PATH)
+ pa_log("dbus: argument is not object path");
+ else {
+ struct adapter *adapter;
+
+ if (!(adapter = adapter_find(u, dbus_message_get_path(msg))))
+ pa_log("dbus: failed to find adapter for object path");
+ else {
+ struct device *node;
+
+ dbus_message_iter_get_basic(&arg_i, &value);
+ pa_log_debug("hcid: device %s created", value);
+
+ node = device_new(adapter, value);
+ PA_LLIST_PREPEND(struct device, adapter->device_list, node);
+
+ get_device_properties(u, node);
+ load_module_for_device(u, node);
+ }
+ }
+
+ } else if (dbus_message_is_signal(msg, "org.bluez.Adapter", "DeviceRemoved")) {
+
+ if (!dbus_message_iter_init(msg, &arg_i))
+ pa_log("dbus: message has no parameters");
+ else if (dbus_message_iter_get_arg_type(&arg_i) != DBUS_TYPE_OBJECT_PATH)
+ pa_log("dbus: argument is not object path");
+ else {
+ struct device *d;
+
+ dbus_message_iter_get_basic(&arg_i, &value);
+ pa_log_debug("hcid: device %s removed", value);
+
+ if ((d = device_find(u, value))) {
+ PA_LLIST_REMOVE(struct device, d->adapter->device_list, d);
+ device_free(d);
+ }
+ }
+
+ } else if (dbus_message_is_signal(msg, "org.bluez.Device", "PropertyChanged")) {
+
+ if (!dbus_message_iter_init(msg, &arg_i))
+ pa_log("dbus: message has no parameters");
+ else {
+ struct device *d;
+
+ if ((d = device_find(u, dbus_message_get_path(msg)))) {
+ parse_device_property(u, d, &arg_i);
+
+ /* Hmm, something changed, let's try to reconnect if we
+ * aren't connected yet */
+ load_module_for_device(u, d);
+ }
+ }
+ }
+
+ dbus_error_free(&err);
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+void pa__done(pa_module* m) {
+ struct userdata *u;
+ struct adapter *i;
+
+ pa_assert(m);
+
+ if (!(u = m->userdata))
+ return;
+
+ while ((i = u->adapter_list)) {
+ PA_LLIST_REMOVE(struct adapter, u->adapter_list, i);
+ adapter_free(i);
+ }
+
+ if (u->conn)
+ pa_dbus_connection_unref(u->conn);
+
+ pa_xfree(u);
+}
+
+int pa__init(pa_module* m) {
+ DBusError err;
+ struct userdata *u;
+
+ pa_assert(m);
+ dbus_error_init(&err);
+
+ m->userdata = u = pa_xnew(struct userdata, 1);
+ u->module = m;
+ PA_LLIST_HEAD_INIT(struct adapter, u->adapter_list);
+
+ /* connect to the bus */
+ u->conn = pa_dbus_bus_get(m->core, DBUS_BUS_SYSTEM, &err);
+ if (dbus_error_is_set(&err) || (u->conn == NULL) ) {
+ pa_log("Failed to get D-Bus connection: %s", err.message);
+ goto fail;
+ }
+
+ /* static detection of bluetooth audio devices */
+ detect_adapters(u);
+ detect_devices(u);
+
+ print_adapters(u);
+ load_modules(u);
+
+ /* dynamic detection of bluetooth audio devices */
+ if (!dbus_connection_add_filter(pa_dbus_connection_get(u->conn), filter_cb, u, NULL)) {
+ pa_log_error("Failed to add filter function");
+ goto fail;
+ }
+
+ dbus_bus_add_match(pa_dbus_connection_get(u->conn), "type='signal',sender='org.bluez',interface='org.bluez.Manager'", &err);
+ if (dbus_error_is_set(&err)) {
+ pa_log_error("Unable to subscribe to org.bluez.Manager signals: %s: %s", err.name, err.message);
+ goto fail;
+ }
+
+ dbus_bus_add_match(pa_dbus_connection_get(u->conn), "type='signal',sender='org.bluez',interface='org.bluez.Adapter'", &err);
+ if (dbus_error_is_set(&err)) {
+ pa_log_error("Unable to subscribe to org.bluez.Adapter signals: %s: %s", err.name, err.message);
+ goto fail;
+ }
+
+ dbus_bus_add_match(pa_dbus_connection_get(u->conn), "type='signal',sender='org.bluez',interface='org.bluez.Device'", &err);
+ if (dbus_error_is_set(&err)) {
+ pa_log_error("Unable to subscribe to org.bluez.Device signals: %s: %s", err.name, err.message);
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ dbus_error_free(&err);
+ pa__done(m);
+
+ return -1;
+}
diff --git a/src/modules/module-bt-proximity.c b/src/modules/bluetooth/module-bluetooth-proximity.c
index f924c3cb..5cca36e5 100644
--- a/src/modules/module-bt-proximity.c
+++ b/src/modules/bluetooth/module-bluetooth-proximity.c
@@ -44,7 +44,7 @@
#include <pulsecore/start-child.h>
#include "dbus-util.h"
-#include "module-bt-proximity-symdef.h"
+#include "module-bluetooth-proximity-symdef.h"
PA_MODULE_AUTHOR("Lennart Poettering");
PA_MODULE_DESCRIPTION("Bluetooth Proximity Volume Control");
diff --git a/src/modules/bt-proximity-helper.c b/src/modules/bluetooth/proximity-helper.c
index 3767f01c..3767f01c 100644
--- a/src/modules/bt-proximity-helper.c
+++ b/src/modules/bluetooth/proximity-helper.c
diff --git a/src/modules/bluetooth/rtp.h b/src/modules/bluetooth/rtp.h
new file mode 100644
index 00000000..690bd43a
--- /dev/null
+++ b/src/modules/bluetooth/rtp.h
@@ -0,0 +1,76 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct rtp_header {
+ uint8_t cc:4;
+ uint8_t x:1;
+ uint8_t p:1;
+ uint8_t v:2;
+
+ uint8_t pt:7;
+ uint8_t m:1;
+
+ uint16_t sequence_number;
+ uint32_t timestamp;
+ uint32_t ssrc;
+ uint32_t csrc[0];
+} __attribute__ ((packed));
+
+struct rtp_payload {
+ uint8_t frame_count:4;
+ uint8_t rfa0:1;
+ uint8_t is_last_fragment:1;
+ uint8_t is_first_fragment:1;
+ uint8_t is_fragmented:1;
+} __attribute__ ((packed));
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct rtp_header {
+ uint8_t v:2;
+ uint8_t p:1;
+ uint8_t x:1;
+ uint8_t cc:4;
+
+ uint8_t m:1;
+ uint8_t pt:7;
+
+ uint16_t sequence_number;
+ uint32_t timestamp;
+ uint32_t ssrc;
+ uint32_t csrc[0];
+} __attribute__ ((packed));
+
+struct rtp_payload {
+ uint8_t is_fragmented:1;
+ uint8_t is_first_fragment:1;
+ uint8_t is_last_fragment:1;
+ uint8_t rfa0:1;
+ uint8_t frame_count:4;
+} __attribute__ ((packed));
+
+#else
+#error "Unknown byte order"
+#endif
diff --git a/src/modules/bluetooth/sbc.c b/src/modules/bluetooth/sbc.c
new file mode 100644
index 00000000..02a6143d
--- /dev/null
+++ b/src/modules/bluetooth/sbc.c
@@ -0,0 +1,1411 @@
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
+ * Copyright (C) 2005-2008 Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+/* todo items:
+
+ use a log2 table for byte integer scale factors calculation (sum log2 results
+ for high and low bytes) fill bitpool by 16 bits instead of one at a time in
+ bits allocation/bitpool generation port to the dsp
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include "sbc_math.h"
+#include "sbc_tables.h"
+
+#include "sbc.h"
+
+#define SBC_SYNCWORD 0x9C
+
+/* This structure contains an unpacked SBC frame.
+ Yes, there is probably quite some unused space herein */
+struct sbc_frame {
+ uint8_t frequency;
+ uint8_t block_mode;
+ uint8_t blocks;
+ enum {
+ MONO = SBC_MODE_MONO,
+ DUAL_CHANNEL = SBC_MODE_DUAL_CHANNEL,
+ STEREO = SBC_MODE_STEREO,
+ JOINT_STEREO = SBC_MODE_JOINT_STEREO
+ } mode;
+ uint8_t channels;
+ enum {
+ LOUDNESS = SBC_AM_LOUDNESS,
+ SNR = SBC_AM_SNR
+ } allocation;
+ uint8_t subband_mode;
+ uint8_t subbands;
+ uint8_t bitpool;
+ uint8_t codesize;
+ uint8_t length;
+
+ /* bit number x set means joint stereo has been used in subband x */
+ uint8_t joint;
+
+ /* only the lower 4 bits of every element are to be used */
+ uint8_t scale_factor[2][8];
+
+ /* raw integer subband samples in the frame */
+
+ int32_t sb_sample_f[16][2][8];
+ int32_t sb_sample[16][2][8]; /* modified subband samples */
+ int16_t pcm_sample[2][16*8]; /* original pcm audio samples */
+};
+
+struct sbc_decoder_state {
+ int subbands;
+ int32_t V[2][170];
+ int offset[2][16];
+};
+
+struct sbc_encoder_state {
+ int subbands;
+ int position[2];
+ int32_t X[2][160];
+};
+
+/*
+ * Calculates the CRC-8 of the first len bits in data
+ */
+static const uint8_t crc_table[256] = {
+ 0x00, 0x1D, 0x3A, 0x27, 0x74, 0x69, 0x4E, 0x53,
+ 0xE8, 0xF5, 0xD2, 0xCF, 0x9C, 0x81, 0xA6, 0xBB,
+ 0xCD, 0xD0, 0xF7, 0xEA, 0xB9, 0xA4, 0x83, 0x9E,
+ 0x25, 0x38, 0x1F, 0x02, 0x51, 0x4C, 0x6B, 0x76,
+ 0x87, 0x9A, 0xBD, 0xA0, 0xF3, 0xEE, 0xC9, 0xD4,
+ 0x6F, 0x72, 0x55, 0x48, 0x1B, 0x06, 0x21, 0x3C,
+ 0x4A, 0x57, 0x70, 0x6D, 0x3E, 0x23, 0x04, 0x19,
+ 0xA2, 0xBF, 0x98, 0x85, 0xD6, 0xCB, 0xEC, 0xF1,
+ 0x13, 0x0E, 0x29, 0x34, 0x67, 0x7A, 0x5D, 0x40,
+ 0xFB, 0xE6, 0xC1, 0xDC, 0x8F, 0x92, 0xB5, 0xA8,
+ 0xDE, 0xC3, 0xE4, 0xF9, 0xAA, 0xB7, 0x90, 0x8D,
+ 0x36, 0x2B, 0x0C, 0x11, 0x42, 0x5F, 0x78, 0x65,
+ 0x94, 0x89, 0xAE, 0xB3, 0xE0, 0xFD, 0xDA, 0xC7,
+ 0x7C, 0x61, 0x46, 0x5B, 0x08, 0x15, 0x32, 0x2F,
+ 0x59, 0x44, 0x63, 0x7E, 0x2D, 0x30, 0x17, 0x0A,
+ 0xB1, 0xAC, 0x8B, 0x96, 0xC5, 0xD8, 0xFF, 0xE2,
+ 0x26, 0x3B, 0x1C, 0x01, 0x52, 0x4F, 0x68, 0x75,
+ 0xCE, 0xD3, 0xF4, 0xE9, 0xBA, 0xA7, 0x80, 0x9D,
+ 0xEB, 0xF6, 0xD1, 0xCC, 0x9F, 0x82, 0xA5, 0xB8,
+ 0x03, 0x1E, 0x39, 0x24, 0x77, 0x6A, 0x4D, 0x50,
+ 0xA1, 0xBC, 0x9B, 0x86, 0xD5, 0xC8, 0xEF, 0xF2,
+ 0x49, 0x54, 0x73, 0x6E, 0x3D, 0x20, 0x07, 0x1A,
+ 0x6C, 0x71, 0x56, 0x4B, 0x18, 0x05, 0x22, 0x3F,
+ 0x84, 0x99, 0xBE, 0xA3, 0xF0, 0xED, 0xCA, 0xD7,
+ 0x35, 0x28, 0x0F, 0x12, 0x41, 0x5C, 0x7B, 0x66,
+ 0xDD, 0xC0, 0xE7, 0xFA, 0xA9, 0xB4, 0x93, 0x8E,
+ 0xF8, 0xE5, 0xC2, 0xDF, 0x8C, 0x91, 0xB6, 0xAB,
+ 0x10, 0x0D, 0x2A, 0x37, 0x64, 0x79, 0x5E, 0x43,
+ 0xB2, 0xAF, 0x88, 0x95, 0xC6, 0xDB, 0xFC, 0xE1,
+ 0x5A, 0x47, 0x60, 0x7D, 0x2E, 0x33, 0x14, 0x09,
+ 0x7F, 0x62, 0x45, 0x58, 0x0B, 0x16, 0x31, 0x2C,
+ 0x97, 0x8A, 0xAD, 0xB0, 0xE3, 0xFE, 0xD9, 0xC4
+};
+
+static uint8_t sbc_crc8(const uint8_t *data, size_t len)
+{
+ uint8_t crc = 0x0f;
+ size_t i;
+ uint8_t octet;
+
+ for (i = 0; i < len / 8; i++)
+ crc = crc_table[crc ^ data[i]];
+
+ octet = data[i];
+ for (i = 0; i < len % 8; i++) {
+ unsigned char bit = ((octet ^ crc) & 0x80) >> 7;
+
+ crc = ((crc & 0x7f) << 1) ^ (bit ? 0x1d : 0);
+
+ octet = octet << 1;
+ }
+
+ return crc;
+}
+
+/*
+ * Code straight from the spec to calculate the bits array
+ * Takes a pointer to the frame in question, a pointer to the bits array and
+ * the sampling frequency (as 2 bit integer)
+ */
+static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
+{
+ uint8_t sf = frame->frequency;
+
+ if (frame->mode == MONO || frame->mode == DUAL_CHANNEL) {
+ int bitneed[2][8], loudness, max_bitneed, bitcount, slicecount, bitslice;
+ int ch, sb;
+
+ for (ch = 0; ch < frame->channels; ch++) {
+ max_bitneed = 0;
+ if (frame->allocation == SNR) {
+ for (sb = 0; sb < frame->subbands; sb++) {
+ bitneed[ch][sb] = frame->scale_factor[ch][sb];
+ if (bitneed[ch][sb] > max_bitneed)
+ max_bitneed = bitneed[ch][sb];
+ }
+ } else {
+ for (sb = 0; sb < frame->subbands; sb++) {
+ if (frame->scale_factor[ch][sb] == 0)
+ bitneed[ch][sb] = -5;
+ else {
+ if (frame->subbands == 4)
+ loudness = frame->scale_factor[ch][sb] - sbc_offset4[sf][sb];
+ else
+ loudness = frame->scale_factor[ch][sb] - sbc_offset8[sf][sb];
+ if (loudness > 0)
+ bitneed[ch][sb] = loudness / 2;
+ else
+ bitneed[ch][sb] = loudness;
+ }
+ if (bitneed[ch][sb] > max_bitneed)
+ max_bitneed = bitneed[ch][sb];
+ }
+ }
+
+ bitcount = 0;
+ slicecount = 0;
+ bitslice = max_bitneed + 1;
+ do {
+ bitslice--;
+ bitcount += slicecount;
+ slicecount = 0;
+ for (sb = 0; sb < frame->subbands; sb++) {
+ if ((bitneed[ch][sb] > bitslice + 1) && (bitneed[ch][sb] < bitslice + 16))
+ slicecount++;
+ else if (bitneed[ch][sb] == bitslice + 1)
+ slicecount += 2;
+ }
+ } while (bitcount + slicecount < frame->bitpool);
+
+ if (bitcount + slicecount == frame->bitpool) {
+ bitcount += slicecount;
+ bitslice--;
+ }
+
+ for (sb = 0; sb < frame->subbands; sb++) {
+ if (bitneed[ch][sb] < bitslice + 2)
+ bits[ch][sb] = 0;
+ else {
+ bits[ch][sb] = bitneed[ch][sb] - bitslice;
+ if (bits[ch][sb] > 16)
+ bits[ch][sb] = 16;
+ }
+ }
+
+ for (sb = 0; bitcount < frame->bitpool && sb < frame->subbands; sb++) {
+ if ((bits[ch][sb] >= 2) && (bits[ch][sb] < 16)) {
+ bits[ch][sb]++;
+ bitcount++;
+ } else if ((bitneed[ch][sb] == bitslice + 1) && (frame->bitpool > bitcount + 1)) {
+ bits[ch][sb] = 2;
+ bitcount += 2;
+ }
+ }
+
+ for (sb = 0; bitcount < frame->bitpool && sb < frame->subbands; sb++) {
+ if (bits[ch][sb] < 16) {
+ bits[ch][sb]++;
+ bitcount++;
+ }
+ }
+
+ }
+
+ } else if (frame->mode == STEREO || frame->mode == JOINT_STEREO) {
+ int bitneed[2][8], loudness, max_bitneed, bitcount, slicecount, bitslice;
+ int ch, sb;
+
+ max_bitneed = 0;
+ if (frame->allocation == SNR) {
+ for (ch = 0; ch < 2; ch++) {
+ for (sb = 0; sb < frame->subbands; sb++) {
+ bitneed[ch][sb] = frame->scale_factor[ch][sb];
+ if (bitneed[ch][sb] > max_bitneed)
+ max_bitneed = bitneed[ch][sb];
+ }
+ }
+ } else {
+ for (ch = 0; ch < 2; ch++) {
+ for (sb = 0; sb < frame->subbands; sb++) {
+ if (frame->scale_factor[ch][sb] == 0)
+ bitneed[ch][sb] = -5;
+ else {
+ if (frame->subbands == 4)
+ loudness = frame->scale_factor[ch][sb] - sbc_offset4[sf][sb];
+ else
+ loudness = frame->scale_factor[ch][sb] - sbc_offset8[sf][sb];
+ if (loudness > 0)
+ bitneed[ch][sb] = loudness / 2;
+ else
+ bitneed[ch][sb] = loudness;
+ }
+ if (bitneed[ch][sb] > max_bitneed)
+ max_bitneed = bitneed[ch][sb];
+ }
+ }
+ }
+
+ bitcount = 0;
+ slicecount = 0;
+ bitslice = max_bitneed + 1;
+ do {
+ bitslice--;
+ bitcount += slicecount;
+ slicecount = 0;
+ for (ch = 0; ch < 2; ch++) {
+ for (sb = 0; sb < frame->subbands; sb++) {
+ if ((bitneed[ch][sb] > bitslice + 1) && (bitneed[ch][sb] < bitslice + 16))
+ slicecount++;
+ else if (bitneed[ch][sb] == bitslice + 1)
+ slicecount += 2;
+ }
+ }
+ } while (bitcount + slicecount < frame->bitpool);
+
+ if (bitcount + slicecount == frame->bitpool) {
+ bitcount += slicecount;
+ bitslice--;
+ }
+
+ for (ch = 0; ch < 2; ch++) {
+ for (sb = 0; sb < frame->subbands; sb++) {
+ if (bitneed[ch][sb] < bitslice + 2) {
+ bits[ch][sb] = 0;
+ } else {
+ bits[ch][sb] = bitneed[ch][sb] - bitslice;
+ if (bits[ch][sb] > 16)
+ bits[ch][sb] = 16;
+ }
+ }
+ }
+
+ ch = 0;
+ sb = 0;
+ while (bitcount < frame->bitpool) {
+ if ((bits[ch][sb] >= 2) && (bits[ch][sb] < 16)) {
+ bits[ch][sb]++;
+ bitcount++;
+ } else if ((bitneed[ch][sb] == bitslice + 1) && (frame->bitpool > bitcount + 1)) {
+ bits[ch][sb] = 2;
+ bitcount += 2;
+ }
+ if (ch == 1) {
+ ch = 0;
+ sb++;
+ if (sb >= frame->subbands) break;
+ } else
+ ch = 1;
+ }
+
+ ch = 0;
+ sb = 0;
+ while (bitcount < frame->bitpool) {
+ if (bits[ch][sb] < 16) {
+ bits[ch][sb]++;
+ bitcount++;
+ }
+ if (ch == 1) {
+ ch = 0;
+ sb++;
+ if (sb >= frame->subbands) break;
+ } else
+ ch = 1;
+ }
+
+ }
+
+}
+
+/*
+ * Unpacks a SBC frame at the beginning of the stream in data,
+ * which has at most len bytes into frame.
+ * Returns the length in bytes of the packed frame, or a negative
+ * value on error. The error codes are:
+ *
+ * -1 Data stream too short
+ * -2 Sync byte incorrect
+ * -3 CRC8 incorrect
+ * -4 Bitpool value out of bounds
+ */
+static int sbc_unpack_frame(const uint8_t *data, struct sbc_frame *frame,
+ size_t len)
+{
+ int consumed;
+ /* Will copy the parts of the header that are relevant to crc
+ * calculation here */
+ uint8_t crc_header[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ int crc_pos = 0;
+ int32_t temp;
+
+ int audio_sample;
+ int ch, sb, blk, bit; /* channel, subband, block and bit standard
+ counters */
+ int bits[2][8]; /* bits distribution */
+ uint32_t levels[2][8]; /* levels derived from that */
+
+ if (len < 4)
+ return -1;
+
+ if (data[0] != SBC_SYNCWORD)
+ return -2;
+
+ frame->frequency = (data[1] >> 6) & 0x03;
+
+ frame->block_mode = (data[1] >> 4) & 0x03;
+ switch (frame->block_mode) {
+ case SBC_BLK_4:
+ frame->blocks = 4;
+ break;
+ case SBC_BLK_8:
+ frame->blocks = 8;
+ break;
+ case SBC_BLK_12:
+ frame->blocks = 12;
+ break;
+ case SBC_BLK_16:
+ frame->blocks = 16;
+ break;
+ }
+
+ frame->mode = (data[1] >> 2) & 0x03;
+ switch (frame->mode) {
+ case MONO:
+ frame->channels = 1;
+ break;
+ case DUAL_CHANNEL: /* fall-through */
+ case STEREO:
+ case JOINT_STEREO:
+ frame->channels = 2;
+ break;
+ }
+
+ frame->allocation = (data[1] >> 1) & 0x01;
+
+ frame->subband_mode = (data[1] & 0x01);
+ frame->subbands = frame->subband_mode ? 8 : 4;
+
+ frame->bitpool = data[2];
+
+ if ((frame->mode == MONO || frame->mode == DUAL_CHANNEL) &&
+ frame->bitpool > 16 * frame->subbands)
+ return -4;
+
+ if ((frame->mode == STEREO || frame->mode == JOINT_STEREO) &&
+ frame->bitpool > 32 * frame->subbands)
+ return -4;
+
+ /* data[3] is crc, we're checking it later */
+
+ consumed = 32;
+
+ crc_header[0] = data[1];
+ crc_header[1] = data[2];
+ crc_pos = 16;
+
+ if (frame->mode == JOINT_STEREO) {
+ if (len * 8 < consumed + frame->subbands)
+ return -1;
+
+ frame->joint = 0x00;
+ for (sb = 0; sb < frame->subbands - 1; sb++)
+ frame->joint |= ((data[4] >> (7 - sb)) & 0x01) << sb;
+ if (frame->subbands == 4)
+ crc_header[crc_pos / 8] = data[4] & 0xf0;
+ else
+ crc_header[crc_pos / 8] = data[4];
+
+ consumed += frame->subbands;
+ crc_pos += frame->subbands;
+ }
+
+ if (len * 8 < consumed + (4 * frame->subbands * frame->channels))
+ return -1;
+
+ for (ch = 0; ch < frame->channels; ch++) {
+ for (sb = 0; sb < frame->subbands; sb++) {
+ /* FIXME assert(consumed % 4 == 0); */
+ frame->scale_factor[ch][sb] =
+ (data[consumed >> 3] >> (4 - (consumed & 0x7))) & 0x0F;
+ crc_header[crc_pos >> 3] |=
+ frame->scale_factor[ch][sb] << (4 - (crc_pos & 0x7));
+
+ consumed += 4;
+ crc_pos += 4;
+ }
+ }
+
+ if (data[3] != sbc_crc8(crc_header, crc_pos))
+ return -3;
+
+ sbc_calculate_bits(frame, bits);
+
+ for (ch = 0; ch < frame->channels; ch++) {
+ for (sb = 0; sb < frame->subbands; sb++)
+ levels[ch][sb] = (1 << bits[ch][sb]) - 1;
+ }
+
+ for (blk = 0; blk < frame->blocks; blk++) {
+ for (ch = 0; ch < frame->channels; ch++) {
+ for (sb = 0; sb < frame->subbands; sb++) {
+ if (levels[ch][sb] > 0) {
+ audio_sample = 0;
+ for (bit = 0; bit < bits[ch][sb]; bit++) {
+ if (consumed > len * 8)
+ return -1;
+
+ if ((data[consumed >> 3] >> (7 - (consumed & 0x7))) & 0x01)
+ audio_sample |= 1 << (bits[ch][sb] - bit - 1);
+
+ consumed++;
+ }
+
+ frame->sb_sample[blk][ch][sb] =
+ (((audio_sample << 1) | 1) << frame->scale_factor[ch][sb]) /
+ levels[ch][sb] - (1 << frame->scale_factor[ch][sb]);
+ } else
+ frame->sb_sample[blk][ch][sb] = 0;
+ }
+ }
+ }
+
+ if (frame->mode == JOINT_STEREO) {
+ for (blk = 0; blk < frame->blocks; blk++) {
+ for (sb = 0; sb < frame->subbands; sb++) {
+ if (frame->joint & (0x01 << sb)) {
+ temp = frame->sb_sample[blk][0][sb] +
+ frame->sb_sample[blk][1][sb];
+ frame->sb_sample[blk][1][sb] =
+ frame->sb_sample[blk][0][sb] -
+ frame->sb_sample[blk][1][sb];
+ frame->sb_sample[blk][0][sb] = temp;
+ }
+ }
+ }
+ }
+
+ if ((consumed & 0x7) != 0)
+ consumed += 8 - (consumed & 0x7);
+
+ return consumed >> 3;
+}
+
+static void sbc_decoder_init(struct sbc_decoder_state *state,
+ const struct sbc_frame *frame)
+{
+ int i, ch;
+
+ memset(state->V, 0, sizeof(state->V));
+ state->subbands = frame->subbands;
+
+ for (ch = 0; ch < 2; ch++)
+ for (i = 0; i < frame->subbands * 2; i++)
+ state->offset[ch][i] = (10 * i + 10);
+}
+
+static inline void sbc_synthesize_four(struct sbc_decoder_state *state,
+ struct sbc_frame *frame, int ch, int blk)
+{
+ int i, k, idx;
+ int32_t *v = state->V[ch];
+ int *offset = state->offset[ch];
+
+ for (i = 0; i < 8; i++) {
+ /* Shifting */
+ offset[i]--;
+ if (offset[i] < 0) {
+ offset[i] = 79;
+ memcpy(v + 80, v, 9 * sizeof(*v));
+ }
+
+ /* Distribute the new matrix value to the shifted position */
+ v[offset[i]] = SCALE4_STAGED1(
+ MULA(synmatrix4[i][0], frame->sb_sample[blk][ch][0],
+ MULA(synmatrix4[i][1], frame->sb_sample[blk][ch][1],
+ MULA(synmatrix4[i][2], frame->sb_sample[blk][ch][2],
+ MUL (synmatrix4[i][3], frame->sb_sample[blk][ch][3])))));
+ }
+
+ /* Compute the samples */
+ for (idx = 0, i = 0; i < 4; i++, idx += 5) {
+ k = (i + 4) & 0xf;
+
+ /* Store in output, Q0 */
+ frame->pcm_sample[ch][blk * 4 + i] = SCALE4_STAGED2(
+ MULA(v[offset[i] + 0], sbc_proto_4_40m0[idx + 0],
+ MULA(v[offset[k] + 1], sbc_proto_4_40m1[idx + 0],
+ MULA(v[offset[i] + 2], sbc_proto_4_40m0[idx + 1],
+ MULA(v[offset[k] + 3], sbc_proto_4_40m1[idx + 1],
+ MULA(v[offset[i] + 4], sbc_proto_4_40m0[idx + 2],
+ MULA(v[offset[k] + 5], sbc_proto_4_40m1[idx + 2],
+ MULA(v[offset[i] + 6], sbc_proto_4_40m0[idx + 3],
+ MULA(v[offset[k] + 7], sbc_proto_4_40m1[idx + 3],
+ MULA(v[offset[i] + 8], sbc_proto_4_40m0[idx + 4],
+ MUL( v[offset[k] + 9], sbc_proto_4_40m1[idx + 4])))))))))));
+ }
+}
+
+static inline void sbc_synthesize_eight(struct sbc_decoder_state *state,
+ struct sbc_frame *frame, int ch, int blk)
+{
+ int i, j, k, idx;
+ int *offset = state->offset[ch];
+
+ for (i = 0; i < 16; i++) {
+ /* Shifting */
+ offset[i]--;
+ if (offset[i] < 0) {
+ offset[i] = 159;
+ for (j = 0; j < 9; j++)
+ state->V[ch][j + 160] = state->V[ch][j];
+ }
+
+ /* Distribute the new matrix value to the shifted position */
+ state->V[ch][offset[i]] = SCALE8_STAGED1(
+ MULA(synmatrix8[i][0], frame->sb_sample[blk][ch][0],
+ MULA(synmatrix8[i][1], frame->sb_sample[blk][ch][1],
+ MULA(synmatrix8[i][2], frame->sb_sample[blk][ch][2],
+ MULA(synmatrix8[i][3], frame->sb_sample[blk][ch][3],
+ MULA(synmatrix8[i][4], frame->sb_sample[blk][ch][4],
+ MULA(synmatrix8[i][5], frame->sb_sample[blk][ch][5],
+ MULA(synmatrix8[i][6], frame->sb_sample[blk][ch][6],
+ MUL( synmatrix8[i][7], frame->sb_sample[blk][ch][7])))))))));
+ }
+
+ /* Compute the samples */
+ for (idx = 0, i = 0; i < 8; i++, idx += 5) {
+ k = (i + 8) & 0xf;
+
+ /* Store in output */
+ frame->pcm_sample[ch][blk * 8 + i] = SCALE8_STAGED2( // Q0
+ MULA(state->V[ch][offset[i] + 0], sbc_proto_8_80m0[idx + 0],
+ MULA(state->V[ch][offset[k] + 1], sbc_proto_8_80m1[idx + 0],
+ MULA(state->V[ch][offset[i] + 2], sbc_proto_8_80m0[idx + 1],
+ MULA(state->V[ch][offset[k] + 3], sbc_proto_8_80m1[idx + 1],
+ MULA(state->V[ch][offset[i] + 4], sbc_proto_8_80m0[idx + 2],
+ MULA(state->V[ch][offset[k] + 5], sbc_proto_8_80m1[idx + 2],
+ MULA(state->V[ch][offset[i] + 6], sbc_proto_8_80m0[idx + 3],
+ MULA(state->V[ch][offset[k] + 7], sbc_proto_8_80m1[idx + 3],
+ MULA(state->V[ch][offset[i] + 8], sbc_proto_8_80m0[idx + 4],
+ MUL( state->V[ch][offset[k] + 9], sbc_proto_8_80m1[idx + 4])))))))))));
+ }
+}
+
+static int sbc_synthesize_audio(struct sbc_decoder_state *state,
+ struct sbc_frame *frame)
+{
+ int ch, blk;
+
+ switch (frame->subbands) {
+ case 4:
+ for (ch = 0; ch < frame->channels; ch++) {
+ for (blk = 0; blk < frame->blocks; blk++)
+ sbc_synthesize_four(state, frame, ch, blk);
+ }
+ return frame->blocks * 4;
+
+ case 8:
+ for (ch = 0; ch < frame->channels; ch++) {
+ for (blk = 0; blk < frame->blocks; blk++)
+ sbc_synthesize_eight(state, frame, ch, blk);
+ }
+ return frame->blocks * 8;
+
+ default:
+ return -EIO;
+ }
+}
+
+static void sbc_encoder_init(struct sbc_encoder_state *state,
+ const struct sbc_frame *frame)
+{
+ memset(&state->X, 0, sizeof(state->X));
+ state->subbands = frame->subbands;
+ state->position[0] = state->position[1] = 9 * frame->subbands;
+}
+
+static inline void _sbc_analyze_four(const int32_t *in, int32_t *out)
+{
+ sbc_fixed_t t[8], s[5];
+
+ t[0] = SCALE4_STAGE1( /* Q8 */
+ MULA(_sbc_proto_4[0], in[8] - in[32], /* Q18 */
+ MUL( _sbc_proto_4[1], in[16] - in[24])));
+
+ t[1] = SCALE4_STAGE1(
+ MULA(_sbc_proto_4[2], in[1],
+ MULA(_sbc_proto_4[3], in[9],
+ MULA(_sbc_proto_4[4], in[17],
+ MULA(_sbc_proto_4[5], in[25],
+ MUL( _sbc_proto_4[6], in[33]))))));
+
+ t[2] = SCALE4_STAGE1(
+ MULA(_sbc_proto_4[7], in[2],
+ MULA(_sbc_proto_4[8], in[10],
+ MULA(_sbc_proto_4[9], in[18],
+ MULA(_sbc_proto_4[10], in[26],
+ MUL( _sbc_proto_4[11], in[34]))))));
+
+ t[3] = SCALE4_STAGE1(
+ MULA(_sbc_proto_4[12], in[3],
+ MULA(_sbc_proto_4[13], in[11],
+ MULA(_sbc_proto_4[14], in[19],
+ MULA(_sbc_proto_4[15], in[27],
+ MUL( _sbc_proto_4[16], in[35]))))));
+
+ t[4] = SCALE4_STAGE1(
+ MULA(_sbc_proto_4[17], in[4] + in[36],
+ MULA(_sbc_proto_4[18], in[12] + in[28],
+ MUL( _sbc_proto_4[19], in[20]))));
+
+ t[5] = SCALE4_STAGE1(
+ MULA(_sbc_proto_4[16], in[5],
+ MULA(_sbc_proto_4[15], in[13],
+ MULA(_sbc_proto_4[14], in[21],
+ MULA(_sbc_proto_4[13], in[29],
+ MUL( _sbc_proto_4[12], in[37]))))));
+
+ /* don't compute t[6]... this term always multiplies
+ * with cos(pi/2) = 0 */
+
+ t[7] = SCALE4_STAGE1(
+ MULA(_sbc_proto_4[6], in[7],
+ MULA(_sbc_proto_4[5], in[15],
+ MULA(_sbc_proto_4[4], in[23],
+ MULA(_sbc_proto_4[3], in[31],
+ MUL( _sbc_proto_4[2], in[39]))))));
+
+ s[0] = MUL( _anamatrix4[0], t[0] + t[4]);
+ s[1] = MUL( _anamatrix4[2], t[2]);
+ s[2] = MULA(_anamatrix4[1], t[1] + t[3],
+ MUL(_anamatrix4[3], t[5]));
+ s[3] = MULA(_anamatrix4[3], t[1] + t[3],
+ MUL(_anamatrix4[1], -t[5] + t[7]));
+ s[4] = MUL( _anamatrix4[3], t[7]);
+
+ out[0] = SCALE4_STAGE2( s[0] + s[1] + s[2] + s[4]); /* Q0 */
+ out[1] = SCALE4_STAGE2(-s[0] + s[1] + s[3]);
+ out[2] = SCALE4_STAGE2(-s[0] + s[1] - s[3]);
+ out[3] = SCALE4_STAGE2( s[0] + s[1] - s[2] - s[4]);
+}
+
+static inline void sbc_analyze_four(struct sbc_encoder_state *state,
+ struct sbc_frame *frame, int ch, int blk)
+{
+ int32_t *x = &state->X[ch][state->position[ch]];
+ int16_t *pcm = &frame->pcm_sample[ch][blk * 4];
+
+ /* Input 4 Audio Samples */
+ x[40] = x[0] = pcm[3];
+ x[41] = x[1] = pcm[2];
+ x[42] = x[2] = pcm[1];
+ x[43] = x[3] = pcm[0];
+
+ _sbc_analyze_four(x, frame->sb_sample_f[blk][ch]);
+
+ state->position[ch] -= 4;
+ if (state->position[ch] < 0)
+ state->position[ch] = 36;
+}
+
+static inline void _sbc_analyze_eight(const int32_t *in, int32_t *out)
+{
+ sbc_fixed_t t[8], s[8];
+
+ t[0] = SCALE8_STAGE1( /* Q10 */
+ MULA(_sbc_proto_8[0], (in[16] - in[64]), /* Q18 = Q18 * Q0 */
+ MULA(_sbc_proto_8[1], (in[32] - in[48]),
+ MULA(_sbc_proto_8[2], in[4],
+ MULA(_sbc_proto_8[3], in[20],
+ MULA(_sbc_proto_8[4], in[36],
+ MUL( _sbc_proto_8[5], in[52])))))));
+
+ t[1] = SCALE8_STAGE1(
+ MULA(_sbc_proto_8[6], in[2],
+ MULA(_sbc_proto_8[7], in[18],
+ MULA(_sbc_proto_8[8], in[34],
+ MULA(_sbc_proto_8[9], in[50],
+ MUL(_sbc_proto_8[10], in[66]))))));
+
+ t[2] = SCALE8_STAGE1(
+ MULA(_sbc_proto_8[11], in[1],
+ MULA(_sbc_proto_8[12], in[17],
+ MULA(_sbc_proto_8[13], in[33],
+ MULA(_sbc_proto_8[14], in[49],
+ MULA(_sbc_proto_8[15], in[65],
+ MULA(_sbc_proto_8[16], in[3],
+ MULA(_sbc_proto_8[17], in[19],
+ MULA(_sbc_proto_8[18], in[35],
+ MULA(_sbc_proto_8[19], in[51],
+ MUL( _sbc_proto_8[20], in[67])))))))))));
+
+ t[3] = SCALE8_STAGE1(
+ MULA( _sbc_proto_8[21], in[5],
+ MULA( _sbc_proto_8[22], in[21],
+ MULA( _sbc_proto_8[23], in[37],
+ MULA( _sbc_proto_8[24], in[53],
+ MULA( _sbc_proto_8[25], in[69],
+ MULA(-_sbc_proto_8[15], in[15],
+ MULA(-_sbc_proto_8[14], in[31],
+ MULA(-_sbc_proto_8[13], in[47],
+ MULA(-_sbc_proto_8[12], in[63],
+ MUL( -_sbc_proto_8[11], in[79])))))))))));
+
+ t[4] = SCALE8_STAGE1(
+ MULA( _sbc_proto_8[26], in[6],
+ MULA( _sbc_proto_8[27], in[22],
+ MULA( _sbc_proto_8[28], in[38],
+ MULA( _sbc_proto_8[29], in[54],
+ MULA( _sbc_proto_8[30], in[70],
+ MULA(-_sbc_proto_8[10], in[14],
+ MULA(-_sbc_proto_8[9], in[30],
+ MULA(-_sbc_proto_8[8], in[46],
+ MULA(-_sbc_proto_8[7], in[62],
+ MUL( -_sbc_proto_8[6], in[78])))))))))));
+
+ t[5] = SCALE8_STAGE1(
+ MULA( _sbc_proto_8[31], in[7],
+ MULA( _sbc_proto_8[32], in[23],
+ MULA( _sbc_proto_8[33], in[39],
+ MULA( _sbc_proto_8[34], in[55],
+ MULA( _sbc_proto_8[35], in[71],
+ MULA(-_sbc_proto_8[20], in[13],
+ MULA(-_sbc_proto_8[19], in[29],
+ MULA(-_sbc_proto_8[18], in[45],
+ MULA(-_sbc_proto_8[17], in[61],
+ MUL( -_sbc_proto_8[16], in[77])))))))))));
+
+ t[6] = SCALE8_STAGE1(
+ MULA( _sbc_proto_8[36], (in[8] + in[72]),
+ MULA( _sbc_proto_8[37], (in[24] + in[56]),
+ MULA( _sbc_proto_8[38], in[40],
+ MULA(-_sbc_proto_8[39], in[12],
+ MULA(-_sbc_proto_8[5], in[28],
+ MULA(-_sbc_proto_8[4], in[44],
+ MULA(-_sbc_proto_8[3], in[60],
+ MUL( -_sbc_proto_8[2], in[76])))))))));
+
+ t[7] = SCALE8_STAGE1(
+ MULA( _sbc_proto_8[35], in[9],
+ MULA( _sbc_proto_8[34], in[25],
+ MULA( _sbc_proto_8[33], in[41],
+ MULA( _sbc_proto_8[32], in[57],
+ MULA( _sbc_proto_8[31], in[73],
+ MULA(-_sbc_proto_8[25], in[11],
+ MULA(-_sbc_proto_8[24], in[27],
+ MULA(-_sbc_proto_8[23], in[43],
+ MULA(-_sbc_proto_8[22], in[59],
+ MUL( -_sbc_proto_8[21], in[75])))))))))));
+
+ s[0] = MULA( _anamatrix8[0], t[0],
+ MUL( _anamatrix8[1], t[6]));
+ s[1] = MUL( _anamatrix8[7], t[1]);
+ s[2] = MULA( _anamatrix8[2], t[2],
+ MULA( _anamatrix8[3], t[3],
+ MULA( _anamatrix8[4], t[5],
+ MUL( _anamatrix8[5], t[7]))));
+ s[3] = MUL( _anamatrix8[6], t[4]);
+ s[4] = MULA( _anamatrix8[3], t[2],
+ MULA(-_anamatrix8[5], t[3],
+ MULA(-_anamatrix8[2], t[5],
+ MUL( -_anamatrix8[4], t[7]))));
+ s[5] = MULA( _anamatrix8[4], t[2],
+ MULA(-_anamatrix8[2], t[3],
+ MULA( _anamatrix8[5], t[5],
+ MUL( _anamatrix8[3], t[7]))));
+ s[6] = MULA( _anamatrix8[1], t[0],
+ MUL( -_anamatrix8[0], t[6]));
+ s[7] = MULA( _anamatrix8[5], t[2],
+ MULA(-_anamatrix8[4], t[3],
+ MULA( _anamatrix8[3], t[5],
+ MUL( -_anamatrix8[2], t[7]))));
+
+ out[0] = SCALE8_STAGE2( s[0] + s[1] + s[2] + s[3]);
+ out[1] = SCALE8_STAGE2( s[1] - s[3] + s[4] + s[6]);
+ out[2] = SCALE8_STAGE2( s[1] - s[3] + s[5] - s[6]);
+ out[3] = SCALE8_STAGE2(-s[0] + s[1] + s[3] + s[7]);
+ out[4] = SCALE8_STAGE2(-s[0] + s[1] + s[3] - s[7]);
+ out[5] = SCALE8_STAGE2( s[1] - s[3] - s[5] - s[6]);
+ out[6] = SCALE8_STAGE2( s[1] - s[3] - s[4] + s[6]);
+ out[7] = SCALE8_STAGE2( s[0] + s[1] - s[2] + s[3]);
+}
+
+static inline void sbc_analyze_eight(struct sbc_encoder_state *state,
+ struct sbc_frame *frame, int ch,
+ int blk)
+{
+ int32_t *x = &state->X[ch][state->position[ch]];
+ int16_t *pcm = &frame->pcm_sample[ch][blk * 8];
+
+ /* Input 8 Audio Samples */
+ x[80] = x[0] = pcm[7];
+ x[81] = x[1] = pcm[6];
+ x[82] = x[2] = pcm[5];
+ x[83] = x[3] = pcm[4];
+ x[84] = x[4] = pcm[3];
+ x[85] = x[5] = pcm[2];
+ x[86] = x[6] = pcm[1];
+ x[87] = x[7] = pcm[0];
+
+ _sbc_analyze_eight(x, frame->sb_sample_f[blk][ch]);
+
+ state->position[ch] -= 8;
+ if (state->position[ch] < 0)
+ state->position[ch] = 72;
+}
+
+static int sbc_analyze_audio(struct sbc_encoder_state *state,
+ struct sbc_frame *frame)
+{
+ int ch, blk;
+
+ switch (frame->subbands) {
+ case 4:
+ for (ch = 0; ch < frame->channels; ch++)
+ for (blk = 0; blk < frame->blocks; blk++)
+ sbc_analyze_four(state, frame, ch, blk);
+ return frame->blocks * 4;
+
+ case 8:
+ for (ch = 0; ch < frame->channels; ch++)
+ for (blk = 0; blk < frame->blocks; blk++)
+ sbc_analyze_eight(state, frame, ch, blk);
+ return frame->blocks * 8;
+
+ default:
+ return -EIO;
+ }
+}
+
+/*
+ * Packs the SBC frame from frame into the memory at data. At most len
+ * bytes will be used, should more memory be needed an appropriate
+ * error code will be returned. Returns the length of the packed frame
+ * on success or a negative value on error.
+ *
+ * The error codes are:
+ * -1 Not enough memory reserved
+ * -2 Unsupported sampling rate
+ * -3 Unsupported number of blocks
+ * -4 Unsupported number of subbands
+ * -5 Bitpool value out of bounds
+ * -99 not implemented
+ */
+
+static int sbc_pack_frame(uint8_t *data, struct sbc_frame *frame, size_t len)
+{
+ int produced;
+ /* Will copy the header parts for CRC-8 calculation here */
+ uint8_t crc_header[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ int crc_pos = 0;
+
+ uint16_t audio_sample;
+
+ int ch, sb, blk, bit; /* channel, subband, block and bit counters */
+ int bits[2][8]; /* bits distribution */
+ int levels[2][8]; /* levels are derived from that */
+
+ u_int32_t scalefactor[2][8]; /* derived from frame->scale_factor */
+
+ data[0] = SBC_SYNCWORD;
+
+ data[1] = (frame->frequency & 0x03) << 6;
+
+ data[1] |= (frame->block_mode & 0x03) << 4;
+
+ data[1] |= (frame->mode & 0x03) << 2;
+
+ data[1] |= (frame->allocation & 0x01) << 1;
+
+ switch (frame->subbands) {
+ case 4:
+ /* Nothing to do */
+ break;
+ case 8:
+ data[1] |= 0x01;
+ break;
+ default:
+ return -4;
+ break;
+ }
+
+ data[2] = frame->bitpool;
+
+ if ((frame->mode == MONO || frame->mode == DUAL_CHANNEL) &&
+ frame->bitpool > frame->subbands << 4)
+ return -5;
+
+ if ((frame->mode == STEREO || frame->mode == JOINT_STEREO) &&
+ frame->bitpool > frame->subbands << 5)
+ return -5;
+
+ /* Can't fill in crc yet */
+
+ produced = 32;
+
+ crc_header[0] = data[1];
+ crc_header[1] = data[2];
+ crc_pos = 16;
+
+ for (ch = 0; ch < frame->channels; ch++) {
+ for (sb = 0; sb < frame->subbands; sb++) {
+ frame->scale_factor[ch][sb] = 0;
+ scalefactor[ch][sb] = 2;
+ for (blk = 0; blk < frame->blocks; blk++) {
+ while (scalefactor[ch][sb] < fabs(frame->sb_sample_f[blk][ch][sb])) {
+ frame->scale_factor[ch][sb]++;
+ scalefactor[ch][sb] *= 2;
+ }
+ }
+ }
+ }
+
+ if (frame->mode == JOINT_STEREO) {
+ /* like frame->sb_sample but joint stereo */
+ int32_t sb_sample_j[16][2];
+ /* scalefactor and scale_factor in joint case */
+ u_int32_t scalefactor_j[2];
+ uint8_t scale_factor_j[2];
+
+ frame->joint = 0;
+
+ for (sb = 0; sb < frame->subbands - 1; sb++) {
+ scale_factor_j[0] = 0;
+ scalefactor_j[0] = 2;
+ scale_factor_j[1] = 0;
+ scalefactor_j[1] = 2;
+
+ for (blk = 0; blk < frame->blocks; blk++) {
+ /* Calculate joint stereo signal */
+ sb_sample_j[blk][0] =
+ (frame->sb_sample_f[blk][0][sb] +
+ frame->sb_sample_f[blk][1][sb]) >> 1;
+ sb_sample_j[blk][1] =
+ (frame->sb_sample_f[blk][0][sb] -
+ frame->sb_sample_f[blk][1][sb]) >> 1;
+
+ /* calculate scale_factor_j and scalefactor_j for joint case */
+ while (scalefactor_j[0] < fabs(sb_sample_j[blk][0])) {
+ scale_factor_j[0]++;
+ scalefactor_j[0] *= 2;
+ }
+ while (scalefactor_j[1] < fabs(sb_sample_j[blk][1])) {
+ scale_factor_j[1]++;
+ scalefactor_j[1] *= 2;
+ }
+ }
+
+ /* decide whether to join this subband */
+ if ((scalefactor[0][sb] + scalefactor[1][sb]) >
+ (scalefactor_j[0] + scalefactor_j[1]) ) {
+ /* use joint stereo for this subband */
+ frame->joint |= 1 << sb;
+ frame->scale_factor[0][sb] = scale_factor_j[0];
+ frame->scale_factor[1][sb] = scale_factor_j[1];
+ scalefactor[0][sb] = scalefactor_j[0];
+ scalefactor[1][sb] = scalefactor_j[1];
+ for (blk = 0; blk < frame->blocks; blk++) {
+ frame->sb_sample_f[blk][0][sb] =
+ sb_sample_j[blk][0];
+ frame->sb_sample_f[blk][1][sb] =
+ sb_sample_j[blk][1];
+ }
+ }
+ }
+
+ data[4] = 0;
+ for (sb = 0; sb < frame->subbands - 1; sb++)
+ data[4] |= ((frame->joint >> sb) & 0x01) << (frame->subbands - 1 - sb);
+
+ crc_header[crc_pos >> 3] = data[4];
+
+ produced += frame->subbands;
+ crc_pos += frame->subbands;
+ }
+
+ for (ch = 0; ch < frame->channels; ch++) {
+ for (sb = 0; sb < frame->subbands; sb++) {
+ data[produced >> 3] <<= 4;
+ crc_header[crc_pos >> 3] <<= 4;
+ data[produced >> 3] |= frame->scale_factor[ch][sb] & 0x0F;
+ crc_header[crc_pos >> 3] |= frame->scale_factor[ch][sb] & 0x0F;
+
+ produced += 4;
+ crc_pos += 4;
+ }
+ }
+
+ /* align the last crc byte */
+ if (crc_pos % 8)
+ crc_header[crc_pos >> 3] <<= 8 - (crc_pos % 8);
+
+ data[3] = sbc_crc8(crc_header, crc_pos);
+
+ sbc_calculate_bits(frame, bits);
+
+ for (ch = 0; ch < frame->channels; ch++) {
+ for (sb = 0; sb < frame->subbands; sb++)
+ levels[ch][sb] = (1 << bits[ch][sb]) - 1;
+ }
+
+ for (blk = 0; blk < frame->blocks; blk++) {
+ for (ch = 0; ch < frame->channels; ch++) {
+ for (sb = 0; sb < frame->subbands; sb++) {
+ if (levels[ch][sb] > 0) {
+ audio_sample =
+ (uint16_t) ((((frame->sb_sample_f[blk][ch][sb]*levels[ch][sb]) >>
+ (frame->scale_factor[ch][sb] + 1)) +
+ levels[ch][sb]) >> 1);
+ audio_sample <<= 16 - bits[ch][sb];
+ for (bit = 0; bit < bits[ch][sb]; bit++) {
+ data[produced >> 3] <<= 1;
+ if (audio_sample & 0x8000)
+ data[produced >> 3] |= 0x1;
+ audio_sample <<= 1;
+ produced++;
+ }
+ }
+ }
+ }
+ }
+
+ /* align the last byte */
+ if (produced % 8) {
+ data[produced >> 3] <<= 8 - (produced % 8);
+ }
+
+ return (produced + 7) >> 3;
+}
+
+struct sbc_priv {
+ int init;
+ struct sbc_frame frame;
+ struct sbc_decoder_state dec_state;
+ struct sbc_encoder_state enc_state;
+};
+
+static void sbc_set_defaults(sbc_t *sbc, unsigned long flags)
+{
+ sbc->frequency = SBC_FREQ_44100;
+ sbc->mode = SBC_MODE_STEREO;
+ sbc->subbands = SBC_SB_8;
+ sbc->blocks = SBC_BLK_16;
+ sbc->bitpool = 32;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ sbc->endian = SBC_LE;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ sbc->endian = SBC_BE;
+#else
+#error "Unknown byte order"
+#endif
+}
+
+int sbc_init(sbc_t *sbc, unsigned long flags)
+{
+ if (!sbc)
+ return -EIO;
+
+ memset(sbc, 0, sizeof(sbc_t));
+
+ sbc->priv = malloc(sizeof(struct sbc_priv));
+ if (!sbc->priv)
+ return -ENOMEM;
+
+ memset(sbc->priv, 0, sizeof(struct sbc_priv));
+
+ sbc_set_defaults(sbc, flags);
+
+ return 0;
+}
+
+int sbc_parse(sbc_t *sbc, void *input, int input_len)
+{
+ return sbc_decode(sbc, input, input_len, NULL, 0, NULL);
+}
+
+int sbc_decode(sbc_t *sbc, void *input, int input_len, void *output,
+ int output_len, int *written)
+{
+ struct sbc_priv *priv;
+ char *ptr;
+ int i, ch, framelen, samples;
+
+ if (!sbc && !input)
+ return -EIO;
+
+ priv = sbc->priv;
+
+ framelen = sbc_unpack_frame(input, &priv->frame, input_len);
+
+ if (!priv->init) {
+ sbc_decoder_init(&priv->dec_state, &priv->frame);
+ priv->init = 1;
+
+ sbc->frequency = priv->frame.frequency;
+ sbc->mode = priv->frame.mode;
+ sbc->subbands = priv->frame.subband_mode;
+ sbc->blocks = priv->frame.block_mode;
+ sbc->allocation = priv->frame.allocation;
+ sbc->bitpool = priv->frame.bitpool;
+
+ priv->frame.codesize = sbc_get_codesize(sbc);
+ priv->frame.length = sbc_get_frame_length(sbc);
+ }
+
+ if (!output)
+ return framelen;
+
+ if (written)
+ *written = 0;
+
+ samples = sbc_synthesize_audio(&priv->dec_state, &priv->frame);
+
+ ptr = output;
+
+ if (output_len < samples * priv->frame.channels * 2)
+ samples = output_len / (priv->frame.channels * 2);
+
+ for (i = 0; i < samples; i++) {
+ for (ch = 0; ch < priv->frame.channels; ch++) {
+ int16_t s;
+ s = priv->frame.pcm_sample[ch][i];
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ if (sbc->endian == SBC_BE) {
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ if (sbc->endian == SBC_LE) {
+#else
+#error "Unknown byte order"
+#endif
+ *ptr++ = (s & 0xff00) >> 8;
+ *ptr++ = (s & 0x00ff);
+ } else {
+ *ptr++ = (s & 0x00ff);
+ *ptr++ = (s & 0xff00) >> 8;
+ }
+ }
+ }
+
+ if (written)
+ *written = samples * priv->frame.channels * 2;
+
+ return framelen;
+}
+
+int sbc_encode(sbc_t *sbc, void *input, int input_len, void *output,
+ int output_len, int *written)
+{
+ struct sbc_priv *priv;
+ char *ptr;
+ int i, ch, framelen, samples;
+
+ if (!sbc && !input)
+ return -EIO;
+
+ priv = sbc->priv;
+
+ if (written)
+ *written = 0;
+
+ if (!priv->init) {
+ priv->frame.frequency = sbc->frequency;
+ priv->frame.mode = sbc->mode;
+ priv->frame.channels = sbc->mode == SBC_MODE_MONO ? 1 : 2;
+ priv->frame.allocation = sbc->allocation;
+ priv->frame.subband_mode = sbc->subbands;
+ priv->frame.subbands = sbc->subbands ? 8 : 4;
+ priv->frame.block_mode = sbc->blocks;
+ priv->frame.blocks = 4 + (sbc->blocks * 4);
+ priv->frame.bitpool = sbc->bitpool;
+ priv->frame.codesize = sbc_get_codesize(sbc);
+ priv->frame.length = sbc_get_frame_length(sbc);
+
+ sbc_encoder_init(&priv->enc_state, &priv->frame);
+ priv->init = 1;
+ }
+
+ /* input must be large enough to encode a complete frame */
+ if (input_len < priv->frame.codesize)
+ return 0;
+
+ /* output must be large enough to receive the encoded frame */
+ if (!output || output_len < priv->frame.length)
+ return -ENOSPC;
+
+ ptr = input;
+
+ for (i = 0; i < priv->frame.subbands * priv->frame.blocks; i++) {
+ for (ch = 0; ch < priv->frame.channels; ch++) {
+ int16_t s;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ if (sbc->endian == SBC_BE)
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ if (sbc->endian == SBC_LE)
+#else
+#error "Unknown byte order"
+#endif
+ s = (ptr[0] & 0xff) << 8 | (ptr[1] & 0xff);
+ else
+ s = (ptr[0] & 0xff) | (ptr[1] & 0xff) << 8;
+ ptr += 2;
+ priv->frame.pcm_sample[ch][i] = s;
+ }
+ }
+
+ samples = sbc_analyze_audio(&priv->enc_state, &priv->frame);
+
+ framelen = sbc_pack_frame(output, &priv->frame, output_len);
+
+ if (written)
+ *written = framelen;
+
+ return samples * priv->frame.channels * 2;
+}
+
+void sbc_finish(sbc_t *sbc)
+{
+ if (!sbc)
+ return;
+
+ if (sbc->priv)
+ free(sbc->priv);
+
+ memset(sbc, 0, sizeof(sbc_t));
+}
+
+int sbc_get_frame_length(sbc_t *sbc)
+{
+ int ret;
+ uint8_t subbands, channels, blocks, joint;
+ struct sbc_priv *priv;
+
+ priv = sbc->priv;
+ if (!priv->init) {
+ subbands = sbc->subbands ? 8 : 4;
+ blocks = 4 + (sbc->blocks * 4);
+ channels = sbc->mode == SBC_MODE_MONO ? 1 : 2;
+ joint = sbc->mode == SBC_MODE_JOINT_STEREO ? 1 : 0;
+ } else {
+ subbands = priv->frame.subbands;
+ blocks = priv->frame.blocks;
+ channels = priv->frame.channels;
+ joint = priv->frame.joint;
+ }
+
+ ret = 4 + (4 * subbands * channels) / 8;
+
+ /* This term is not always evenly divide so we round it up */
+ if (channels == 1)
+ ret += ((blocks * channels * sbc->bitpool) + 7) / 8;
+ else
+ ret += (((joint ? subbands : 0) + blocks * sbc->bitpool) + 7)
+ / 8;
+
+ return ret;
+}
+
+int sbc_get_frame_duration(sbc_t *sbc)
+{
+ uint8_t subbands, blocks;
+ uint16_t frequency;
+ struct sbc_priv *priv;
+
+ priv = sbc->priv;
+ if (!priv->init) {
+ subbands = sbc->subbands ? 8 : 4;
+ blocks = 4 + (sbc->blocks * 4);
+ } else {
+ subbands = priv->frame.subbands;
+ blocks = priv->frame.blocks;
+ }
+
+ switch (sbc->frequency) {
+ case SBC_FREQ_16000:
+ frequency = 16000;
+ break;
+
+ case SBC_FREQ_32000:
+ frequency = 32000;
+ break;
+
+ case SBC_FREQ_44100:
+ frequency = 44100;
+ break;
+
+ case SBC_FREQ_48000:
+ frequency = 48000;
+ break;
+ default:
+ return 0;
+ }
+
+ return (1000000 * blocks * subbands) / frequency;
+}
+
+int sbc_get_codesize(sbc_t *sbc)
+{
+ uint8_t subbands, channels, blocks;
+ struct sbc_priv *priv;
+
+ priv = sbc->priv;
+ if (!priv->init) {
+ subbands = sbc->subbands ? 8 : 4;
+ blocks = 4 + (sbc->blocks * 4);
+ channels = sbc->mode == SBC_MODE_MONO ? 1 : 2;
+ } else {
+ subbands = priv->frame.subbands;
+ blocks = priv->frame.blocks;
+ channels = priv->frame.channels;
+ }
+
+ return subbands * blocks * channels * 2;
+}
+
+int sbc_reinit(sbc_t *sbc, unsigned long flags)
+{
+ struct sbc_priv *priv;
+
+ if (!sbc || !sbc->priv)
+ return -EIO;
+
+ priv = sbc->priv;
+
+ if (priv->init == 1)
+ memset(sbc->priv, 0, sizeof(struct sbc_priv));
+
+ sbc_set_defaults(sbc, flags);
+
+ return 0;
+}
diff --git a/src/modules/bluetooth/sbc.h b/src/modules/bluetooth/sbc.h
new file mode 100644
index 00000000..ab47e329
--- /dev/null
+++ b/src/modules/bluetooth/sbc.h
@@ -0,0 +1,97 @@
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
+ * Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __SBC_H
+#define __SBC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+/* sampling frequency */
+#define SBC_FREQ_16000 0x00
+#define SBC_FREQ_32000 0x01
+#define SBC_FREQ_44100 0x02
+#define SBC_FREQ_48000 0x03
+
+/* blocks */
+#define SBC_BLK_4 0x00
+#define SBC_BLK_8 0x01
+#define SBC_BLK_12 0x02
+#define SBC_BLK_16 0x03
+
+/* channel mode */
+#define SBC_MODE_MONO 0x00
+#define SBC_MODE_DUAL_CHANNEL 0x01
+#define SBC_MODE_STEREO 0x02
+#define SBC_MODE_JOINT_STEREO 0x03
+
+/* allocation method */
+#define SBC_AM_LOUDNESS 0x00
+#define SBC_AM_SNR 0x01
+
+/* subbands */
+#define SBC_SB_4 0x00
+#define SBC_SB_8 0x01
+
+/* Data endianess */
+#define SBC_LE 0x00
+#define SBC_BE 0x01
+
+struct sbc_struct {
+ unsigned long flags;
+
+ uint8_t frequency;
+ uint8_t blocks;
+ uint8_t subbands;
+ uint8_t mode;
+ uint8_t allocation;
+ uint8_t bitpool;
+ uint8_t endian;
+
+ void *priv;
+};
+
+typedef struct sbc_struct sbc_t;
+
+int sbc_init(sbc_t *sbc, unsigned long flags);
+int sbc_reinit(sbc_t *sbc, unsigned long flags);
+int sbc_parse(sbc_t *sbc, void *input, int input_len);
+int sbc_decode(sbc_t *sbc, void *input, int input_len, void *output,
+ int output_len, int *len);
+int sbc_encode(sbc_t *sbc, void *input, int input_len, void *output,
+ int output_len, int *written);
+int sbc_get_frame_length(sbc_t *sbc);
+int sbc_get_frame_duration(sbc_t *sbc);
+int sbc_get_codesize(sbc_t *sbc);
+void sbc_finish(sbc_t *sbc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SBC_H */
diff --git a/src/modules/bluetooth/sbc_math.h b/src/modules/bluetooth/sbc_math.h
new file mode 100644
index 00000000..b3d87a62
--- /dev/null
+++ b/src/modules/bluetooth/sbc_math.h
@@ -0,0 +1,72 @@
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
+ * Copyright (C) 2005-2008 Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#define fabs(x) ((x) < 0 ? -(x) : (x))
+/* C does not provide an explicit arithmetic shift right but this will
+ always be correct and every compiler *should* generate optimal code */
+#define ASR(val, bits) ((-2 >> 1 == -1) ? \
+ ((int32_t)(val)) >> (bits) : ((int32_t) (val)) / (1 << (bits)))
+
+#define SCALE_PROTO4_TBL 15
+#define SCALE_ANA4_TBL 17
+#define SCALE_PROTO8_TBL 16
+#define SCALE_ANA8_TBL 17
+#define SCALE_SPROTO4_TBL 12
+#define SCALE_SPROTO8_TBL 14
+#define SCALE_NPROTO4_TBL 11
+#define SCALE_NPROTO8_TBL 11
+#define SCALE4_STAGE1_BITS 15
+#define SCALE4_STAGE2_BITS 16
+#define SCALE4_STAGED1_BITS 15
+#define SCALE4_STAGED2_BITS 16
+#define SCALE8_STAGE1_BITS 15
+#define SCALE8_STAGE2_BITS 15
+#define SCALE8_STAGED1_BITS 15
+#define SCALE8_STAGED2_BITS 16
+
+typedef int32_t sbc_fixed_t;
+
+#define SCALE4_STAGE1(src) ASR(src, SCALE4_STAGE1_BITS)
+#define SCALE4_STAGE2(src) ASR(src, SCALE4_STAGE2_BITS)
+#define SCALE4_STAGED1(src) ASR(src, SCALE4_STAGED1_BITS)
+#define SCALE4_STAGED2(src) ASR(src, SCALE4_STAGED2_BITS)
+#define SCALE8_STAGE1(src) ASR(src, SCALE8_STAGE1_BITS)
+#define SCALE8_STAGE2(src) ASR(src, SCALE8_STAGE2_BITS)
+#define SCALE8_STAGED1(src) ASR(src, SCALE8_STAGED1_BITS)
+#define SCALE8_STAGED2(src) ASR(src, SCALE8_STAGED2_BITS)
+
+#define SBC_FIXED_0(val) { val = 0; }
+#define MUL(a, b) ((a) * (b))
+#ifdef __arm__
+#define MULA(a, b, res) ({ \
+ int tmp = res; \
+ __asm__( \
+ "mla %0, %2, %3, %0" \
+ : "=&r" (tmp) \
+ : "0" (tmp), "r" (a), "r" (b)); \
+ tmp; })
+#else
+#define MULA(a, b, res) ((a) * (b) + (res))
+#endif
diff --git a/src/modules/bluetooth/sbc_tables.h b/src/modules/bluetooth/sbc_tables.h
new file mode 100644
index 00000000..7ac4e68b
--- /dev/null
+++ b/src/modules/bluetooth/sbc_tables.h
@@ -0,0 +1,167 @@
+/*
+ *
+ * Bluetooth low-complexity, subband codec (SBC) library
+ *
+ * Copyright (C) 2004-2008 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
+ * Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+/* A2DP specification: Appendix B, page 69 */
+static const int sbc_offset4[4][4] = {
+ { -1, 0, 0, 0 },
+ { -2, 0, 0, 1 },
+ { -2, 0, 0, 1 },
+ { -2, 0, 0, 1 }
+};
+
+/* A2DP specification: Appendix B, page 69 */
+static const int sbc_offset8[4][8] = {
+ { -2, 0, 0, 0, 0, 0, 0, 1 },
+ { -3, 0, 0, 0, 0, 0, 1, 2 },
+ { -4, 0, 0, 0, 0, 0, 1, 2 },
+ { -4, 0, 0, 0, 0, 0, 1, 2 }
+};
+
+#define SP4(val) ASR(val, SCALE_PROTO4_TBL)
+#define SA4(val) ASR(val, SCALE_ANA4_TBL)
+#define SP8(val) ASR(val, SCALE_PROTO8_TBL)
+#define SA8(val) ASR(val, SCALE_ANA8_TBL)
+#define SS4(val) ASR(val, SCALE_SPROTO4_TBL)
+#define SS8(val) ASR(val, SCALE_SPROTO8_TBL)
+#define SN4(val) ASR(val, SCALE_NPROTO4_TBL)
+#define SN8(val) ASR(val, SCALE_NPROTO8_TBL)
+
+static const int32_t _sbc_proto_4[20] = {
+ SP4(0x02cb3e8c), SP4(0x22b63dc0), SP4(0x002329cc), SP4(0x053b7548),
+ SP4(0x31eab940), SP4(0xec1f5e60), SP4(0xff3773a8), SP4(0x0061c5a7),
+ SP4(0x07646680), SP4(0x3f239480), SP4(0xf89f23a8), SP4(0x007a4737),
+ SP4(0x00b32807), SP4(0x083ddc80), SP4(0x4825e480), SP4(0x0191e578),
+ SP4(0x00ff11ca), SP4(0x00fb7991), SP4(0x069fdc58), SP4(0x4b584000)
+};
+
+static const int32_t _anamatrix4[4] = {
+ SA4(0x2d413cc0), SA4(0x3b20d780), SA4(0x40000000), SA4(0x187de2a0)
+};
+
+static const int32_t _sbc_proto_8[40] = {
+ SP8(0x02e5cd20), SP8(0x22d0c200), SP8(0x006bfe27), SP8(0x07808930),
+ SP8(0x3f1c8800), SP8(0xf8810d70), SP8(0x002cfdc6), SP8(0x055acf28),
+ SP8(0x31f566c0), SP8(0xebfe57e0), SP8(0xff27c437), SP8(0x001485cc),
+ SP8(0x041c6e58), SP8(0x2a7cfa80), SP8(0xe4c4a240), SP8(0xfe359e4c),
+ SP8(0x0048b1f8), SP8(0x0686ce30), SP8(0x38eec5c0), SP8(0xf2a1b9f0),
+ SP8(0xffe8904a), SP8(0x0095698a), SP8(0x0824a480), SP8(0x443b3c00),
+ SP8(0xfd7badc8), SP8(0x00d3e2d9), SP8(0x00c183d2), SP8(0x084e1950),
+ SP8(0x4810d800), SP8(0x017f43fe), SP8(0x01056dd8), SP8(0x00e9cb9f),
+ SP8(0x07d7d090), SP8(0x4a708980), SP8(0x0488fae8), SP8(0x0113bd20),
+ SP8(0x0107b1a8), SP8(0x069fb3c0), SP8(0x4b3db200), SP8(0x00763f48)
+};
+
+static const int32_t sbc_proto_4_40m0[] = {
+ SS4(0x00000000), SS4(0xffa6982f), SS4(0xfba93848), SS4(0x0456c7b8),
+ SS4(0x005967d1), SS4(0xfffb9ac7), SS4(0xff589157), SS4(0xf9c2a8d8),
+ SS4(0x027c1434), SS4(0x0019118b), SS4(0xfff3c74c), SS4(0xff137330),
+ SS4(0xf81b8d70), SS4(0x00ec1b8b), SS4(0xfff0b71a), SS4(0xffe99b00),
+ SS4(0xfef84470), SS4(0xf6fb4370), SS4(0xffcdc351), SS4(0xffe01dc7)
+};
+
+static const int32_t sbc_proto_4_40m1[] = {
+ SS4(0xffe090ce), SS4(0xff2c0475), SS4(0xf694f800), SS4(0xff2c0475),
+ SS4(0xffe090ce), SS4(0xffe01dc7), SS4(0xffcdc351), SS4(0xf6fb4370),
+ SS4(0xfef84470), SS4(0xffe99b00), SS4(0xfff0b71a), SS4(0x00ec1b8b),
+ SS4(0xf81b8d70), SS4(0xff137330), SS4(0xfff3c74c), SS4(0x0019118b),
+ SS4(0x027c1434), SS4(0xf9c2a8d8), SS4(0xff589157), SS4(0xfffb9ac7)
+};
+
+static const int32_t sbc_proto_8_80m0[] = {
+ SS8(0x00000000), SS8(0xfe8d1970), SS8(0xee979f00), SS8(0x11686100),
+ SS8(0x0172e690), SS8(0xfff5bd1a), SS8(0xfdf1c8d4), SS8(0xeac182c0),
+ SS8(0x0d9daee0), SS8(0x00e530da), SS8(0xffe9811d), SS8(0xfd52986c),
+ SS8(0xe7054ca0), SS8(0x0a00d410), SS8(0x006c1de4), SS8(0xffdba705),
+ SS8(0xfcbc98e8), SS8(0xe3889d20), SS8(0x06af2308), SS8(0x000bb7db),
+ SS8(0xffca00ed), SS8(0xfc3fbb68), SS8(0xe071bc00), SS8(0x03bf7948),
+ SS8(0xffc4e05c), SS8(0xffb54b3b), SS8(0xfbedadc0), SS8(0xdde26200),
+ SS8(0x0142291c), SS8(0xff960e94), SS8(0xff9f3e17), SS8(0xfbd8f358),
+ SS8(0xdbf79400), SS8(0xff405e01), SS8(0xff7d4914), SS8(0xff8b1a31),
+ SS8(0xfc1417b8), SS8(0xdac7bb40), SS8(0xfdbb828c), SS8(0xff762170)
+};
+
+static const int32_t sbc_proto_8_80m1[] = {
+ SS8(0xff7c272c), SS8(0xfcb02620), SS8(0xda612700), SS8(0xfcb02620),
+ SS8(0xff7c272c), SS8(0xff762170), SS8(0xfdbb828c), SS8(0xdac7bb40),
+ SS8(0xfc1417b8), SS8(0xff8b1a31), SS8(0xff7d4914), SS8(0xff405e01),
+ SS8(0xdbf79400), SS8(0xfbd8f358), SS8(0xff9f3e17), SS8(0xff960e94),
+ SS8(0x0142291c), SS8(0xdde26200), SS8(0xfbedadc0), SS8(0xffb54b3b),
+ SS8(0xffc4e05c), SS8(0x03bf7948), SS8(0xe071bc00), SS8(0xfc3fbb68),
+ SS8(0xffca00ed), SS8(0x000bb7db), SS8(0x06af2308), SS8(0xe3889d20),
+ SS8(0xfcbc98e8), SS8(0xffdba705), SS8(0x006c1de4), SS8(0x0a00d410),
+ SS8(0xe7054ca0), SS8(0xfd52986c), SS8(0xffe9811d), SS8(0x00e530da),
+ SS8(0x0d9daee0), SS8(0xeac182c0), SS8(0xfdf1c8d4), SS8(0xfff5bd1a)
+};
+
+static const int32_t _anamatrix8[8] = {
+ SA8(0x3b20d780), SA8(0x187de2a0), SA8(0x3ec52f80), SA8(0x3536cc40),
+ SA8(0x238e7680), SA8(0x0c7c5c20), SA8(0x2d413cc0), SA8(0x40000000)
+};
+
+static const int32_t synmatrix4[8][4] = {
+ { SN4(0x05a82798), SN4(0xfa57d868), SN4(0xfa57d868), SN4(0x05a82798) },
+ { SN4(0x030fbc54), SN4(0xf89be510), SN4(0x07641af0), SN4(0xfcf043ac) },
+ { SN4(0x00000000), SN4(0x00000000), SN4(0x00000000), SN4(0x00000000) },
+ { SN4(0xfcf043ac), SN4(0x07641af0), SN4(0xf89be510), SN4(0x030fbc54) },
+ { SN4(0xfa57d868), SN4(0x05a82798), SN4(0x05a82798), SN4(0xfa57d868) },
+ { SN4(0xf89be510), SN4(0xfcf043ac), SN4(0x030fbc54), SN4(0x07641af0) },
+ { SN4(0xf8000000), SN4(0xf8000000), SN4(0xf8000000), SN4(0xf8000000) },
+ { SN4(0xf89be510), SN4(0xfcf043ac), SN4(0x030fbc54), SN4(0x07641af0) }
+};
+
+static const int32_t synmatrix8[16][8] = {
+ { SN8(0x05a82798), SN8(0xfa57d868), SN8(0xfa57d868), SN8(0x05a82798),
+ SN8(0x05a82798), SN8(0xfa57d868), SN8(0xfa57d868), SN8(0x05a82798) },
+ { SN8(0x0471ced0), SN8(0xf8275a10), SN8(0x018f8b84), SN8(0x06a6d988),
+ SN8(0xf9592678), SN8(0xfe70747c), SN8(0x07d8a5f0), SN8(0xfb8e3130) },
+ { SN8(0x030fbc54), SN8(0xf89be510), SN8(0x07641af0), SN8(0xfcf043ac),
+ SN8(0xfcf043ac), SN8(0x07641af0), SN8(0xf89be510), SN8(0x030fbc54) },
+ { SN8(0x018f8b84), SN8(0xfb8e3130), SN8(0x06a6d988), SN8(0xf8275a10),
+ SN8(0x07d8a5f0), SN8(0xf9592678), SN8(0x0471ced0), SN8(0xfe70747c) },
+ { SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), SN8(0x00000000),
+ SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), SN8(0x00000000) },
+ { SN8(0xfe70747c), SN8(0x0471ced0), SN8(0xf9592678), SN8(0x07d8a5f0),
+ SN8(0xf8275a10), SN8(0x06a6d988), SN8(0xfb8e3130), SN8(0x018f8b84) },
+ { SN8(0xfcf043ac), SN8(0x07641af0), SN8(0xf89be510), SN8(0x030fbc54),
+ SN8(0x030fbc54), SN8(0xf89be510), SN8(0x07641af0), SN8(0xfcf043ac) },
+ { SN8(0xfb8e3130), SN8(0x07d8a5f0), SN8(0xfe70747c), SN8(0xf9592678),
+ SN8(0x06a6d988), SN8(0x018f8b84), SN8(0xf8275a10), SN8(0x0471ced0) },
+ { SN8(0xfa57d868), SN8(0x05a82798), SN8(0x05a82798), SN8(0xfa57d868),
+ SN8(0xfa57d868), SN8(0x05a82798), SN8(0x05a82798), SN8(0xfa57d868) },
+ { SN8(0xf9592678), SN8(0x018f8b84), SN8(0x07d8a5f0), SN8(0x0471ced0),
+ SN8(0xfb8e3130), SN8(0xf8275a10), SN8(0xfe70747c), SN8(0x06a6d988) },
+ { SN8(0xf89be510), SN8(0xfcf043ac), SN8(0x030fbc54), SN8(0x07641af0),
+ SN8(0x07641af0), SN8(0x030fbc54), SN8(0xfcf043ac), SN8(0xf89be510) },
+ { SN8(0xf8275a10), SN8(0xf9592678), SN8(0xfb8e3130), SN8(0xfe70747c),
+ SN8(0x018f8b84), SN8(0x0471ced0), SN8(0x06a6d988), SN8(0x07d8a5f0) },
+ { SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000),
+ SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000) },
+ { SN8(0xf8275a10), SN8(0xf9592678), SN8(0xfb8e3130), SN8(0xfe70747c),
+ SN8(0x018f8b84), SN8(0x0471ced0), SN8(0x06a6d988), SN8(0x07d8a5f0) },
+ { SN8(0xf89be510), SN8(0xfcf043ac), SN8(0x030fbc54), SN8(0x07641af0),
+ SN8(0x07641af0), SN8(0x030fbc54), SN8(0xfcf043ac), SN8(0xf89be510) },
+ { SN8(0xf9592678), SN8(0x018f8b84), SN8(0x07d8a5f0), SN8(0x0471ced0),
+ SN8(0xfb8e3130), SN8(0xf8275a10), SN8(0xfe70747c), SN8(0x06a6d988) }
+};
diff --git a/src/modules/gconf/Makefile b/src/modules/gconf/Makefile
index 316beb72..efe5a336 100644..120000
--- a/src/modules/gconf/Makefile
+++ b/src/modules/gconf/Makefile
@@ -1,13 +1 @@
-# This is a dirty trick just to ease compilation with emacs
-#
-# This file is not intended to be distributed or anything
-#
-# So: don't touch it, even better ignore it!
-
-all:
- $(MAKE) -C ../..
-
-clean:
- $(MAKE) -C ../.. clean
-
-.PHONY: all clean
+../../pulse/Makefile \ No newline at end of file
diff --git a/src/modules/module-alsa-sink.c b/src/modules/module-alsa-sink.c
index 6f0d7830..30d4d3aa 100644
--- a/src/modules/module-alsa-sink.c
+++ b/src/modules/module-alsa-sink.c
@@ -623,7 +623,11 @@ static int unsuspend(struct userdata *u) {
pa_log_info("Trying resume...");
snd_config_update_free_global();
- if ((err = snd_pcm_open(&u->pcm_handle, u->device_name, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) {
+ if ((err = snd_pcm_open(&u->pcm_handle, u->device_name, SND_PCM_STREAM_PLAYBACK,
+ /*SND_PCM_NONBLOCK|*/
+ SND_PCM_NO_AUTO_RESAMPLE|
+ SND_PCM_NO_AUTO_CHANNELS|
+ SND_PCM_NO_AUTO_FORMAT)) < 0) {
pa_log("Error opening PCM device %s: %s", u->device_name, snd_strerror(err));
goto fail;
}
@@ -650,7 +654,9 @@ static int unsuspend(struct userdata *u) {
}
if (nfrags != u->nfragments || period_size*u->frame_size != u->fragment_size) {
- pa_log_warn("Resume failed, couldn't restore original fragment settings.");
+ pa_log_warn("Resume failed, couldn't restore original fragment settings. (Old: %lu*%lu, New %lu*%lu)",
+ (unsigned long) u->nfragments, (unsigned long) u->fragment_size,
+ (unsigned long) nfrags, period_size * u->frame_size);
goto fail;
}
@@ -1130,7 +1136,7 @@ static void thread_func(void *userdata) {
pa_rtpoll_set_timer_disabled(u->rtpoll);
/* Hmm, nothing to do. Let's sleep */
- if ((ret = pa_rtpoll_run(u->rtpoll, 1)) < 0)
+ if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0)
goto fail;
if (ret == 0)
@@ -1150,7 +1156,7 @@ static void thread_func(void *userdata) {
goto fail;
}
- if (revents & (POLLERR|POLLNVAL|POLLHUP)) {
+ if (revents & (POLLERR|POLLNVAL|POLLHUP|POLLPRI)) {
if (pa_alsa_recover_from_poll(u->pcm_handle, revents) < 0)
goto fail;
@@ -1159,7 +1165,7 @@ static void thread_func(void *userdata) {
}
if (revents && u->use_tsched)
- pa_log_debug("Wakeup from ALSA! (%i)", revents);
+ pa_log_debug("Wakeup from ALSA!%s%s", (revents & POLLIN) ? " INPUT" : "", (revents & POLLOUT) ? " OUTPUT" : "");
}
}
diff --git a/src/modules/module-alsa-source.c b/src/modules/module-alsa-source.c
index fca05006..d0a22db7 100644
--- a/src/modules/module-alsa-source.c
+++ b/src/modules/module-alsa-source.c
@@ -565,7 +565,12 @@ static int unsuspend(struct userdata *u) {
pa_log_info("Trying resume...");
snd_config_update_free_global();
- if ((err = snd_pcm_open(&u->pcm_handle, u->device_name, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) {
+
+ if ((err = snd_pcm_open(&u->pcm_handle, u->device_name, SND_PCM_STREAM_CAPTURE,
+ /*SND_PCM_NONBLOCK|*/
+ SND_PCM_NO_AUTO_RESAMPLE|
+ SND_PCM_NO_AUTO_CHANNELS|
+ SND_PCM_NO_AUTO_FORMAT)) < 0) {
pa_log("Error opening PCM device %s: %s", u->device_name, snd_strerror(err));
goto fail;
}
@@ -592,7 +597,9 @@ static int unsuspend(struct userdata *u) {
}
if (nfrags != u->nfragments || period_size*u->frame_size != u->fragment_size) {
- pa_log_warn("Resume failed, couldn't restore original fragment settings.");
+ pa_log_warn("Resume failed, couldn't restore original fragment settings. (Old: %lu*%lu, New %lu*%lu)",
+ (unsigned long) u->nfragments, (unsigned long) u->fragment_size,
+ (unsigned long) nfrags, period_size * u->frame_size);
goto fail;
}
@@ -964,7 +971,7 @@ static void thread_func(void *userdata) {
pa_rtpoll_set_timer_disabled(u->rtpoll);
/* Hmm, nothing to do. Let's sleep */
- if ((ret = pa_rtpoll_run(u->rtpoll, 1)) < 0)
+ if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0)
goto fail;
if (ret == 0)
@@ -984,7 +991,7 @@ static void thread_func(void *userdata) {
goto fail;
}
- if (revents & (POLLERR|POLLNVAL|POLLHUP)) {
+ if (revents & (POLLERR|POLLNVAL|POLLHUP|POLLPRI)) {
if (pa_alsa_recover_from_poll(u->pcm_handle, revents) < 0)
goto fail;
@@ -992,7 +999,7 @@ static void thread_func(void *userdata) {
}
if (revents && u->use_tsched)
- pa_log_debug("Wakeup from ALSA! (%i)", revents);
+ pa_log_debug("Wakeup from ALSA!%s%s", (revents & POLLIN) ? " INPUT" : "", (revents & POLLOUT) ? " OUTPUT" : "");
}
}
diff --git a/src/modules/module-protocol-stub.c b/src/modules/module-protocol-stub.c
index 0e98b1c3..aefd4020 100644
--- a/src/modules/module-protocol-stub.c
+++ b/src/modules/module-protocol-stub.c
@@ -148,7 +148,7 @@
# include <pulsecore/esound.h>
# define TCPWRAP_SERVICE "esound"
# define IPV4_PORT ESD_DEFAULT_PORT
-# define MODULE_ARGUMENTS_COMMON "sink", "source", "auth-anonymous", "cookie", "auth-cookie", "auth-cookie-enabled"
+# define MODULE_ARGUMENTS_COMMON "sink", "source", "auth-anonymous", "cookie", "auth-cookie", "auth-cookie-enabled",
# ifdef USE_TCP_SOCKETS
# include "module-esound-protocol-tcp-symdef.h"
diff --git a/src/modules/module-stream-restore.c b/src/modules/module-stream-restore.c
index 47f5d836..fe79291e 100644
--- a/src/modules/module-stream-restore.c
+++ b/src/modules/module-stream-restore.c
@@ -377,7 +377,7 @@ static pa_hook_result_t source_output_new_hook_callback(pa_core *c, pa_source_ou
pa_log_info("Restoring device for stream %s.", name);
new_data->source = s;
} else
- pa_log_info("Not restroing device for stream %s, because already set", name);
+ pa_log_info("Not restoring device for stream %s, because already set", name);
}
pa_xfree(e);
diff --git a/src/modules/rtp/Makefile b/src/modules/rtp/Makefile
index 316beb72..efe5a336 100644..120000
--- a/src/modules/rtp/Makefile
+++ b/src/modules/rtp/Makefile
@@ -1,13 +1 @@
-# This is a dirty trick just to ease compilation with emacs
-#
-# This file is not intended to be distributed or anything
-#
-# So: don't touch it, even better ignore it!
-
-all:
- $(MAKE) -C ../..
-
-clean:
- $(MAKE) -C ../.. clean
-
-.PHONY: all clean
+../../pulse/Makefile \ No newline at end of file
diff --git a/src/pulse/client-conf.c b/src/pulse/client-conf.c
index 739ef161..58d64642 100644
--- a/src/pulse/client-conf.c
+++ b/src/pulse/client-conf.c
@@ -61,6 +61,7 @@ static const pa_client_conf default_conf = {
.disable_shm = FALSE,
.cookie_file = NULL,
.cookie_valid = FALSE,
+ .shm_size = 0
};
pa_client_conf *pa_client_conf_new(void) {
@@ -99,6 +100,7 @@ int pa_client_conf_load(pa_client_conf *c, const char *filename) {
{ "autospawn", pa_config_parse_bool, NULL },
{ "cookie-file", pa_config_parse_string, NULL },
{ "disable-shm", pa_config_parse_bool, NULL },
+ { "shm-size-bytes", pa_config_parse_size, NULL },
{ NULL, NULL, NULL },
};
@@ -110,6 +112,7 @@ int pa_client_conf_load(pa_client_conf *c, const char *filename) {
table[5].data = &c->autospawn;
table[6].data = &c->cookie_file;
table[7].data = &c->disable_shm;
+ table[8].data = &c->shm_size;
if (filename) {
diff --git a/src/pulse/client-conf.h b/src/pulse/client-conf.h
index 699279aa..4eac467e 100644
--- a/src/pulse/client-conf.h
+++ b/src/pulse/client-conf.h
@@ -31,6 +31,7 @@ typedef struct pa_client_conf {
pa_bool_t autospawn, disable_shm;
uint8_t cookie[PA_NATIVE_COOKIE_LENGTH];
pa_bool_t cookie_valid; /* non-zero, when cookie is valid */
+ size_t shm_size;
} pa_client_conf;
/* Create a new configuration data object and reset it to defaults */
diff --git a/src/pulse/client.conf.in b/src/pulse/client.conf.in
index 8339d651..579bcc20 100644
--- a/src/pulse/client.conf.in
+++ b/src/pulse/client.conf.in
@@ -30,3 +30,4 @@
; cookie-file =
; disable-shm = no
+; shm-size-bytes = 0 # setting this 0 will use the system-default, usually 64 MiB
diff --git a/src/pulse/context.c b/src/pulse/context.c
index 154e5faf..3145d9c8 100644
--- a/src/pulse/context.c
+++ b/src/pulse/context.c
@@ -174,10 +174,10 @@ pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *
pa_client_conf_load(c->conf, NULL);
pa_client_conf_env(c->conf);
- if (!(c->mempool = pa_mempool_new(!c->conf->disable_shm))) {
+ if (!(c->mempool = pa_mempool_new(!c->conf->disable_shm, c->conf->shm_size))) {
if (!c->conf->disable_shm)
- c->mempool = pa_mempool_new(FALSE);
+ c->mempool = pa_mempool_new(FALSE, c->conf->shm_size);
if (!c->mempool) {
context_free(c);
diff --git a/src/pulse/stream.c b/src/pulse/stream.c
index d0c7d67e..ababe176 100644
--- a/src/pulse/stream.c
+++ b/src/pulse/stream.c
@@ -86,7 +86,7 @@ pa_stream *pa_stream_new_with_proplist(
pa_assert(PA_REFCNT_VALUE(c) >= 1);
PA_CHECK_VALIDITY_RETURN_NULL(c, ss && pa_sample_spec_valid(ss), PA_ERR_INVALID);
- PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 12 || (ss->format != PA_SAMPLE_S32LE || ss->format != PA_SAMPLE_S32NE), PA_ERR_NOTSUPPORTED);
+ PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 12 || (ss->format != PA_SAMPLE_S32LE && ss->format != PA_SAMPLE_S32BE), PA_ERR_NOTSUPPORTED);
PA_CHECK_VALIDITY_RETURN_NULL(c, !map || (pa_channel_map_valid(map) && map->channels == ss->channels), PA_ERR_INVALID);
PA_CHECK_VALIDITY_RETURN_NULL(c, name || (p && pa_proplist_contains(p, PA_PROP_MEDIA_NAME)), PA_ERR_INVALID);
@@ -557,7 +557,7 @@ void pa_command_stream_started(pa_pdispatch *pd, uint32_t command, uint32_t tag,
request_auto_timing_update(s, TRUE);
if (s->started_callback)
- s->started_callback(s, s->suspended_userdata);
+ s->started_callback(s, s->started_userdata);
finish:
pa_context_unref(c);
@@ -1851,7 +1851,7 @@ pa_operation* pa_stream_set_name(pa_stream *s, const char *name, pa_stream_succe
if (s->context->version >= 13) {
pa_proplist *p = pa_proplist_new();
- pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, name);
+ pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name);
o = pa_stream_proplist_update(s, PA_UPDATE_REPLACE, p, cb, userdata);
pa_proplist_free(p);
} else {
diff --git a/src/pulsecore/conf-parser.c b/src/pulsecore/conf-parser.c
index 6b0e1d56..58ceab91 100644
--- a/src/pulsecore/conf-parser.c
+++ b/src/pulsecore/conf-parser.c
@@ -166,6 +166,24 @@ int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue,
return 0;
}
+int pa_config_parse_size(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) {
+ size_t *i = data;
+ uint32_t k;
+
+ pa_assert(filename);
+ pa_assert(lvalue);
+ pa_assert(rvalue);
+ pa_assert(data);
+
+ if (pa_atou(rvalue, &k) < 0) {
+ pa_log("[%s:%u] Failed to parse numeric value: %s", filename, line, rvalue);
+ return -1;
+ }
+
+ *i = (size_t) k;
+ return 0;
+}
+
int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata) {
int k;
pa_bool_t *b = data;
diff --git a/src/pulsecore/conf-parser.h b/src/pulsecore/conf-parser.h
index 7eb1fae2..a5174fce 100644
--- a/src/pulsecore/conf-parser.h
+++ b/src/pulsecore/conf-parser.h
@@ -39,8 +39,9 @@ typedef struct pa_config_item {
* NULL */
int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void *userdata);
-/* Generic parsers for integers, booleans and strings */
+/* Generic parsers for integers, size_t, booleans and strings */
int pa_config_parse_int(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata);
+int pa_config_parse_size(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata);
int pa_config_parse_bool(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata);
int pa_config_parse_string(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, void *userdata);
diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c
index ad00f4f4..0bc5cb40 100644
--- a/src/pulsecore/core-util.c
+++ b/src/pulsecore/core-util.c
@@ -42,6 +42,7 @@
#include <dirent.h>
#include <regex.h>
#include <langinfo.h>
+#include <sys/utsname.h>
#ifdef HAVE_STRTOF_L
#include <locale.h>
@@ -1314,31 +1315,43 @@ static char* make_random_dir(mode_t m) {
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";
- char fn[24] = "/tmp/pulse-";
+ const char *tmpdir;
+ char *fn;
+ size_t pathlen;
- fn[sizeof(fn)-1] = 0;
+ if (!(tmpdir = getenv("TMPDIR")))
+ if (!(tmpdir = getenv("TMP")))
+ if (!(tmpdir = getenv("TEMP")))
+ tmpdir = getenv("TEMPDIR");
+
+ if (!tmpdir || !pa_is_path_absolute(tmpdir))
+ tmpdir = "/tmp";
+
+ fn = pa_sprintf_malloc("%s/pulse-XXXXXXXXXXXX", tmpdir);
+ pathlen = strlen(fn);
for (;;) {
- unsigned i;
+ size_t i;
int r;
mode_t u;
int saved_errno;
- for (i = 11; i < sizeof(fn)-1; i++)
+ for (i = pathlen - 12; i < pathlen; i++)
fn[i] = table[rand() % (sizeof(table)-1)];
u = umask((~m) & 0777);
r = mkdir(fn, m);
+
saved_errno = errno;
umask(u);
+ errno = saved_errno;
if (r >= 0)
- return pa_xstrdup(fn);
-
- errno = saved_errno;
+ return fn;
if (errno != EEXIST) {
pa_log_error("Failed to create random directory %s: %s", fn, pa_cstrerror(errno));
+ pa_xfree(fn);
return NULL;
}
}
@@ -1369,6 +1382,7 @@ static int make_random_dir_and_link(mode_t m, const char *k) {
char *pa_get_runtime_dir(void) {
char *d, *k = NULL, *p = NULL, *t = NULL, *mid;
struct stat st;
+ mode_t m;
/* The runtime directory shall contain dynamic data that needs NOT
* to be kept accross reboots and is usuallly private to the user,
@@ -1377,10 +1391,9 @@ char *pa_get_runtime_dir(void) {
* this directory, we link it to a random subdir in /tmp, if it
* was not explicitly configured. */
- if ((d = getenv("PULSE_RUNTIME_PATH"))) {
- mode_t m;
+ m = pa_in_system_mode() ? 0755U : 0700U;
- m = pa_in_system_mode() ? 0755U : 0700U;
+ if ((d = getenv("PULSE_RUNTIME_PATH"))) {
if (pa_make_secure_dir(d, m, (uid_t) -1, (gid_t) -1) < 0) {
pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno));
@@ -1393,6 +1406,11 @@ char *pa_get_runtime_dir(void) {
if (!(d = get_pulse_home()))
goto fail;
+ if (pa_make_secure_dir(d, m, (uid_t) -1, (gid_t) -1) < 0) {
+ pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno));
+ goto fail;
+ }
+
if (!(mid = pa_machine_id())) {
pa_xfree(d);
goto fail;
@@ -2333,7 +2351,7 @@ int pa_reset_sigs(int except, ...) {
int pa_reset_sigsv(const int except[]) {
int sig;
- for (sig = 1; sig < _NSIG; sig++) {
+ for (sig = 1; sig < NSIG; sig++) {
pa_bool_t reset = TRUE;
switch (sig) {
@@ -2445,5 +2463,12 @@ char *pa_machine_id(void) {
/* If no hostname was set we use the POSIX hostid. It's usually
* the IPv4 address. Mit not be that stable. */
return pa_sprintf_malloc("%08lx", (unsigned long) gethostid);
+}
+
+char *pa_uname_string(void) {
+ struct utsname u;
+
+ pa_assert_se(uname(&u) == 0);
+ return pa_sprintf_malloc("%s %s %s %s", u.sysname, u.machine, u.release, u.version);
}
diff --git a/src/pulsecore/core-util.h b/src/pulsecore/core-util.h
index c9e307f5..df8ce3f8 100644
--- a/src/pulsecore/core-util.h
+++ b/src/pulsecore/core-util.h
@@ -191,5 +191,6 @@ pa_bool_t pa_in_system_mode(void);
#define pa_streq(a,b) (!strcmp((a),(b)))
char *pa_machine_id(void);
+char *pa_uname_string(void);
#endif
diff --git a/src/pulsecore/core.c b/src/pulsecore/core.c
index 6f8a2929..5761bbc7 100644
--- a/src/pulsecore/core.c
+++ b/src/pulsecore/core.c
@@ -66,7 +66,7 @@ static int core_process_msg(pa_msgobject *o, int code, void *userdata, int64_t o
static void core_free(pa_object *o);
-pa_core* pa_core_new(pa_mainloop_api *m, int shared) {
+pa_core* pa_core_new(pa_mainloop_api *m, pa_bool_t shared, size_t shm_size) {
pa_core* c;
pa_mempool *pool;
int j;
@@ -74,14 +74,14 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) {
pa_assert(m);
if (shared) {
- if (!(pool = pa_mempool_new(shared))) {
+ if (!(pool = pa_mempool_new(shared, shm_size))) {
pa_log_warn("failed to allocate shared memory pool. Falling back to a normal memory pool.");
- shared = 0;
+ shared = FALSE;
}
}
if (!shared) {
- if (!(pool = pa_mempool_new(shared))) {
+ if (!(pool = pa_mempool_new(shared, shm_size))) {
pa_log("pa_mempool_new() failed.");
return NULL;
}
@@ -138,6 +138,7 @@ pa_core* pa_core_new(pa_mainloop_api *m, int shared) {
c->realtime_scheduling = FALSE;
c->realtime_priority = 5;
c->disable_remixing = FALSE;
+ c->disable_lfe_remixing = FALSE;
for (j = 0; j < PA_CORE_HOOK_MAX; j++)
pa_hook_init(&c->hooks[j], c);
diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
index eb768418..39559082 100644
--- a/src/pulsecore/core.h
+++ b/src/pulsecore/core.h
@@ -124,6 +124,7 @@ struct pa_core {
pa_bool_t running_as_daemon:1;
pa_bool_t realtime_scheduling:1;
pa_bool_t disable_remixing:1;
+ pa_bool_t disable_lfe_remixing:1;
pa_resample_method_t resample_method;
int realtime_priority;
@@ -140,7 +141,7 @@ enum {
PA_CORE_MESSAGE_MAX
};
-pa_core* pa_core_new(pa_mainloop_api *m, int shared);
+pa_core* pa_core_new(pa_mainloop_api *m, pa_bool_t shared, size_t shm_size);
/* Check whether noone is connected to this core */
void pa_core_check_idle(pa_core *c);
diff --git a/src/pulsecore/idxset.c b/src/pulsecore/idxset.c
index b6423efd..24a28db7 100644
--- a/src/pulsecore/idxset.c
+++ b/src/pulsecore/idxset.c
@@ -80,7 +80,7 @@ unsigned pa_idxset_trivial_hash_func(const void *p) {
}
int pa_idxset_trivial_compare_func(const void *a, const void *b) {
- return a != b;
+ return a < b ? -1 : (a > b ? 1 : 0);
}
pa_idxset* pa_idxset_new(pa_hash_func_t hash_func, pa_compare_func_t compare_func) {
@@ -318,8 +318,7 @@ void* pa_idxset_rrobin(pa_idxset *s, uint32_t *idx) {
hash = *idx % NBUCKETS;
- if (!(e = index_scan(s, hash, *idx)))
- return NULL;
+ e = index_scan(s, hash, *idx);
if (e && e->iterate_next)
e = e->iterate_next;
diff --git a/src/pulse/lock-autospawn.c b/src/pulsecore/lock-autospawn.c
index d36b669e..d36b669e 100644
--- a/src/pulse/lock-autospawn.c
+++ b/src/pulsecore/lock-autospawn.c
diff --git a/src/pulse/lock-autospawn.h b/src/pulsecore/lock-autospawn.h
index c04c4bd1..c04c4bd1 100644
--- a/src/pulse/lock-autospawn.h
+++ b/src/pulsecore/lock-autospawn.h
diff --git a/src/pulsecore/memblock.c b/src/pulsecore/memblock.c
index 6d12acdc..400a4e1e 100644
--- a/src/pulsecore/memblock.c
+++ b/src/pulsecore/memblock.c
@@ -680,8 +680,9 @@ static void memblock_replace_import(pa_memblock *b) {
pa_mutex_unlock(seg->import->mutex);
}
-pa_mempool* pa_mempool_new(pa_bool_t shared) {
+pa_mempool* pa_mempool_new(pa_bool_t shared, size_t size) {
pa_mempool *p;
+ char t1[64], t2[64];
p = pa_xnew(pa_mempool, 1);
@@ -692,13 +693,26 @@ pa_mempool* pa_mempool_new(pa_bool_t shared) {
if (p->block_size < PA_PAGE_SIZE)
p->block_size = PA_PAGE_SIZE;
- p->n_blocks = PA_MEMPOOL_SLOTS_MAX;
+ if (size <= 0)
+ p->n_blocks = PA_MEMPOOL_SLOTS_MAX;
+ else {
+ p->n_blocks = (unsigned) (size / p->block_size);
+
+ if (p->n_blocks < 2)
+ p->n_blocks = 2;
+ }
if (pa_shm_create_rw(&p->memory, p->n_blocks * p->block_size, shared, 0700) < 0) {
pa_xfree(p);
return NULL;
}
+ pa_log_debug("Using %s memory pool with %u slots of size %s each, total size is %s",
+ p->memory.shared ? "shared" : "private",
+ p->n_blocks,
+ pa_bytes_snprint(t1, sizeof(t1), (unsigned) p->block_size),
+ pa_bytes_snprint(t2, sizeof(t2), (unsigned) (p->n_blocks * p->block_size)));
+
memset(&p->stat, 0, sizeof(p->stat));
pa_atomic_store(&p->n_init, 0);
diff --git a/src/pulsecore/memblock.h b/src/pulsecore/memblock.h
index efe55b02..b1eab2a9 100644
--- a/src/pulsecore/memblock.h
+++ b/src/pulsecore/memblock.h
@@ -117,7 +117,7 @@ pa_mempool * pa_memblock_get_pool(pa_memblock *b);
pa_memblock *pa_memblock_will_need(pa_memblock *b);
/* The memory block manager */
-pa_mempool* pa_mempool_new(pa_bool_t shared);
+pa_mempool* pa_mempool_new(pa_bool_t shared, size_t size);
void pa_mempool_free(pa_mempool *p);
const pa_mempool_stat* pa_mempool_get_stat(pa_mempool *p);
void pa_mempool_vacuum(pa_mempool *p);
diff --git a/src/pulsecore/prioq.c b/src/pulsecore/prioq.c
new file mode 100644
index 00000000..693dc517
--- /dev/null
+++ b/src/pulsecore/prioq.c
@@ -0,0 +1,256 @@
+/***
+ This file is part of PulseAudio.
+
+ Copyright 2008 Lennart Poettering
+
+ PulseAudio is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation; either version 2 of the License,
+ or (at your option) any later version.
+
+ PulseAudio is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with PulseAudio; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pulse/xmalloc.h>
+
+#include <pulsecore/flist.h>
+
+#include "prioq.h"
+
+struct pa_prioq_item {
+ void *value;
+ unsigned idx;
+};
+
+struct pa_prioq {
+ pa_prioq_item **items;
+ unsigned n_items;
+ unsigned n_allocated;
+ pa_compare_func_t compare_func;
+};
+
+PA_STATIC_FLIST_DECLARE(items, 0, pa_xfree);
+
+pa_prioq *pa_prioq_new(pa_compare_func_t compare_func) {
+
+ pa_prioq *q;
+
+ q = pa_xnew(pa_prioq, 1);
+ q->compare_func = compare_func;
+ q->n_items = 0;
+ q->n_allocated = 64;
+ q->items = pa_xnew(pa_prioq_item*, q->n_allocated);
+
+ return q;
+}
+
+void pa_prioq_free(pa_prioq *q, pa_free2_cb_t free_cb, void *userdata) {
+ pa_prioq_item **i, **e;
+
+ pa_assert(q);
+
+ for (i = q->items, e = q->items + q->n_items; i < e; i++) {
+
+ if (!*i)
+ continue;
+
+ if (free_cb)
+ free_cb((*i)->value, userdata);
+
+ pa_xfree(*i);
+ }
+
+ pa_xfree(q->items);
+ pa_xfree(q);
+}
+
+static void shuffle_up(pa_prioq *q, pa_prioq_item *i) {
+ unsigned j;
+
+ pa_assert(q);
+ pa_assert(i);
+
+ j = i->idx;
+
+ while (j > 0) {
+ unsigned k;
+
+ k = (j-1)/2;
+
+ if (q->compare_func(q->items[k]->value, i->value) < 0)
+ break;
+
+ q->items[k]->idx = j;
+ q->items[j] = q->items[k];
+
+ j = k;
+ }
+
+ i->idx = j;
+ q->items[j] = i;
+
+}
+
+pa_prioq_item* pa_prioq_put(pa_prioq *q, void *p) {
+ pa_prioq_item *i;
+
+ pa_assert(q);
+
+ if (q->n_items >= q->n_allocated) {
+ q->n_allocated = PA_MAX(q->n_items+1, q->n_allocated)*2;
+ q->items = pa_xrealloc(q->items, sizeof(pa_prioq_item*) * q->n_allocated);
+ }
+
+ if (!(i = pa_flist_pop(PA_STATIC_FLIST_GET(items))))
+ i = pa_xnew(pa_prioq_item, 1);
+
+ i->value = p;
+ i->idx = q->n_items++;
+
+ shuffle_up(q, i);
+
+ return i;
+}
+
+void* pa_prioq_peek(pa_prioq *q) {
+ pa_assert(q);
+
+ if (q->n_items <= 0)
+ return NULL;
+
+ return q->items[0]->value;
+}
+
+void* pa_prioq_pop(pa_prioq *q){
+ pa_assert(q);
+
+ if (q->n_items <= 0)
+ return NULL;
+
+ return pa_prioq_remove(q, q->items[0]);
+}
+
+static void swap(pa_prioq *q, unsigned j, unsigned k) {
+ pa_prioq_item *t;
+
+ pa_assert(q);
+ pa_assert(j < q->n_items);
+ pa_assert(k < q->n_items);
+
+ pa_assert(q->items[j]->idx == j);
+ pa_assert(q->items[k]->idx == k);
+
+ t = q->items[j];
+
+ q->items[j]->idx = k;
+ q->items[j] = q->items[k];
+
+ q->items[k]->idx = j;
+ q->items[k] = t;
+}
+
+static void shuffle_down(pa_prioq *q, unsigned idx) {
+
+ pa_assert(q);
+ pa_assert(idx < q->n_items);
+
+ for (;;) {
+ unsigned j, k, s;
+
+ k = (idx+1)*2; /* right child */
+ j = k-1; /* left child */
+
+ if (j >= q->n_items)
+ break;
+
+ if (q->compare_func(q->items[j]->value, q->items[idx]->value) < 0)
+
+ /* So our left child is smaller than we are, let's
+ * remember this fact */
+ s = j;
+ else
+ s = idx;
+
+ if (k < q->n_items &&
+ q->compare_func(q->items[k]->value, q->items[s]->value) < 0)
+
+ /* So our right child is smaller than we are, let's
+ * remember this fact */
+ s = k;
+
+ /* s now points to the smallest of the three items */
+
+ if (s == idx)
+ /* No swap necessary, we're done */
+ break;
+
+ swap(q, idx, s);
+ idx = s;
+ }
+}
+
+void* pa_prioq_remove(pa_prioq *q, pa_prioq_item *i) {
+ void *p;
+
+ pa_assert(q);
+ pa_assert(i);
+ pa_assert(q->n_items >= 1);
+
+ p = i->value;
+
+ if (q->n_items-1 == i->idx) {
+ /* We are the last entry, so let's just remove us and good */
+ q->n_items--;
+
+ } else {
+
+ /* We are not the last entry, we need to replace ourselves
+ * with the last node and reshuffle */
+
+ q->items[i->idx] = q->items[q->n_items-1];
+ q->items[i->idx]->idx = i->idx;
+ q->n_items--;
+
+ shuffle_down(q, i->idx);
+ }
+
+ if (pa_flist_push(PA_STATIC_FLIST_GET(items), i) < 0)
+ pa_xfree(i);
+
+ return p;
+}
+
+unsigned pa_prioq_size(pa_prioq *q) {
+ pa_assert(q);
+
+ return q->n_items;
+}
+
+pa_bool_t pa_prioq_isempty(pa_prioq *q) {
+ pa_assert(q);
+
+ return q->n_items == 0;
+}
+
+void pa_prioq_reshuffle(pa_prioq *q, pa_prioq_item *i) {
+ pa_assert(q);
+ pa_assert(i);
+
+ /* This will move the entry down as far as necessary */
+ shuffle_down(q, i->idx);
+
+ /* And this will move the entry up as far as necessary */
+ shuffle_up(q, i);
+}
diff --git a/src/pulsecore/prioq.h b/src/pulsecore/prioq.h
new file mode 100644
index 00000000..fd3550b7
--- /dev/null
+++ b/src/pulsecore/prioq.h
@@ -0,0 +1,64 @@
+#ifndef foopulsecoreprioqhfoo
+#define foopulsecoreprioqhfoo
+
+/***
+ This file is part of PulseAudio.
+
+ Copyright 2008 Lennart Poettering
+
+ PulseAudio is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ PulseAudio is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with PulseAudio; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
+#include <inttypes.h>
+
+#include <pulsecore/macro.h>
+#include <pulsecore/idxset.h>
+
+/* A heap-based priority queue. Removal and insertion is O(log
+ * n). Removal can happen a the top or at any position referenced by a
+ * pa_prioq_item. */
+
+typedef struct pa_prioq pa_prioq;
+typedef struct pa_prioq_item pa_prioq_item;
+
+/* Instantiate a new prioq with the specified comparison functions */
+pa_prioq* pa_prioq_new(pa_compare_func_t compare_func);
+
+/* Free the prioq. When the prioq is not empty the specified function is called for every entry contained */
+void pa_prioq_free(pa_prioq *q, pa_free2_cb_t free_cb, void *userdata);
+
+/* Store a new item in the prioq. */
+pa_prioq_item* pa_prioq_put(pa_prioq *q, void* data);
+
+/* Get the item on the top of the queue, but don't remove it from the queue*/
+void* pa_prioq_peek(pa_prioq*q);
+
+/* Get the item on the top of the queue, and remove it from thq queue */
+void* pa_prioq_pop(pa_prioq*q);
+
+/* Remove an arbitrary from theq prioq, returning it's data */
+void* pa_prioq_remove(pa_prioq*q, pa_prioq_item *i);
+
+/* The priority of an item was modified. Adjustthe queue to that */
+void pa_prioq_reshuffle(pa_prioq *q, pa_prioq_item *i);
+
+/* Return the current number of items in the prioq */
+unsigned pa_prioq_size(pa_prioq*s);
+
+/* Return TRUE of the prioq is empty */
+pa_bool_t pa_prioq_isempty(pa_prioq *s);
+
+#endif
diff --git a/src/pulsecore/proplist-util.c b/src/pulsecore/proplist-util.c
index 6005775e..4d505f57 100644
--- a/src/pulsecore/proplist-util.c
+++ b/src/pulsecore/proplist-util.c
@@ -37,7 +37,7 @@
void pa_init_proplist(pa_proplist *p) {
int a, b;
-#ifndef HAVE_DECL_ENVIRON
+#if !HAVE_DECL_ENVIRON
extern char **environ;
#endif
char **e;
diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index 6ccee571..5c6dbf44 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -2192,6 +2192,7 @@ static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_ta
if (c->version < 10 || (c->version >= 13 && !shm_on_remote))
do_shm = FALSE;
+#ifdef HAVE_CREDS
if (do_shm) {
/* Only enable SHM if both sides are owned by the same
* user. This is a security measure because otherwise data
@@ -2201,6 +2202,7 @@ static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_ta
if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid)
do_shm = FALSE;
}
+#endif
pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm));
pa_pstream_enable_shm(c->pstream, do_shm);
diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c
index 45cd68c1..b2d512c8 100644
--- a/src/pulsecore/resampler.c
+++ b/src/pulsecore/resampler.c
@@ -716,7 +716,11 @@ static void calc_map_table(pa_resampler *r) {
* channels for LFE. */
for (ic = 0; ic < r->i_ss.channels; ic++) {
- r->map_table[oc][ic] = 1.0f / (float) r->i_ss.channels;
+
+ if (!(r->flags & PA_RESAMPLER_NO_LFE))
+ r->map_table[oc][ic] = 1.0f / (float) r->i_ss.channels;
+ else
+ r->map_table[oc][ic] = 0;
/* Please note that a channel connected to LFE
* doesn't really count as connected. */
@@ -851,7 +855,7 @@ static void calc_map_table(pa_resampler *r) {
}
}
- if (ic_unconnected_lfe > 0) {
+ if (ic_unconnected_lfe > 0 && !(r->flags & PA_RESAMPLER_NO_LFE)) {
/* OK, so there is an unconnected LFE channel. Let's mix
* it into all channels, with factor 0.375 */
@@ -1414,40 +1418,46 @@ static void peaks_resample(pa_resampler *r, const pa_memchunk *input, unsigned i
unsigned j;
j = ((r->peaks.o_counter * r->i_ss.rate) / r->o_ss.rate);
- j = j > r->peaks.i_counter ? j - r->peaks.i_counter : 0;
- if (j >= in_n_frames)
- break;
+ if (j > r->peaks.i_counter)
+ j -= r->peaks.i_counter;
+ else
+ j = 0;
pa_assert(o_index * fz < pa_memblock_get_length(output->memblock));
if (r->work_format == PA_SAMPLE_S16NE) {
unsigned i, c;
- int16_t *s = (int16_t*) ((uint8_t*) src + fz * j);
+ int16_t *s = (int16_t*) ((uint8_t*) src + fz * start);
int16_t *d = (int16_t*) ((uint8_t*) dst + fz * o_index);
- for (i = start; i <= j; i++)
+ for (i = start; i <= j && i < in_n_frames; i++)
+
for (c = 0; c < r->o_ss.channels; c++, s++) {
int16_t n;
n = (int16_t) (*s < 0 ? -*s : *s);
- if (n > r->peaks.max_i[c])
+ if (PA_UNLIKELY(n > r->peaks.max_i[c]))
r->peaks.max_i[c] = n;
}
+ if (i >= in_n_frames)
+ break;
+
for (c = 0; c < r->o_ss.channels; c++, d++) {
- *d = r->peaks.max_i[c];
- r->peaks.max_i[c] = 0;
+ *d = r->peaks.max_i[c];
+ r->peaks.max_i[c] = 0;
}
+
} else {
unsigned i, c;
- float *s = (float*) ((uint8_t*) src + fz * j);
+ float *s = (float*) ((uint8_t*) src + fz * start);
float *d = (float*) ((uint8_t*) dst + fz * o_index);
pa_assert(r->work_format == PA_SAMPLE_FLOAT32NE);
- for (i = start; i <= j; i++)
+ for (i = start; i <= j && i < in_n_frames; i++)
for (c = 0; c < r->o_ss.channels; c++, s++) {
float n = fabsf(*s);
@@ -1455,13 +1465,16 @@ static void peaks_resample(pa_resampler *r, const pa_memchunk *input, unsigned i
r->peaks.max_f[c] = n;
}
+ if (i >= in_n_frames)
+ break;
+
for (c = 0; c < r->o_ss.channels; c++, d++) {
*d = r->peaks.max_f[c];
r->peaks.max_f[c] = 0;
}
}
- start = j+1;
+ start = j;
}
pa_memblock_release(input->memblock);
diff --git a/src/pulsecore/resampler.h b/src/pulsecore/resampler.h
index 5e302a9b..87110cc2 100644
--- a/src/pulsecore/resampler.h
+++ b/src/pulsecore/resampler.h
@@ -49,9 +49,10 @@ typedef enum pa_resample_method {
} pa_resample_method_t;
typedef enum pa_resample_flags {
- PA_RESAMPLER_VARIABLE_RATE = 1,
- PA_RESAMPLER_NO_REMAP = 2, /* implies NO_REMIX */
- PA_RESAMPLER_NO_REMIX = 4
+ PA_RESAMPLER_VARIABLE_RATE = 0x0001U,
+ PA_RESAMPLER_NO_REMAP = 0x0002U, /* implies NO_REMIX */
+ PA_RESAMPLER_NO_REMIX = 0x0004U,
+ PA_RESAMPLER_NO_LFE = 0x0008U
} pa_resample_flags_t;
pa_resampler* pa_resampler_new(
diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index 7d80242f..326a7e2c 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -201,7 +201,8 @@ pa_sink_input* pa_sink_input_new(
data->resample_method,
((flags & PA_SINK_INPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) |
((flags & PA_SINK_INPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) |
- (core->disable_remixing || (flags & PA_SINK_INPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0)))) {
+ (core->disable_remixing || (flags & PA_SINK_INPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0) |
+ (core->disable_lfe_remixing ? PA_RESAMPLER_NO_LFE : 0)))) {
pa_log_warn("Unsupported resampling operation.");
return NULL;
}
diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
index 5df950a8..d76f6e4e 100644
--- a/src/pulsecore/source-output.c
+++ b/src/pulsecore/source-output.c
@@ -171,7 +171,8 @@ pa_source_output* pa_source_output_new(
data->resample_method,
((flags & PA_SOURCE_OUTPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) |
((flags & PA_SOURCE_OUTPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) |
- (core->disable_remixing || (flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0)))) {
+ (core->disable_remixing || (flags & PA_SOURCE_OUTPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0) |
+ (core->disable_lfe_remixing ? PA_RESAMPLER_NO_LFE : 0)))) {
pa_log_warn("Unsupported resampling operation.");
return NULL;
}
diff --git a/src/tests/envelope-test.c b/src/tests/envelope-test.c
index d71eff1c..4a72f5a3 100644
--- a/src/tests/envelope-test.c
+++ b/src/tests/envelope-test.c
@@ -205,7 +205,7 @@ int main(int argc, char *argv[]) {
oil_init();
pa_log_set_maximal_level(PA_LOG_DEBUG);
- pa_assert_se(pool = pa_mempool_new(FALSE));
+ pa_assert_se(pool = pa_mempool_new(FALSE, 0));
pa_assert_se(envelope = pa_envelope_new(&ss));
block = generate_block(pool, &ss);
diff --git a/src/tests/lock-autospawn-test.c b/src/tests/lock-autospawn-test.c
index cb3dc87c..80cfda6a 100644
--- a/src/tests/lock-autospawn-test.c
+++ b/src/tests/lock-autospawn-test.c
@@ -28,7 +28,7 @@
#include <pulsecore/macro.h>
#include <pulsecore/thread.h>
-#include <pulse/lock-autospawn.h>
+#include <pulsecore/lock-autospawn.h>
#include <pulse/util.h>
static void thread_func(void*k) {
diff --git a/src/tests/mcalign-test.c b/src/tests/mcalign-test.c
index c0665822..92e3e14e 100644
--- a/src/tests/mcalign-test.c
+++ b/src/tests/mcalign-test.c
@@ -41,7 +41,7 @@ int main(int argc, char *argv[]) {
pa_mcalign *a;
pa_memchunk c;
- p = pa_mempool_new(0);
+ p = pa_mempool_new(FALSE, 0);
a = pa_mcalign_new(11);
diff --git a/src/tests/memblock-test.c b/src/tests/memblock-test.c
index 6da1b1e9..37b5b403 100644
--- a/src/tests/memblock-test.c
+++ b/src/tests/memblock-test.c
@@ -78,9 +78,9 @@ int main(int argc, char *argv[]) {
const char txt[] = "This is a test!";
- pool_a = pa_mempool_new(1);
- pool_b = pa_mempool_new(1);
- pool_c = pa_mempool_new(1);
+ pool_a = pa_mempool_new(TRUE, 0);
+ pool_b = pa_mempool_new(TRUE, 0);
+ pool_c = pa_mempool_new(TRUE, 0);
pa_mempool_get_shm_id(pool_a, &id_a);
pa_mempool_get_shm_id(pool_b, &id_b);
diff --git a/src/tests/memblockq-test.c b/src/tests/memblockq-test.c
index 7bf992a1..c53945b4 100644
--- a/src/tests/memblockq-test.c
+++ b/src/tests/memblockq-test.c
@@ -63,7 +63,7 @@ int main(int argc, char *argv[]) {
pa_log_set_maximal_level(PA_LOG_DEBUG);
- p = pa_mempool_new(0);
+ p = pa_mempool_new(FALSE, 0);
silence.memblock = pa_memblock_new_fixed(p, (char*) "__", 2, 1);
assert(silence.memblock);
diff --git a/src/tests/mix-test.c b/src/tests/mix-test.c
index 544121fd..759d7690 100644
--- a/src/tests/mix-test.c
+++ b/src/tests/mix-test.c
@@ -201,7 +201,7 @@ int main(int argc, char *argv[]) {
oil_init();
pa_log_set_maximal_level(PA_LOG_DEBUG);
- pa_assert_se(pool = pa_mempool_new(FALSE));
+ pa_assert_se(pool = pa_mempool_new(FALSE, 0));
a.channels = 1;
a.rate = 44100;
diff --git a/src/tests/prioq-test.c b/src/tests/prioq-test.c
new file mode 100644
index 00000000..120b512b
--- /dev/null
+++ b/src/tests/prioq-test.c
@@ -0,0 +1,44 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pulsecore/prioq.h>
+#include <pulsecore/macro.h>
+
+#define N 1024
+
+int main(int argc, char *argv[]) {
+ pa_prioq *q;
+ unsigned i;
+
+ srand(0);
+
+ q = pa_prioq_new(pa_idxset_trivial_compare_func);
+
+ /* Fill in 1024 */
+ for (i = 0; i < N; i++)
+ pa_prioq_put(q, PA_UINT_TO_PTR((unsigned) rand()));
+
+ /* Remove half of it again */
+ for (i = 0; i < N/2; i++){
+ unsigned u = PA_PTR_TO_UINT(pa_prioq_pop(q));
+ pa_log("%16u", u);
+ }
+
+ pa_log("Refilling");
+
+ /* Fill in another 1024 */
+ for (i = 0; i < N; i++)
+ pa_prioq_put(q, PA_UINT_TO_PTR((unsigned) rand()));
+
+
+ /* Remove everything */
+ while (!pa_prioq_isempty(q)) {
+ unsigned u = PA_PTR_TO_UINT(pa_prioq_pop(q));
+ pa_log("%16u", u);
+ }
+
+ pa_prioq_free(q, NULL, NULL);
+
+ return 0;
+}
diff --git a/src/tests/remix-test.c b/src/tests/remix-test.c
index 4777c150..3538d7d4 100644
--- a/src/tests/remix-test.c
+++ b/src/tests/remix-test.c
@@ -58,7 +58,7 @@ int main(int argc, char *argv[]) {
oil_init();
pa_log_set_maximal_level(PA_LOG_DEBUG);
- pa_assert_se(pool = pa_mempool_new(FALSE));
+ pa_assert_se(pool = pa_mempool_new(FALSE, 0));
for (i = 0; maps[i].channels > 0; i++)
for (j = 0; maps[j].channels > 0; j++) {
diff --git a/src/tests/resampler-test.c b/src/tests/resampler-test.c
index 6959127b..2d591867 100644
--- a/src/tests/resampler-test.c
+++ b/src/tests/resampler-test.c
@@ -201,7 +201,7 @@ int main(int argc, char *argv[]) {
oil_init();
pa_log_set_maximal_level(PA_LOG_DEBUG);
- pa_assert_se(pool = pa_mempool_new(FALSE));
+ pa_assert_se(pool = pa_mempool_new(FALSE, 0));
a.channels = b.channels = 1;
a.rate = b.rate = 44100;