Red de conocimiento informático - Problemas con los teléfonos móviles - ¿Qué archivos de encabezado debe incluir snd_pcm_open?

¿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)

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);

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:

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,

.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,

};

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;

...

}

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,

..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