static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const char __user *buf, size_t bytes)
{
size_t xfer = 0;
ssize_t tmp;
struct snd_pcm_runtime *runtime = substream->runtime;
if (atomic_read(&substream->mmap_count))
return -ENXIO;
if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
return tmp;
mutex_lock(&runtime->oss.params_lock);
while (bytes > 0) {
/*
函数snd_pcm_oss_period_size最终将建立如下一个视图:[luther.gliethttp]
struct a { char one_period[runtime->oss.period_bytes] };
struct a periods_array[runtime->oss.periods]
《浅析alsa声卡驱动snd_pcm_oss_period_size函数》runtime->oss.period_frames为当前可用a[]数组索引号+1,
语言描述的话,一共有periods个重复物理地址上连续的存储空间,每个存储空间的大小为period_bytes
*/
if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
tmp = bytes;
// 如果该period_bytes存储空间不能容纳下tmp个字节数据了,那么
// tmp等于period_bytes存储空间还能够容纳的字节数, 否则tmp等于bytes,能够全部容纳
if (tmp + runtime->oss.buffer_used > runtime->oss.period_bytes)
tmp = runtime->oss.period_bytes - runtime->oss.buffer_used;
if (tmp > 0) {
// 将用户空间的数据buf,拷贝到runtime->oss.buffer + runtime->oss.buffer_used开始处
if (copy_from_user(runtime->oss.buffer + runtime->oss.buffer_used, buf, tmp)) {
tmp = -EFAULT;
goto err;
}
}
runtime->oss.buffer_used += tmp; // 移动可用空间起始指针
buf += tmp;
bytes -= tmp;
xfer += tmp;
if (substream->oss.setup.partialfrag ||
runtime->oss.buffer_used == runtime->oss.period_bytes) {
// 如果runtime->oss.buffer_used == runtime->oss.period_bytes成立,表示
// 本period缓冲区已经全部装满,那么下发该缓冲区中period_bytes字节音频数据
tmp = snd_pcm_oss_write2(substream, runtime->oss.buffer + runtime->oss.period_ptr,
runtime->oss.buffer_used - runtime->oss.period_ptr, 1); // 1表示buf来自内核空间
《浅析alsa声卡驱动snd_pcm_oss_write2函数》 if (tmp <= 0)
goto err;
// 调整指针和数据大小
runtime->oss.bytes += tmp;
runtime->oss.period_ptr += tmp;
runtime->oss.period_ptr %= runtime->oss.period_bytes;
if (runtime->oss.period_ptr == 0 ||
runtime->oss.period_ptr == runtime->oss.buffer_used)
runtime->oss.buffer_used = 0;
else if ((substream->f_flags & O_NONBLOCK) != 0) {
tmp = -EAGAIN;
goto err;
}
}
} else {
// 因为runtime->oss.buffer_used等于0,所以表示runtime->oss.buffer缓冲区中现在一个音频
// 数据都没有,同样bytes一定大于runtime->oss.period_bytes
// 所以不需要做上面的拼接操作,直接调用snd_pcm_oss_write2下发一整个period满数据大小的音频数据[luther.gliethttp]
tmp = snd_pcm_oss_write2(substream,
《浅析alsa声卡驱动snd_pcm_oss_write2函数》 (const char __force *)buf,
runtime->oss.period_bytes, 0); // 0表示buf来自用户空间
if (tmp <= 0)
goto err;
runtime->oss.bytes += tmp;
buf += tmp;
bytes -= tmp;
xfer += tmp;
if ((substream->f_flags & O_NONBLOCK) != 0 &&
tmp != runtime->oss.period_bytes)
break;
}
}
mutex_unlock(&runtime->oss.params_lock);
return xfer;
err:
mutex_unlock(&runtime->oss.params_lock);
return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
}
阅读(1675) | 评论(0) | 转发(0) |