¿Qué archivos de encabezado debe incluir snd_pcm_open?
Diagrama de secuencia snd_pcm_open
Análisis de código detallado (tomando la reproducción como ejemplo)
Problemas introducidos
alsa_utils aplay.
Utilice punteros de función en la interfaz de reproducción para implementar las siguientes definiciones específicas
static snd_pcm_sframes_t (*writei_func)(snd_pcm_t *handle, const void *buffer, snd_pcm_uframes_t size);
Iniciar sesión Copia
Asignado de la siguiente manera
writei_func = snd_pcm_writei;
readi_func = snd_pcm_readi
writen_func = snd_pcm_writen
;readn_func = snd_pcm_readn;
Copiar después de iniciar sesión
snd_pcm_writei escribe en el flujo de datos PCM llamando a _snd_pcm_writei. El prototipo de función de _snd_pcm_writei es el siguiente
snd_pcm_sframes_t _snd_pcm_writei estático en línea. ( snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t tamaño)
{
/* Manejar el bloqueo en la devolución de llamada*/
if (!writei) p>
return -ENOSYS;
return pcm-gt; fast_ops-gt; writei(pcm-gt; fast_op_arg, buffer, tamaño); // Reproducir puntero de función
}
Copiar después de iniciar sesión
_snd_pcm_writei llama a pcm-gt;fast_ops-gt;writei para la operación real.
Al observar el código fuente de aplay.c, nunca hemos encontrado la ubicación donde se inicializa la estructura const snd_pcm_fast_ops_t *fast_ops en el dispositivo PCM, por lo que es muy probable que la operación correspondiente se realice en snd_pcm_open.
Análisis detallado de snd_pcm_open
La llamada a snd_pcm_open en alsa_utils aplay.c es la siguiente
...
char *pcm_name = "predeterminado ";
...
err = snd_pcm_open(amp; handle, pcm_name, stream, open_mode);
if (err lt; 0 ) {
error(_("error de apertura de audio: s"), snd_ strerror(err));
Devuelve 1; >
Copiar después de iniciar sesión
El prototipo de la función snd_pcm_open es el siguiente
int snd_pcm_open(snd_pcm_t **pcmp, const char *name,
snd_pcm_stream_t flujo, modo int)
{
snd_config_t *top;
int err;
afirmar(snd_pcm_stream_t amp; amp; nombre);
p>
if (_ snd_is_ucm_device(nombre)) {
nombre = uc_mgr_alibcfg_by_device(amp; arriba, nombre);
if (nombre == NULL)
return -ENODEV;
} else {
err = snd_config_update_ref(amp; top);
if (err lt; 0)
return err;
}
err = snd_pcm_open_noupdate(pcmp, top, nombre, flujo, modo, 0) ;
snd_config_unref(top) ;
return err;
}
Copiar después de iniciar sesión
pcmp, el nombre del dispositivo PCM abierto, que se abrirá El nombre del dispositivo PCM, el nombre del dispositivo PCM que se abrirá; flujo predeterminado
, el tipo de flujo PCM correspondiente, que se reproduce; Flujo PCM (SND_PCM_STREAM_PLAYBACK) y modo de grabación de flujo PCM (SND_PCM_STREAM_CAPTURE)
, modo de apertura, bloqueo, no bloqueo y asíncrono, etc.
snd_pcm_open obtiene la información de configuración en als.conf llamando a snd_config_update_ref y guarda los parámetros en snd_config_t.
Analice la configuración de snd_config_t a través de snd_pcm_open_noupdate. El prototipo de la función snd_pcm_open_noupdate es el siguiente
static int snd_pcm_open_noupdate(snd_pcm_t **pcmp, snd_config_t *root,
const char. *nombre, flujo snd_pcm_stream_t,
modo int, salto int)
{
int err
snd_config_t *pcm _conf; /p>
Carácter constante *str;
err = snd_config_search_definition(root, "pcm", nombre, amp;pcm_conf);
if (err lt; 0) {
SNDERR("PCM s desconocidos", nombre);
return err
}
if (snd_config_get_string(pcm_conf, amp; ; str) gt ;= 0)
// Análisis recursivo de bucle
err = snd_pcm_open_noupdate(pcmp, root, str, stream, mode,
hop 1); p>
else {
snd_config_set_hop(pcm_conf, hop);
err = snd_pcm_open_conf(pcmp, nombre, raíz, pcm_conf, flujo, modo
<); p> }snd_config_delete(pcm_conf);
Devolver err
}
Copiar después de iniciar sesión
snd_pcm_open_conf Extraer parámetros de snd_config_t
static const char *const build_in_pcms[] = {
"adpcm", "alaw", "copy", "dmix", "file", "hooks ", "hw" ", "ladspa", "lfloat",
"linear", "mulaw", "multi", "null", "empty", "plug", "rate", "ruta", " compartir",
"shm", "dsnoop", "dshare", "asym", "iec958", "softvol", "mmap_emul",
NULL
};
static int snd_pcm_open_conf(snd_pcm_t **pcmp, const char *nombre,
snd_config_t *pcm_root, snd_config_t *pcm_conf,
flujo snd_pcm_stream_t, modo int)
{
...
sprintf(buf, "_snd_pcm_s_open", str); //Nombre abierto, es decir, "_snd_pcm_hw_open"
...
const char * const *build_in = build_in_pcms;
sprintf(buf1, "libasound_module_pcm_s.so", str);
...
// Obtener lib a través de open_name Correspondiente función de biblioteca de enlace dinámico
open_func = snd_dlobj_cache_get(lib, open_name,
SND_DLSYM_VERSION(SND_PCM_DLSYM_ VERSION), 1);
if (open_func) {
err = open_func(pcmp, name, pcm_root, pcm_conf, stream, mode);
...
Copiar después de iniciar sesión
llamadas a snd_pcm_open_conf snd_dlobj_cache_get para obtener el puntero de función _snd_pcm_hw_open
_snd_pcm_hw_open crea hw_pc llamando a snd_dlobj_cache_get en la biblioteca dinámica libasound_module_pcm_hw. Por lo tanto
_snd_pcm_hw_open m equipo.
El prototipo de la función snd_pcm_hw_open es el siguiente
int snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name,
int card, int device, int subdevice,
snd_pcm_stream_t stream, modo int,
int mmap_emulation ATTRIBUTE_UNUSED,
int sync_ptr_ioctl)
{
...
if ((ret = snd_ctl_hw_open(amp;ctl, NULL, card, 0)) lt; 0)
return ret;
...
fd = snd_open_device(nombre de archivo, fmode);
...
return snd_pcm_hw_open_fd(pcmp, nombre, fd, sync_ptr_ioctl);
_err: p>
if (fd gt; = 0)
close(fd);
snd_ctl_close(ctl);
return ret;
}
Copiar después de iniciar sesión
snd_pcm_hw_open realiza las siguientes operaciones:
Llamar a snd_ctl_hw_open creará un dispositivo de control de hardware y establecerá la devolución de llamada constante snd_ ctl_ops_t *ops, el parámetro de devolución de llamada es snd_ctl_hw_ops, la interfaz de operación específica es la siguiente:
static const snd_ctl_ops_t snd_ctl_hw_ops = {
.close = snd_ctl_hw_close,
.nonblock = snd_ctl_hw_nonblock,
.async = snd_ctl_hw_async,
.subscribe_events = snd_ctl_hw_subscribe_events,
..card_info = snd_ctl_hw_card_info,
.element_list = snd_ctl_hw_elem_list,
.element_info = snd_ctl_hw_elem_info,
..element_add = snd_ctl_hw_elem_add,
.element_replace = snd_ctl_hw_elem_replace,
.element_remove = snd_ ctl_hw_elem_remove ,
..element_read = snd_ctl_hw_elem_read,
.element_write = snd_ctl_hw_elem_write,
.element_lock = snd_ctl_hw_elem_lock,
..element_unlock = snd_ctl_hw
_elem_unlock,
.element_tlv = snd_ctl_hw_elem_tlv,
.hwdep_next_device = snd_ctl_hw_hwdep_next_device,
.hwdep_info = snd_ctl_hw_hwdep_info,
t _dispositivo = snd_ctl_hw_pcm_next_device ,
.pcm_info = snd_ctl_hw_pcm_info,
.pcm_prefer_subdevice = snd_ctl_hw_pcm_prefer_subdevice,
.rawmidi_next_device = snd_ctl_hw_rawmidi_next_device,
.info = snd_ctl_ hw_rawmidi_info, p>
.rawmidi_prefer_subdevice = snd_ctl_hw_rawmidi_prefer_subdevice,
.set_power_state = snd_ctl_hw_set_power_state,
.get_power_state = snd_ctl_hw_get_power_state,
.read = snd_ctl_hw_read, p >
};
Copia de inicio de sesión
Llame a snd_pcm_hw_open_fd para crear el dispositivo hw PCM y configurar la devolución de llamada correspondiente. El prototipo de la función snd_pcm_hw_open_fd es el siguiente
.int snd_pcm_hw_open_fd(snd_pcm_t * *pcmp, const char *name, int fd,
int sync_ptr_ioctl)
ret = snd_pcm_new(amp;pcm, SND_PCM_TYPE_HW, nombre, información. stream, mode);
...
// Configurar la interfaz de devolución de llamada
pcm-gt = amp; > pcm-gt; fast_ops = amp ;snd_pcm_hw_fast_ops;
pcm-gt;private_data = hw;
pcm-gt;poll_fd = fd;
pcm- gt;poll_events = info.stream = = SND_PCM_STREAM_PLAYBACK ?POLLOUT: POLLIN;
pcm-gt;tstamp_type = tstamp_type;
...
} p>
Copiar después de iniciar sesión
La interfaz de devolución de llamada es la siguiente
static const snd_pcm_ops_t snd_pcm_hw_ops = {
.close = snd_pcm_hw_close,
.info = snd_ pcm_hw_info,
p>
.hw_refine = sn
d_pcm_hw_hw_refine,
..hw_params = snd_pcm_hw_hw_params,
.hw_free = snd_pcm_hw_hw_free,
p> .sw_params = snd_pcm_hw_sw_params,
. channel_info = snd_pcm_hw_channel_info,
.dump = snd_pcm_hw_dump,
.nonblock = snd_ pcm_hw_nonblock,
.async = snd_pcm_hw_async,
.mmap chmap,
};
const estática snd_pcm_fast_ops_t snd_pcm_hw_fast_ops = {
.status = snd_pcm_hw_status,
.state = snd_pcm_hw_state, <. /p >
.hwsync = snd_pcm_hw_ hwsync,
.delay = snd_pcm_hw_delay,
.prepare = snd_pcm_hw_prepare,
.reset = snd_pcm_hw_reset, p>
..start = snd_pcm_hw_start,
.drop = snd_pcm_hw_drop,
.drain = snd_pcm_hw_drain,
.pause = snd_pcm_hw_pause,
..rewindable = snd_pcm_hw_ rewindable,
.rewind = snd_pcm_hw_rewind,
.forwardable = snd_pcm_hw_forwardable,
.forward = snd_pcm_hw_forward,
.resume = snd_pcm_hw_resume,
.link = snd_pcm_hw_link,
.link_slaves = snd_pcm_hw_link_slaves,
.unlink = snd_pcm_hw_unlink,
.writei = snd_pcm_hw_writei, //reproducir devolución de llamada de transmisión
.writen = snd_pcm_hw_writen,
.readi = snd_pcm_hw_readi,
.readn = snd_pcm_hw _read
n,
.
.mmap_commit = snd_pcm_hw_mmap_commit,
.htimestamp = snd_pcm_hw_htimestamp,
.poll_descriptors = NULL,
.poll_descriptors_count = NULL,
.poll_revents = NULL,
};
Copie el pcm anterior después de iniciar sesión
-gt;fast_ops-gt;writei es snd_pcm_hw_writei.
Audio y vídeo
Si te gusta el artículo, llama al excelente blogger~
Sandalias de tacón stiletto
Recomendaciones destacadas
Publicidad