diff options
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> @@ -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; |