static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
unsigned long data,
snd_pcm_uframes_t size,
int nonblock,
transfer_f transfer)
{
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_uframes_t xfer = 0;
snd_pcm_uframes_t offset = 0;
int err = 0;
if (size == 0)
return 0;
snd_pcm_stream_lock_irq(substream);
switch (runtime->status->state) {
case SNDRV_PCM_STATE_PREPARED:
case SNDRV_PCM_STATE_RUNNING:
case SNDRV_PCM_STATE_PAUSED:
break;
case SNDRV_PCM_STATE_XRUN:
err = -EPIPE;
goto _end_unlock;
case SNDRV_PCM_STATE_SUSPENDED:
err = -ESTRPIPE;
goto _end_unlock;
default:
err = -EBADFD;
goto _end_unlock;
}
while (size > 0) {
snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
snd_pcm_uframes_t avail;
snd_pcm_uframes_t cont;
if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
snd_pcm_update_hw_ptr(substream);
avail = snd_pcm_playback_avail(runtime);
if (!avail) {
if (nonblock) {
err = -EAGAIN;
goto _end_unlock;
}
err = wait_for_avail_min(substream, &avail);
if (err < 0)
goto _end_unlock;
}
frames = size > avail ? avail : size;
cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;
if (frames > cont)
frames = cont;
if (snd_BUG_ON(!frames)) {
snd_pcm_stream_unlock_irq(substream);
return -EINVAL;
}
appl_ptr = runtime->control->appl_ptr;
appl_ofs = appl_ptr % runtime->buffer_size;
snd_pcm_stream_unlock_irq(substream);
// 上面是组织数据,下面对于snd_pcm_lib_write调用,transfer为snd_pcm_lib_write_transfer
《浅析alsa声卡驱动snd_pcm_lib_write_transfer函数》 // 将数据拷贝到runtime->dma_area这个DMA空间[luther.gliethttp]
if ((err = transfer(substream, appl_ofs, data, offset, frames)) < 0)
goto _end;
snd_pcm_stream_lock_irq(substream);
switch (runtime->status->state) {
case SNDRV_PCM_STATE_XRUN:
err = -EPIPE;
goto _end_unlock;
case SNDRV_PCM_STATE_SUSPENDED:
err = -ESTRPIPE;
goto _end_unlock;
default:
break;
}
appl_ptr += frames;
if (appl_ptr >= runtime->boundary)
appl_ptr -= runtime->boundary;
runtime->control->appl_ptr = appl_ptr;
if (substream->ops->ack)
substream->ops->ack(substream);
offset += frames;
size -= frames;
xfer += frames;
if (runtime->status->state == SNDRV_PCM_STATE_PREPARED &&
snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t)runtime->start_threshold) {
err = snd_pcm_start(substream); // start all linked streams启动发送,将streams中的所有音频数据递交到硬件[luther.gliethttp]
《浅析alsa声卡驱动snd_pcm_start函数-将音频数据真实的发送到外部音频接口硬件》 if (err < 0)
goto _end_unlock;
}
}
_end_unlock:
snd_pcm_stream_unlock_irq(substream);
_end:
return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
}
阅读(5919) | 评论(1) | 转发(0) |