📄 pcm_oss.c
字号:
runtime->oss.format = snd_pcm_oss_format_to(params_format(¶ms)); runtime->oss.channels = params_channels(¶ms); runtime->oss.rate = params_rate(¶ms); runtime->oss.params = 0; runtime->oss.prepare = 1; if (runtime->oss.buffer != NULL) vfree(runtime->oss.buffer); runtime->oss.buffer = vmalloc(runtime->oss.period_bytes); runtime->oss.buffer_used = 0; snd_assert(runtime->dma_area != NULL, return -EIO); snd_pcm_format_set_silence(runtime->format, runtime->dma_area, bytes_to_samples(runtime, runtime->dma_bytes)); return 0;}static int snd_pcm_oss_get_active_substream(snd_pcm_oss_file_t *pcm_oss_file, snd_pcm_substream_t **r_substream){ int idx, err; snd_pcm_substream_t *asubstream = NULL, *substream; for (idx = 0; idx < 2; idx++) { substream = pcm_oss_file->streams[idx]; if (substream == NULL) continue; if (asubstream == NULL) asubstream = substream; if (substream->runtime->oss.params) { err = snd_pcm_oss_change_params(substream); if (err < 0) return err; } } snd_assert(asubstream != NULL, return -EIO); if (r_substream) *r_substream = asubstream; return 0;}static int snd_pcm_oss_prepare(snd_pcm_substream_t *substream){ int err; snd_pcm_runtime_t *runtime = substream->runtime; err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, 0); if (err < 0) { snd_printd("snd_pcm_oss_prepare: SNDRV_PCM_IOCTL_PREPARE failed\n"); return err; } runtime->oss.prepare = 0; runtime->oss.prev_hw_ptr_interrupt = 0; return 0;}static int snd_pcm_oss_make_ready(snd_pcm_substream_t *substream){ snd_pcm_runtime_t *runtime; int err; if (substream == NULL) return 0; runtime = substream->runtime; if (runtime->oss.params) { err = snd_pcm_oss_change_params(substream); if (err < 0) return err; } if (runtime->oss.prepare) { err = snd_pcm_oss_prepare(substream); if (err < 0) return err; } return 0;}snd_pcm_sframes_t snd_pcm_oss_write3(snd_pcm_substream_t *substream, const char *ptr, snd_pcm_uframes_t frames, int in_kernel){ snd_pcm_runtime_t *runtime = substream->runtime; int ret; while (1) { if (runtime->status->state == SNDRV_PCM_STATE_XRUN || runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { ret = snd_pcm_oss_prepare(substream); if (ret < 0) break; } if (in_kernel) { mm_segment_t fs; fs = snd_enter_user(); ret = snd_pcm_lib_write(substream, ptr, frames); snd_leave_user(fs); } else { ret = snd_pcm_lib_write(substream, ptr, frames); } if (ret != -EPIPE && ret != -ESTRPIPE) break; /* test, if we can't store new data, because the stream */ /* has not been started */ if (runtime->status->state == SNDRV_PCM_STATE_PREPARED) return -EAGAIN; } return ret;}snd_pcm_sframes_t snd_pcm_oss_read3(snd_pcm_substream_t *substream, char *ptr, snd_pcm_uframes_t frames, int in_kernel){ snd_pcm_runtime_t *runtime = substream->runtime; int ret; while (1) { if (runtime->status->state == SNDRV_PCM_STATE_XRUN || runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, 0); if (ret < 0) break; } else if (runtime->status->state == SNDRV_PCM_STATE_SETUP) { ret = snd_pcm_oss_prepare(substream); if (ret < 0) break; } ret = snd_pcm_lib_read(substream, ptr, frames); if (in_kernel) { mm_segment_t fs; fs = snd_enter_user(); ret = snd_pcm_lib_read(substream, ptr, frames); snd_leave_user(fs); } else { ret = snd_pcm_lib_read(substream, ptr, frames); } if (ret != -EPIPE && ret != -ESTRPIPE) break; } return ret;}snd_pcm_sframes_t snd_pcm_oss_writev3(snd_pcm_substream_t *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel){ snd_pcm_runtime_t *runtime = substream->runtime; int ret; while (1) { if (runtime->status->state == SNDRV_PCM_STATE_XRUN || runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { ret = snd_pcm_oss_prepare(substream); if (ret < 0) break; } if (in_kernel) { mm_segment_t fs; fs = snd_enter_user(); ret = snd_pcm_lib_writev(substream, bufs, frames); snd_leave_user(fs); } else { ret = snd_pcm_lib_writev(substream, bufs, frames); } if (ret != -EPIPE && ret != -ESTRPIPE) break; /* test, if we can't store new data, because the stream */ /* has not been started */ if (runtime->status->state == SNDRV_PCM_STATE_PREPARED) return -EAGAIN; } return ret;} snd_pcm_sframes_t snd_pcm_oss_readv3(snd_pcm_substream_t *substream, void **bufs, snd_pcm_uframes_t frames, int in_kernel){ snd_pcm_runtime_t *runtime = substream->runtime; int ret; while (1) { if (runtime->status->state == SNDRV_PCM_STATE_XRUN || runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, 0); if (ret < 0) break; } else if (runtime->status->state == SNDRV_PCM_STATE_SETUP) { ret = snd_pcm_oss_prepare(substream); if (ret < 0) break; } if (in_kernel) { mm_segment_t fs; fs = snd_enter_user(); ret = snd_pcm_lib_readv(substream, bufs, frames); snd_leave_user(fs); } else { ret = snd_pcm_lib_readv(substream, bufs, frames); } if (ret != -EPIPE && ret != -ESTRPIPE) break; } return ret;}static ssize_t snd_pcm_oss_write2(snd_pcm_substream_t *substream, const char *buf, size_t bytes, int in_kernel){ snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_sframes_t frames, frames1; if (runtime->oss.plugin_first) { snd_pcm_plugin_channel_t *channels; size_t oss_frame_bytes = (runtime->oss.plugin_first->src_width * runtime->oss.plugin_first->src_format.channels) / 8; if (!in_kernel) { if (copy_from_user(runtime->oss.buffer, buf, bytes)) return -EFAULT; buf = runtime->oss.buffer; } frames = bytes / oss_frame_bytes; frames1 = snd_pcm_plug_client_channels_buf(substream, (char *)buf, frames, &channels); if (frames1 < 0) return frames1; frames1 = snd_pcm_plug_write_transfer(substream, channels, frames1); if (frames1 <= 0) return frames1; bytes = frames1 * oss_frame_bytes; } else { frames = bytes_to_frames(runtime, bytes); frames1 = snd_pcm_oss_write3(substream, buf, frames, in_kernel); if (frames1 <= 0) return frames1; bytes = frames_to_bytes(runtime, frames1); } return bytes;}static ssize_t snd_pcm_oss_write1(snd_pcm_substream_t *substream, const char *buf, size_t bytes){ size_t xfer = 0; ssize_t tmp; snd_pcm_runtime_t *runtime = substream->runtime; if (atomic_read(&runtime->mmap_count)) return -ENXIO; if ((tmp = snd_pcm_oss_make_ready(substream)) < 0) return tmp; while (bytes > 0) { if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) { tmp = bytes; if (tmp + runtime->oss.buffer_used > runtime->oss.period_bytes) tmp = runtime->oss.period_bytes - runtime->oss.buffer_used; if (tmp > 0) { if (copy_from_user(runtime->oss.buffer + runtime->oss.buffer_used, buf, tmp)) return xfer > 0 ? xfer : -EFAULT; } runtime->oss.buffer_used += tmp; buf += tmp; bytes -= tmp; xfer += tmp; if (runtime->oss.buffer_used == runtime->oss.period_bytes) { tmp = snd_pcm_oss_write2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1); if (tmp <= 0) return xfer > 0 ? xfer : tmp; runtime->oss.bytes += tmp; runtime->oss.buffer_used = 0; } } else { tmp = snd_pcm_oss_write2(substream, (char *)buf, runtime->oss.period_bytes, 0); if (tmp <= 0) return xfer > 0 ? xfer : tmp; runtime->oss.bytes += tmp; buf += tmp; bytes -= tmp; xfer += tmp; } } return xfer;}static ssize_t snd_pcm_oss_read2(snd_pcm_substream_t *substream, char *buf, size_t bytes, int in_kernel){ snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_sframes_t frames, frames1; char *final_dst = buf; if (runtime->oss.plugin_first) { snd_pcm_plugin_channel_t *channels; size_t oss_frame_bytes = (runtime->oss.plugin_last->dst_width * runtime->oss.plugin_last->dst_format.channels) / 8; if (!in_kernel) buf = runtime->oss.buffer; frames = bytes / oss_frame_bytes; frames1 = snd_pcm_plug_client_channels_buf(substream, buf, frames, &channels); if (frames1 < 0) return frames1; frames1 = snd_pcm_plug_read_transfer(substream, channels, frames1); if (frames1 <= 0) return frames1; bytes = frames1 * oss_frame_bytes; if (!in_kernel && copy_to_user(final_dst, buf, bytes)) return -EFAULT; } else { frames = bytes_to_frames(runtime, bytes); frames1 = snd_pcm_oss_read3(substream, buf, frames, in_kernel); if (frames1 <= 0) return frames1; bytes = frames_to_bytes(runtime, frames1); } return bytes;}static ssize_t snd_pcm_oss_read1(snd_pcm_substream_t *substream, char *buf, size_t bytes){ size_t xfer = 0; ssize_t tmp; snd_pcm_runtime_t *runtime = substream->runtime; if (atomic_read(&runtime->mmap_count)) return -ENXIO; if ((tmp = snd_pcm_oss_make_ready(substream)) < 0) return tmp; while (bytes > 0) { if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) { if (runtime->oss.buffer_used == 0) { tmp = snd_pcm_oss_read2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1); if (tmp <= 0) return xfer > 0 ? xfer : tmp; runtime->oss.bytes += tmp; runtime->oss.buffer_used = runtime->oss.period_bytes; } tmp = bytes; if ((size_t) tmp > runtime->oss.buffer_used) tmp = runtime->oss.buffer_used; if (copy_to_user(buf, runtime->oss.buffer + (runtime->oss.period_bytes - runtime->oss.buffer_used), tmp)) return xfer > 0 ? xfer : -EFAULT; buf += tmp; bytes -= tmp; xfer += tmp; runtime->oss.buffer_used -= tmp; } else { tmp = snd_pcm_oss_read2(substream, (char *)buf, runtime->oss.period_bytes, 0); if (tmp <= 0) return xfer > 0 ? xfer : tmp; runtime->oss.bytes += tmp; buf += tmp; bytes -= tmp; xfer += tmp; } } return xfer;}static int snd_pcm_oss_reset(snd_pcm_oss_file_t *pcm_oss_file){ snd_pcm_substream_t *substream; substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; if (substream != NULL) { snd_pcm_kernel_playback_ioctl(substream, SNDRV_PCM_IOCTL_DROP, 0); substream->runtime->oss.prepare = 1; } substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; if (substream != NULL) { snd_pcm_kernel_capture_ioctl(substream, SNDRV_PCM_IOCTL_DROP, 0); substream->runtime->oss.prepare = 1; } return 0;}static int snd_pcm_oss_sync(snd_pcm_oss_file_t *pcm_oss_file){ int err = 0; unsigned int saved_f_flags; snd_pcm_substream_t *substream; snd_pcm_runtime_t *runtime; ssize_t result; wait_queue_t wait; substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK]; if (substream != NULL) { if ((err = snd_pcm_oss_make_ready(substream)) < 0) return err; runtime = substream->runtime; if (runtime->oss.buffer_used > 0) { snd_pcm_format_set_silence(runtime->format, runtime->oss.buffer + runtime->oss.buffer_used, bytes_to_samples(runtime, runtime->oss.period_bytes - runtime->oss.buffer_used)); init_waitqueue_entry(&wait, current); add_wait_queue(&runtime->sleep, &wait); while (1) { result = snd_pcm_oss_write2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1); if (result > 0) { runtime->oss.buffer_used = 0; break; } if (result != 0 && result != -EAGAIN) break; set_current_state(TASK_INTERRUPTIBLE); schedule(); if (signal_pending(current)) { result = -ERESTARTSYS; break; } } set_current_state(TASK_RUNNING); remove_wait_queue(&runtime->sleep, &wait); if (result < 0) return result; } saved_f_flags = substream->ffile->f_flags; substream->ffile->f_flags &= ~O_NONBLOCK; err = snd_pcm_kernel_playback_ioctl(substream, SNDRV_PCM_IOCTL_DRAIN, 0); substream->ffile->f_flags = saved_f_flags; if (err < 0) return err; runtime->oss.prepare = 1; } substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; if (substream != NULL) { if ((err = snd_pcm_oss_make_ready(substream)) < 0) return err; runtime = substream->runtime; err = snd_pcm_kernel_capture_ioctl(substream, SNDRV_PCM_IOCTL_DROP, 0); if (err < 0) return err; runtime->oss.buffer_used = 0; runtime->oss.prepare = 1; } return 0;}static int snd_pcm_oss_set_rate(snd_pcm_oss_file_t *pcm_oss_file, int rate){ int idx; for (idx = 1; idx >= 0; --idx) { snd_pcm_substream_t *substream = pcm_oss_file->streams[idx]; snd_pcm_runtime_t *runtime; if (substream == NULL) continue; runtime = substream->runtime; if (rate < 1000) rate = 1000; else if (rate > 48000) rate = 48000; if (runtime->oss.rate != rate) { runtime->oss.params = 1; runtime->oss.rate = rate; } } return snd_pcm_oss_get_rate(pcm_oss_file);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -