Traducción al Español que hice de sndio. Este trabajo está licenciada por el Autor de este sitio bajo los mismos términos y condiciones de la web antes citada y por la Licencia FDL 1.3.
sndio es una pequeña parte del marco de audio y MIDI del proyecto OpenBSD y portado a FreeBSD, Linux y NetBSD. Proporciona un servidor ligero de audio y MIDI y una API de espacio de usuario totalmente documentada para acceder al servidor o al hardware directamente de una manera uniforme. sndio está diseñado para funcionar con aplicaciones de escritorio, pero presta especial atención a los mecanismos de sincronización y la confiabilidad requeridas por las aplicaciones musicales. La confiabilidad a través de la simplicidad es parte de los objetivos del proyecto.
Este código fuente se construye en cualquier sistema OpenBSD, Linux y FreeBSD sin modificaciones. Los parches para hacer que sndio funcione en NetBSD están disponibles en el árbol de puertos.
Hay binarios disponibles para los siguientes sistemas operativos.
Muchos programas de código abierto, incluyendo los principales reproductores multimedia, navegadores web, librerías de audio y utilidades que soportan sndio de forma nativa. Otros programas tienen parches en el árbol de puertos de OpenBSD esperando integración en fases previas.
sndio es una mejora del audio de OpenBSD y sub-sistemas MIDI. Cuenta con un servidor de audio y MIDI, y provee una nueva API basada una la biblioteca. Este marco está diseñado con ciertas restricciones de aplicaciones de audio en mente: estricto control de latencia y sincronización precisa entre transmisiones de audio. Admite las conversiones de remuestreo y formato al vuelo, compartiendo dispositivos entre múltiples aplicaciones, sea un dispositivo en múltiples subdispositivos y consecuente sincronización con aplicaciones que no son de audio. La simplicidad de la arquitectura, el diseño y la implementación son lo más importante, y lo que intentan obtener es una herramienta ligera, rápida y confiable.
Las aplicaciones de escritorio y de audio musical requieren que el sistema operativo exponga el hardware de audio y MIDI. Pero hay un desfase entre los requisitos de las aplicaciones y lo que ofrece el hardware. El subsistema de audio de alto nivel, una capa intermedia entre las aplicaciones y los controladores de dispositivos, se encarga de llenar ese vacío. Puede utilizarse para:
NetBSD tiene un kernel de audio que sólo se encarga de las conversiones de formato y el remuestreo 4; permite ejecutar casi todas las aplicaciones en la mayoría del hardware soportado, pero no permite ejecutar múltiples aplicaciones de audio simultáneamente. FreeBSD tiene un espacio de trabajo en el núcleo similar que también puede dividir dispositivos hardware en múltiples dispositivos lógicos y aplicar efectos digitales sobre la marcha 5; permite compartir dispositivos entre múltiples programas, pero no proporciona ningún mecanismo a nivel de sistema para sincronizarlos. OSS es un kernel framework comercial de código abierto proporcionado por Front technologies con características similares al de FreeBSD. Todas estas implementaciones exponen API basadas en llamadas al sistema (en contraposición a las bibliotecas). Linux utiliza ALSA: un marco de trabajo rico y complejo que se ejecuta como una biblioteca de espacio de usuario 6. Se basa en extensiones (plug-ins) que procesan flujos de audio sobre la marcha. Existen extensiones para prácticamente todo: mezclas, efectos, conversiones, remuestreo, etc.
Nota
4 El rango dinámico está definido por: 20 log (a/aO) donde a es la amplitud máxima, y a0 es la amplitud mínima de la señal. Con muestras de 16 bits, la amplitud máxima es 216, y la amplitud mínima es 1. El rango dinámico es así: 20 log 216 ≃96dB.
Nota
5 Esta declaración es falsa para las interfaces de audio profesionales que pueden admitir hasta 120 dB.
Nota
6 Cualquier señal continua con un espectro limitado se puede muestrear y convertir nuevamente al original sin pérdida de información (Teorema de Shanon). Con este punto de vista, el remuestreo consiste simplemente en calcular la señal continua y volver a muestrearla a la nueva solicitud.
Para superar las limitaciones del subsistema de audio, se pueden usar ciertas bibliotecas y servidores de audio del espacio de usuarios. Por ejemplo, los proyectos GNOME y KDE solían usar Esound y Art, superar las limitaciones del subsistema de audio de Linux antes de que ALSA estuviera disponible; ahora son reemplazados por Pulse, que tiene aún más funciones que los complementos ALSA 7 y 8.
Nota
7 Por ejemplo, al procesar una señal grabada en hardware con un rango dinámico de 96 dB, el ruido generado por el procesamiento debe ser tal que la relación señal sobre ruido se mantenga por encima de 96 dB.
Nota
8 Pero probablemente los programas que usan E/S de bloqueo rara vez necesitan eventos asincrónicos.
Los anteriores marcos de trabajo en el kernel o en el espacio de usuario suponen que las aplicaciones de audio son independientes, es decir, que la sincronización o el intercambio de datos entre aplicaciones no son gestionados por el subsistema de audio. Este tipo de marcos son útiles para la producción musical (u otras tareas de audio más complejas) siempre que todo el procesamiento relacionado con el audio se realice dentro de un único programa monolítico. El marco de trabajo (framework) jack supera esta limitación: permite que los programas cooperen: pueden pasarse datos de forma sincrónica entre ellos; además, jack proporciona un mecanismo de sincronización para aplicaciones que no son de audio. Por otro lado, jack sólo admite un formato de muestreo y funciona a una frecuencia de muestreo fija, lo cual es aceptable para aplicaciones musicales. En teoría, jack podría utilizarse también para escritorio, pero las distribuciones de escritorio de Linux han privilegiado otros marcos de trabajo.
El marco de trabajo sndio propuesto intenta cumplir con la mayoría de los requisitos de las aplicaciones de escritorio, pero presta especial atención a los mecanismos de sincronización requeridos por las aplicaciones musicales. La implementación actual admite conversiones, remuestreo, mezcla, mapeo de canales, división de dispositivos y sincronización de transmisiones de audio. Además, el volumen de aplicación y la sincronización están controlados por protocolos MIDI estándar, lo que permite la interoperabilidad no solo con aplicaciones MIDI sino también con hardware MIDI conectado a la máquina. Estos aspectos son novedosos en el mundo Unix. La simplicidad y la robustez de la arquitectura, el diseño y la implementación son parte de los requisitos; Por lo tanto, no se proporcionan ciertas características complicadas o no esenciales (por ejemplo, efectos, monitoreo, transparencia de red).
Primero, presentamos el problema que sndio intenta resolver y los objetivos del proyecto. Luego discutimos todas las opciones técnicas en el debate para demostrar que son una consecuencia natural de los objetivos del proyecto. Luego presentamos la arquitectura sndio resultante. Finalmente mostramos pocos casos de uso para ilustrar cómo se usa en la practica.
Nota
1 Escriba programas que hagan una cosa y lo hagan bien. Escriba programas para trabajar juntos. Doug McIlroy.
El rendimiento está relacionado con el tiempo de CPU consumido para realizar una tarea determinada, mientras que la capacidad de respuesta mide qué tan rápido se procesa un evento. No existe una relación directa entre el rendimiento y la capacidad de respuesta: dependiendo de para qué esté diseñado un programa, puede tener un mal rendimiento y una buena capacidad de respuesta o lo contrario
Un servidor de audio es un proceso limitado de E/S: después de todo, se supone que es solo una capa delgada entre la aplicación y el controlador del dispositivo. Por lo tanto, su consumo total de CPU es muy pequeño y se supone que es insignificante en comparación con los recursos de CPU disponibles en la máquina. Entonces "desperdiciar" ciclos de la CPU no son un problema, ya que el tiempo total de CPU consumido permanece insignificante.
La capacidad de respuesta, por otro lado, es de primera importancia: por ejemplo, el servidor de audio debe producir datos para reproducir tan pronto como el dispositivo lo solicite, para reducir al mínimo la posibilidad de que se agote el búfer, lo que provocaría un sonido entrecortado. Del mismo modo, un evento MIDI «nota de reproducción» procedente de un teclado MIDI debe procesarse inmediatamente y transmitirse al sintetizador que producirá el sonido real.
En los sistemas similares a UNIX, se accede al hardware de audio a través de un controlador de dispositivo de caracteres. El código de conversión, mezcla y remuestreo es una capa intermedia entre el controlador del dispositivo y la aplicación. Solo el controlador del dispositivo debe ejecutarse en el espacio del núcleo; Las conversiones y la mezcla se pueden realizar en el espacio del usuario como un proceso de usuario regular o en modo núcleo (kernel).
En una implementación de espacio de usuario, la aplicación produce datos de audio, los transmite al servidor de audio, que a su vez los procesa y los transmite al kernel. En una implementación de solo núcleo, la aplicación produce datos de audio y los transmite directamente al núcleo, que hace las conversiones y transmite el resultado al hardware.
En una implementación exclusiva de núcleo, la comunicación entre un proceso de espacio de usuario y el núcleo utiliza llamadas del sistema de lectura y escritura que copian datos de un espacio de direcciones a otro; Obviamente, esta copia de datos es inútil. En la implementación de un espacio de usuario, las cosas son aún peores: la aplicación transmite datos al servidor de audio utilizando sockets que implica dos copias adicionales de los datos
La copia de datos pueden consumir casi tanto tiempo de CPU como procesamiento, pero generalmente esto no es un problema siempre que el tiempo total de CPU consumido sea insignificante. Por ejemplo, en un SL-C32002 2 afilado, que consideramos "no muy rápido", la sobrecarga de la copia adicional es de alrededor del 50% del consumo de CPU, lo que puede parecer significativo. Sin embargo, esto corresponde a solo el 0.5% del tiempo de CPU disponible en la máquina, que consideraremos como aceptable 3.
Nota
2 Esta máquina tiene un procesador Intel PXA27X a 416MHz y ejecuta el puerto zaurus de OpenBSD.
3 La estimación aproximada del porcentaje de tiempo de CPU adicional dedicado a copiar datos entre dos espacios de dirección se obtiene fácilmente comparando los
usos de la CPU de los siguientes dos comando:
$ dd if=/dev/zero | dd of=/dev/null
$ aucat -n -i /dev/zero -o - | dd of=/dev/null
El segundo comando ejecuta el servidor de audio aucat en modo Loopback; En este modo utiliza su salida y entrada estándar para reproducir y como dispositivos de
grabación.
El problema básico de la copia innecesaria de datos no tiene que ver con la implementación del núcleo frente a la del espacio de usuario; de hecho, una implementación exclusiva de este ya está sujeta a la copia innecesaria de datos. El problema básico está en no usar memoria compartida para la comunicación de audio. Este es un problema general; dejamos el cambio del esquema de intercambio de datos de audio de OpenBSD a copia cero para un proyecto futuro, y no lo tenemos en cuenta en este diseño.
La latencia de audio es el tiempo que hay entre: cuando la aplicación comienza a proporcionar muestras al sistema y el usuario las escucha. Las muestras se almacenan en búfer y los búferes son usados por el hardware de audio a una velocidad constante (la frecuencia de muestreo), por lo que la latencia es simplemente proporcional al tamaño del búfer.
Si los búferes se almacenan en la memoria del núcleo o la memoria del espacio de usuario: no importa para la latencia. Lo único que es importante para la latencia es el uso del búfer de extremo a extremo.
Cuando se agota el búfer de reproducción, la interfaz de audio ya no tiene muestras que reproducir, e inserta silencio en dicha reproducción, haciendo que el sonido se entrecorte. El agotamiento del búfer (overrun) puede hacer que la aplicación pierda la sincronización; aunque esto es molesto para la sincronización de vídeo y audio, es catastrófico para el rendimiento de la música.
En una implementación de núcleo, este procesa los datos y los transmite al dispositivo de audio en una sola toma, es decir, sin que se adelante. En comparación con la implementación del espacio de usuario, esto mismo en el núcleo no está sujeto a insuficiencias de proceso causados solo por el servidor de audio.
Se puede argumentar que, en el caso de una implementación en espacio de usuario, puede haber demoras causadas únicamente por el servidor, es decir, la aplicación se ejecuta a tiempo pero la ejecución del servidor se retrasa. La experiencia del autor es que esto nunca ocurre: todos los procesos están igualmente sujetos a retrasos. Además, cuanto más intensivo es un proceso para la CPU, más posibilidades tiene de no ejecutarse, y uno de los principales requisitos para la implementación de sndio es que sea ligera.
Sólo las operaciones que involucran a todos los flujos, como la mezcla, deben implementarse estrictamente en el proceso del servidor. Dado que las conversiones, el remuestreo y el mapeo de canales son específicos de un único flujo, pueden ser realizados por la propia aplicación, por ejemplo incluyendo funciones para leer y escribir muestras. En ambas implementaciones, el código es el mismo y se ejecuta en espacio de usuario.
La principal ventaja del enfoque usando biblioteca es no requerir el servidor de audio si el usuario planea ejecutar solo una transmisión. La ventaja del enfoque único del servidor es ser más simple para el desarrollador y los puntos de vista del usuario: la implementación es más simple porque todo el procesamiento ocurre en el mismo lugar y el usuario tiene un solo programa para configurar (el servidor).
Elegimos el enfoque de solo servidor para la implementación actual para su simplicidad, sin embargo, cambiar al enfoque de la biblioteca es solo una cuestión de esfuerzo de integración: pegar el código del servidor a la biblioteca y agregar los archivos de configuración necesarios.
Las muestras que usan 16 bits de precisión dan un rango dinámico de unos 96 dB 1, lo que permite distinguir el leve susurro de las hojas (aprox. 10 dB) superpuesto al sonido de un martillo neumático a 1 mtr. (aprox. 100 dB). Desde este punto de vista, la precisión de 16 bits parece suficiente para el procesamiento de audio.
Nota
1 El rango dinámico está definido por: 20 log a / a0
Donde a es la amplitud máxima, y a0 es la amplitud mínima de la señal. Con muestras de 16 bits, la amplitud máxima es 216, y la amplitud mínima es 1. El rango
dinámico es así: 20 log 216 ≃96dB
Sin embargo, el hardware moderno admite muestras de 24 bits y podría manejar teóricamente el rango dinámico de 144dB, que es mucho más grande que el rango dinámico del oído humano (aproximadamente 120dB). Sin embargo, las piezas analógicas en el hardware de audio rara vez alcanzan 144dB de rango dinámico, y en la mayoría de los casos está más cerca de 96dB que a 144dB. En otras palabras, en la mayoría de los casos, muestras de 16 bits son más significativas que muestras de 24 bits, ya que en realidad la mayoría de los bits significativos de las muestras de 24 bits son audibles, y los bits menos significativos están ocultos por el ruido y la distorsión 5.
Nota
5 Esta declaración es falsa para las interfaces de audio profesionales que pueden admitir hasta 120dB.
Por otro lado, el procesamiento de precisión de 16 bits requiere aritmética de 32 bits y la precisión de 24 bits requeriría aritmética de 48 bits. El servidor de audio sndio está diseñado para ser rápido incluso en máquinas más lentas de 32 bits, como el puerto zaurus que admite 416MHz Intel PXA27X ARM CPU. Por eso, dado el pequeño beneficio de la precisión de 24 bits, usamos precisión de 16 bits.
Sin embargo, cambiar la implementación de precisión de 16 bits a 24 bits es casi tan simple como cambiar el tipo entero utilizado para almacenar muestras.