PulseAudio e reamostragem dos fluxos de áudio
Apesar de constantemente difamado, achincalhado, (injustamente na maioria das vezes) o PulseAudio foi um passo importante para modernizar o áudio no Linux. Ainda existem arestas a aparar, é claro, porém o mais importante podemos considerar pronto.
De forma simplificada, o que o PulseAudio faz é reunir todos os fluxos de áudio das aplicações, uniformizar a especificação das amostras (caso sejam diferentes) e enviar ao ALSA para ele fazer o som tocar. O que é usado do ALSA são os drivers (kernel) e a alsa-lib. O resto, os programas do pacote alsa-utils, não tem mais papel nenhum — pelo menos não quando tudo está funcionando bem. A detecção do hardware de som é toda automática por parte do udev, o que acabou com vários hacks que existiam antigamente.
Pois bem. Quando o ALSA "abre" o hardware de áudio numa detrminada especificação (resolução, taxa de amostragem), o hardware fica travado nesta especificação. Ou seja, se você envia um fluxo de áudio 16-bit, 44,1kHz para ele, você não pode enviar outro, ao mesmo tempo, que seja 24-bit, 48kHz, por exemplo. PS: em hardware de áudio profissional geralmente pode, mas estamos falando de hardware dos pobres mortais aqui.
Então dá para perceber que alguém precisa juntar tudo que o usuário estiver tocando, transformar na mesma especificação e depois enviar ao ALSA. Nos Tempos Antigos, quem fazia isso era a própria alsa-lib. E basicamente só.
Com o PulseAudio, ele passou a ser responsável por esta tarefa, ao mesmo tempo que trouxe vários outros recursos, entre eles podemos destacar dois: controle independente de volume por aplicativo; capacidade de mudar de hardware on-the-fly (trocar da entrada de microfone analógica da placa de som para um microfone USB, por exemplo, sem interromper os aplicativos que estejam usando-o).
Por padrão o PulseAudio tenta configurar o hardware de som na especificação do CD, ou seja, resolução de 16-bit e taxa de amostragem de 44,1kHz. Quando o hardware não suporta alguma dessas características, o PA configura o que for mais próximo — na verdade, o PA conversa com a alsa-lib nesse processo.
Definida a especificação da amostra, todos os fluxos de áudio que o PulseAudio receber que não baterem com a taxa de amostragem configurada serão reamostrados (resample). Reamostrar demanda processamento. O PulseAudio suporta vários modos, desde códigos bem simples (e com resultado bem ruim) até códigos que beiram a precisão matemática (e que usam um caminhão de processamento).
Veja os modos suportados com:
Se no arquivo
Para quem quer a melhor qualidade possível, existem os modos "src-", que usam a libsamplerate. Em ordem decrescente de qualidade (e de uso de processamento):
Mudando a especificação da amostra
Em
(caso estejam comentadas essas linhas, o padrão s16le 44100Hz é usado, ou o que o ALSA disponibilizar para o PA)
Formatos possíveis: u8, s16le, s16be, s24le, s24be, s24-32le, s24-32be, s32le, s32be float32le, float32be, ulaw, alaw
Taxas de amostragem comuns: 44100, 48000, 96000, 192000
Porém precisamos saber o que o hardware suporta, ou melhor, o que o driver suporta. Infelizmente não achei nada em
Requer, além do gcc, do pacote de desenvolvimento da alsa-lib. No Debian e derivados é o pacote
Saída na minha SoundBlaster Live! 5.1:
Saída do áudio integrado da placa-mãe Gigabyte GA-8VM800M:
A diferença que salta aos olhos é que a taxa de amostargem na Live! é configurável entre 4kHz e 96kHz, enquanto no áudio integrado da Gigabyte é fixa em 48kHz.
Levando em conta que boa parte do que se toca num PC hoje em dia são fluxos de áudio de 44,1kHz (MP3 ripadas de CDs, maioria dos vídeos do YouTube, etc.), ter o hardware de áudio fixo em 48kHz faz o PulseAudio ter que reamostrar todos os fluxos de áudio. Por outro lado, vídeos ripados de DVDs (ou os DVDs em si) costumam ter áudio a 48kHz, que não precisariam de reamostragem.
Consultando o PulseAudio
→ http://www.pulseaudio.org/wiki/CLI
Áudio integrado da placa-mãe Gigabyte GA-8VM800M:
Aqui um cliente conectado ao PA (Flash 10.3 no Chromium) via plugin
SoundBlaster Live! 5.1:
Aqui o PA configurou o ALSA em 44,1kHz (
Banshee tocando um arquivo MP3 de 44,1kHz. Essa é a mesma taxa de amostragem usada pelo ALSA; portanto, não é necessário reamostrar (
Vale notar que o GStreamer (framework usado pelo Banshee) se comunica com o PA com resolução 32-bit float (
Para reiniciar o PulseAudio, você pode logar novamente, reiniciar a máquina, ou executar
De forma simplificada, o que o PulseAudio faz é reunir todos os fluxos de áudio das aplicações, uniformizar a especificação das amostras (caso sejam diferentes) e enviar ao ALSA para ele fazer o som tocar. O que é usado do ALSA são os drivers (kernel) e a alsa-lib. O resto, os programas do pacote alsa-utils, não tem mais papel nenhum — pelo menos não quando tudo está funcionando bem. A detecção do hardware de som é toda automática por parte do udev, o que acabou com vários hacks que existiam antigamente.
Pois bem. Quando o ALSA "abre" o hardware de áudio numa detrminada especificação (resolução, taxa de amostragem), o hardware fica travado nesta especificação. Ou seja, se você envia um fluxo de áudio 16-bit, 44,1kHz para ele, você não pode enviar outro, ao mesmo tempo, que seja 24-bit, 48kHz, por exemplo. PS: em hardware de áudio profissional geralmente pode, mas estamos falando de hardware dos pobres mortais aqui.
Então dá para perceber que alguém precisa juntar tudo que o usuário estiver tocando, transformar na mesma especificação e depois enviar ao ALSA. Nos Tempos Antigos, quem fazia isso era a própria alsa-lib. E basicamente só.
Com o PulseAudio, ele passou a ser responsável por esta tarefa, ao mesmo tempo que trouxe vários outros recursos, entre eles podemos destacar dois: controle independente de volume por aplicativo; capacidade de mudar de hardware on-the-fly (trocar da entrada de microfone analógica da placa de som para um microfone USB, por exemplo, sem interromper os aplicativos que estejam usando-o).
Por padrão o PulseAudio tenta configurar o hardware de som na especificação do CD, ou seja, resolução de 16-bit e taxa de amostragem de 44,1kHz. Quando o hardware não suporta alguma dessas características, o PA configura o que for mais próximo — na verdade, o PA conversa com a alsa-lib nesse processo.
Definida a especificação da amostra, todos os fluxos de áudio que o PulseAudio receber que não baterem com a taxa de amostragem configurada serão reamostrados (resample). Reamostrar demanda processamento. O PulseAudio suporta vários modos, desde códigos bem simples (e com resultado bem ruim) até códigos que beiram a precisão matemática (e que usam um caminhão de processamento).
Veja os modos suportados com:
$ pulseaudio --dump-resample-methods src-sinc-best-quality src-sinc-medium-quality src-sinc-fastest src-zero-order-hold src-linear trivial speex-float-0 speex-float-1 speex-float-2 speex-float-3 speex-float-4 speex-float-5 speex-float-6 speex-float-7 speex-float-8 speex-float-9 speex-float-10 speex-fixed-0 speex-fixed-1 speex-fixed-2 speex-fixed-3 speex-fixed-4 speex-fixed-5 speex-fixed-6 speex-fixed-7 speex-fixed-8 speex-fixed-9 speex-fixed-10 ffmpeg auto copy peaks
Se no arquivo
/etc/pulse/daemon.conf
a opção resample-method
estiver comentada, é usado por padrão speex-float-3
. As distribuições Linux costumam customizar (o Ubuntu usa speex-float-1
). Os modos "speex" usam código da libspeex, que são equilibrados: qualidade decente sem moer o processador. "float" indica que necessitam de um processador com FPU (co-processador aritmético) e "fixed" não. Em desktops não faz muito sentido essa diferenciação, afinal temos FPU nos processadores desde o i486DX, porém em dispositivos embarcados é importante. Quanto menor o número dos modos "speex", menor o uso de processamento e menor a qualidade.Para quem quer a melhor qualidade possível, existem os modos "src-", que usam a libsamplerate. Em ordem decrescente de qualidade (e de uso de processamento):
src-sinc-best-quality
, src-sinc-medium-quality
, src-sinc-fastest
, src-zero-order-hold
, src-linear
src-sinc-best-quality
é uma draga de processamento. Não se espante em ver o processo do PulseAudio consumindo 20% do seu Core i5 quando estiver fazendo reamostragem num par de fluxos de áudio. Das opções "src-" eu fico com src-sinc-fastest
ou no máximo src-sinc-medium-quality
.Mudando a especificação da amostra
Em
/etc/pulse/daemon.conf
default-sample-format = s16le default-sample-rate = 44100
(caso estejam comentadas essas linhas, o padrão s16le 44100Hz é usado, ou o que o ALSA disponibilizar para o PA)
Formatos possíveis: u8, s16le, s16be, s24le, s24be, s24-32le, s24-32be, s32le, s32be float32le, float32be, ulaw, alaw
Taxas de amostragem comuns: 44100, 48000, 96000, 192000
Porém precisamos saber o que o hardware suporta, ou melhor, o que o driver suporta. Infelizmente não achei nada em
/proc
ou /sys
que seja consistente para obter essa informação. Na lista de discussão do ALSA, foi postado tempos atrás um pequeno programa em C que serve para este fim: http://article.gmane.org/gmane.linux.alsa.user/32525$ gcc -o hw_params hw_params.c -lasound
Requer, além do gcc, do pacote de desenvolvimento da alsa-lib. No Debian e derivados é o pacote
libasound2-dev
; no Fedora e derivados é o alsa-lib-devel
.Saída na minha SoundBlaster Live! 5.1:
$ ./hw_params Device: hw (type: HW) Access types: MMAP_INTERLEAVED RW_INTERLEAVED Formats: U8 S16_LE Channels: 1 2 Sample rates: 4000-96000 Interrupt interval: 166-16384000 us Buffer size: 666-16384000 us
Saída do áudio integrado da placa-mãe Gigabyte GA-8VM800M:
$ ./hw_params Device: hw (type: HW) Access types: MMAP_INTERLEAVED RW_INTERLEAVED Formats: U8 S16_LE Channels: 1 2 Sample rates: 48000 Interrupt interval: 166-682667 us Buffer size: 333-1365334 us
A diferença que salta aos olhos é que a taxa de amostargem na Live! é configurável entre 4kHz e 96kHz, enquanto no áudio integrado da Gigabyte é fixa em 48kHz.
Levando em conta que boa parte do que se toca num PC hoje em dia são fluxos de áudio de 44,1kHz (MP3 ripadas de CDs, maioria dos vídeos do YouTube, etc.), ter o hardware de áudio fixo em 48kHz faz o PulseAudio ter que reamostrar todos os fluxos de áudio. Por outro lado, vídeos ripados de DVDs (ou os DVDs em si) costumam ter áudio a 48kHz, que não precisariam de reamostragem.
Consultando o PulseAudio
→ http://www.pulseaudio.org/wiki/CLI
Áudio integrado da placa-mãe Gigabyte GA-8VM800M:
$ pacmd list-sinks Welcome to PulseAudio! Use "help" for usage information. >>> 1 sink(s) available. * index: 0 name: <alsa_output.pci-0000_00_11.5.analog-stereo> driver: <module-alsa-card.c> flags: HARDWARE HW_MUTE_CTRL HW_VOLUME_CTRL DECIBEL_VOLUME LATENCY DYNAMIC_LATENCY state: RUNNING suspend cause: priority: 9959 volume: 0: 41% 1: 41% 0: -23,32 dB 1: -23,32 dB balance 0,00 base volume: 63% -12,00 dB volume steps: 65537 muted: no current latency: 19,58 ms max request: 3 KiB max rewind: 64 KiB monitor source: 0 sample spec: s16le 2ch 48000Hz channel map: front-left,front-right Stereo used by: 1 linked by: 1 configured latency: 20,00 ms; range is 0,50 .. 341,33 ms card: 0 <alsa_card.pci-0000_00_11.5> module: 4 properties: alsa.resolution_bits = "16" device.api = "alsa" device.class = "sound" alsa.class = "generic" alsa.subclass = "generic-mix" alsa.name = "VIA 8237" alsa.id = "VIA 8237" alsa.subdevice = "0" alsa.subdevice_name = "subdevice #0" alsa.device = "0" alsa.card = "0" alsa.card_name = "VIA 8237" alsa.long_card_name = "VIA 8237 with ALC655 at 0xbc00, irq 22" alsa.driver_name = "snd_via82xx" device.bus_path = "pci-0000:00:11.5" sysfs.path = "/devices/pci0000:00/0000:00:11.5/sound/card0" device.bus = "pci" device.vendor.id = "1106" device.vendor.name = "VIA Technologies, Inc." device.product.id = "3059" device.product.name = "VT8233/A/8235/8237 AC97 Audio Controller" device.form_factor = "internal" device.string = "front:0" device.buffering.buffer_size = "65536" device.buffering.fragment_size = "32768" device.access_mode = "mmap+timer" device.profile.name = "analog-stereo" device.profile.description = "Estéreo analógico" device.description = "Áudio interno Estéreo analógico" alsa.mixer_name = "Realtek ALC655 rev 1" alsa.components = "AC97a:414c4761" module-udev-detect.discovered = "1" device.icon_name = "audio-card-pci" ports: analog-output;output-amplifier-on: Saída analógica / Amplificador (priority 9910) analog-output;output-amplifier-off: Saída analógica / Sem amplificador (priority 9900) analog-output-mono;output-amplifier-on: Saída analógica monofônica / Amplificador (priority 5010) analog-output-mono;output-amplifier-off: Saída analógica monofônica / Sem amplificador (priority 5000) analog-output-lfe-on-mono;output-amplifier-on: Saída analógica (LFE) / Amplificador (priority 4010) analog-output-lfe-on-mono;output-amplifier-off: Saída analógica (LFE) / Sem amplificador (priority 4000) active port: <analog-output;output-amplifier-on> >>>
sample spec: s16le 2ch 48000Hz
é a forma como o PA configurou o ALSA.$ pacmd list-sink-inputs Welcome to PulseAudio! Use "help" for usage information. >>> 1 sink input(s) available. index: 2 driver: <protocol-native.c> flags: state: RUNNING sink: 0 <alsa_output.pci-0000_00_11.5.analog-stereo> volume: 0: 100% 1: 100% 0: 0,00 dB 1: 0,00 dB balance 0,00 muted: no current latency: 482,99 ms requested latency: 20,00 ms sample spec: s16le 2ch 44100Hz channel map: front-left,front-right Stereo resample method: src-sinc-fastest module: 8 client: 8 <ALSA plug-in [chromium]> properties: media.name = "ALSA Playback" application.name = "ALSA plug-in [chromium]" native-protocol.peer = "UNIX socket client" native-protocol.version = "16" application.process.id = "793" application.process.user = "marcos" application.process.host = "PENTIUM4" application.process.binary = "chromium" window.x11.display = ":0.0" application.language = "pt_BR.UTF-8" application.process.machine_id = "a9cc6e94ec58167d02a07e8500000206" application.process.session_id = "a9cc6e94ec58167d02a07e8500000206-1307821349.641491-1084107650" application.icon_name = "chromium" module-stream-restore.id = "sink-input-by-application-name:ALSA plug-in [chromium]" >>>
Aqui um cliente conectado ao PA (Flash 10.3 no Chromium) via plugin
pulse
de emulação do ALSA pelo PA. Como o áudio é 44,1kHz (sample spec: s16le 2ch 44100Hz
) e o ALSA está usando 48kHz (a única taxa de amostragem suportada pelo driver), o PA está reamostrando via libsamplerate "fastest" (resample method: src-sinc-fastest
), que eu configurei no /etc/pulse/daemon.conf
com a opção resample-method
. Para baixar o uso de processamento, posso escolher um modo de reamostragem mais simples, como os da libspeex.SoundBlaster Live! 5.1:
$ pacmd list-sinks Welcome to PulseAudio! Use "help" for usage information. >>> 1 sink(s) available. * index: 0 name: <alsa_output.pci-0000_03_05.0.analog-stereo> driver: <module-alsa-card.c> flags: HARDWARE HW_MUTE_CTRL HW_VOLUME_CTRL DECIBEL_VOLUME LATENCY DYNAMIC_LATENCY state: RUNNING suspend cause: priority: 9059 volume: 0: 22% 1: 22% 0: -39,67 dB 1: -39,67 dB balance 0,00 base volume: 63% -12,00 dB volume steps: 65537 muted: no current latency: 89,64 ms max request: 15 KiB max rewind: 64 KiB monitor source: 0 sample spec: s16le 2ch 44100Hz channel map: front-left,front-right Stereo used by: 1 linked by: 1 configured latency: 90,00 ms; range is 0,50 .. 371,52 ms card: 0 <alsa_card.pci-0000_03_05.0> module: 4 properties: alsa.resolution_bits = "16" device.api = "alsa" device.class = "sound" alsa.class = "generic" alsa.subclass = "generic-mix" alsa.name = "ADC Capture/Standard PCM Playback" alsa.id = "emu10k1" alsa.subdevice = "0" alsa.subdevice_name = "subdevice #0" alsa.device = "0" alsa.card = "0" alsa.card_name = "SB Live! 5.1 [SB0220]" alsa.long_card_name = "SB Live! 5.1 [SB0220] (rev.10, serial:0x80651102) at 0xe800, irq 20" alsa.driver_name = "snd_emu10k1" device.bus_path = "pci-0000:03:05.0" sysfs.path = "/devices/pci0000:00/0000:00:14.4/0000:03:05.0/sound/card0" device.bus = "pci" device.vendor.id = "1102" device.vendor.name = "Creative Labs" device.product.id = "0002" device.product.name = "SB Live! EMU10k1" device.string = "front:0" device.buffering.buffer_size = "65536" device.buffering.fragment_size = "65536" device.access_mode = "mmap+timer" device.profile.name = "analog-stereo" device.profile.description = "Estéreo analógico" device.description = "SB Live! EMU10k1 Estéreo analógico" alsa.mixer_name = "SigmaTel STAC9708,11" alsa.components = "AC97a:83847608" module-udev-detect.discovered = "1" device.icon_name = "audio-card-pci" ports: output-amplifier-on: Amplificador (priority 10) output-amplifier-off: Sem amplificador (priority 0) active port: <output-amplifier-on> >>>
Aqui o PA configurou o ALSA em 44,1kHz (
sample spec: s16le 2ch 44100Hz
), que é suportado pelo driver.$ pacmd list-sink-inputs Welcome to PulseAudio! Use "help" for usage information. >>> 1 sink input(s) available. index: 59 driver: <protocol-native.c> flags: START_CORKED state: RUNNING sink: 0 <alsa_output.pci-0000_03_05.0.analog-stereo> volume: 0: 100% 1: 100% 0: 0,00 dB 1: 0,00 dB balance 0,00 muted: no current latency: 104,74 ms requested latency: 90,00 ms sample spec: float32le 2ch 44100Hz channel map: front-left,front-right Stereo resample method: copy module: 8 client: 85 <Banshee> properties: media.name = "\"The Best\" por \"Tina Turner\"" application.name = "Banshee" native-protocol.peer = "UNIX socket client" native-protocol.version = "16" application.process.id = "4170" application.process.user = "marcos" application.process.host = "ATHLON" application.process.binary = "mono" application.icon_name = "media-player-banshee" window.x11.display = ":0.0" application.language = "pt_BR.UTF-8" application.process.machine_id = "f9d0817e2c946b346ff241e30000000a" application.process.session_id = "f9d0817e2c946b346ff241e30000000a-1307733263.86396-659648757" module-stream-restore.id = "sink-input-by-application-name:Banshee" media.title = "The Best" media.artist = "Tina Turner" >>>
Banshee tocando um arquivo MP3 de 44,1kHz. Essa é a mesma taxa de amostragem usada pelo ALSA; portanto, não é necessário reamostrar (
resample method: copy
).Vale notar que o GStreamer (framework usado pelo Banshee) se comunica com o PA com resolução 32-bit float (
sample spec: float32le 2ch 44100Hz
), que previne, em teoria, clipping entre o tocador e o PA: http://xiph.org/video/vid1.shtml (14:13).Para reiniciar o PulseAudio, você pode logar novamente, reiniciar a máquina, ou executar
pulseaudio -k
como usuário normal. Isso encerrará o programa, mas o PA será iniciado novamente em seguida automaticamente, relendo o arquivo de configuração.
Comentários
Postar um comentário