123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- // Copyright 2013 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "media/audio/sndio/sndio_input.h"
- #include <stddef.h>
- #include "base/bind.h"
- #include "base/logging.h"
- #include "base/macros.h"
- #include "base/message_loop/message_loop.h"
- #include "media/audio/openbsd/audio_manager_openbsd.h"
- #include "media/audio/audio_manager.h"
- namespace media {
- void sndio_in_onmove(void *arg, int delta) {
- NOTIMPLEMENTED();
- SndioAudioInputStream* self = static_cast<SndioAudioInputStream*>(arg);
- self->hw_delay_ = delta - self->params_.GetBytesPerFrame();
- }
- void *sndio_in_threadstart(void *arg) {
- NOTIMPLEMENTED();
- SndioAudioInputStream* self = static_cast<SndioAudioInputStream*>(arg);
- self->ReadAudio();
- return NULL;
- }
- SndioAudioInputStream::SndioAudioInputStream(AudioManagerBase* audio_manager,
- const std::string& device_name,
- const AudioParameters& params)
- : audio_manager_(audio_manager),
- device_name_(device_name),
- params_(params),
- bytes_per_buffer_(params.frames_per_buffer() *
- (params.channels() * params.bits_per_sample()) /
- 8),
- buffer_duration_(base::TimeDelta::FromMicroseconds(
- params.frames_per_buffer() * base::Time::kMicrosecondsPerSecond /
- static_cast<float>(params.sample_rate()))),
- callback_(NULL),
- device_handle_(NULL),
- read_callback_behind_schedule_(false),
- audio_bus_(AudioBus::Create(params)) {
- }
- SndioAudioInputStream::~SndioAudioInputStream() {}
- bool SndioAudioInputStream::Open() {
- struct sio_par par;
- int sig;
- if (device_handle_)
- return false; // Already open.
- if (params_.format() != AudioParameters::AUDIO_PCM_LINEAR &&
- params_.format() != AudioParameters::AUDIO_PCM_LOW_LATENCY) {
- LOG(WARNING) << "Unsupported audio format.";
- return false;
- }
- sio_initpar(&par);
- par.rate = params_.sample_rate();
- par.pchan = params_.channels();
- par.bits = params_.bits_per_sample();
- par.bps = par.bits / 8;
- par.sig = sig = par.bits != 8 ? 1 : 0;
- par.le = SIO_LE_NATIVE;
- par.appbufsz = params_.frames_per_buffer();
- sndio_rec_bufsz_ = par.bufsz;
- sndio_rec_bufsize_ = par.round * par.bps * par.rchan;
- device_handle_ = sio_open(SIO_DEVANY, SIO_REC, 0);
- if (device_handle_ == NULL) {
- LOG(ERROR) << "Couldn't open audio device.";
- return false;
- }
- if (!sio_setpar(device_handle_, &par) || !sio_getpar(device_handle_, &par)) {
- LOG(ERROR) << "Couldn't set audio parameters.";
- goto bad_close;
- }
- if (par.rate != (unsigned int)params_.sample_rate() ||
- par.pchan != (unsigned int)params_.channels() ||
- par.bits != (unsigned int)params_.bits_per_sample() ||
- par.sig != (unsigned int)sig ||
- (par.bps > 1 && par.le != SIO_LE_NATIVE) ||
- (par.bits != par.bps * 8)) {
- LOG(ERROR) << "Unsupported audio parameters.";
- goto bad_close;
- }
- sio_onmove(device_handle_, sndio_in_onmove, this);
- audio_buffer_.reset(new uint8_t[bytes_per_buffer_]);
- return true;
- bad_close:
- sio_close(device_handle_);
- return false;
- }
- void SndioAudioInputStream::Start(AudioInputCallback* callback) {
- DCHECK(!callback_ && callback);
- callback_ = callback;
- StartAgc();
- // We start reading data half |buffer_duration_| later than when the
- // buffer might have got filled, to accommodate some delays in the audio
- // driver. This could also give us a smooth read sequence going forward.
- base::TimeDelta delay = buffer_duration_ + buffer_duration_ / 2;
- next_read_time_ = base::TimeTicks::Now() + delay;
- if (pthread_create(&thread_, NULL, sndio_in_threadstart, this) != 0)
- LOG(ERROR) << "Failed to create real-time thread.";
- }
- void SndioAudioInputStream::ReadAudio() {
- NOTIMPLEMENTED();
- DCHECK(callback_);
- int num_buffers = sndio_rec_bufsize_ / params_.frames_per_buffer();
- double normalized_volume = 0.0;
- // Update the AGC volume level once every second. Note that, |volume| is
- // also updated each time SetVolume() is called through IPC by the
- // render-side AGC.
- GetAgcVolume(&normalized_volume);
- while (num_buffers--) {
- int frames_read = sio_read(device_handle_, audio_buffer_.get(),
- params_.frames_per_buffer());
- if (frames_read == params_.frames_per_buffer()) {
- audio_bus_->FromInterleaved(audio_buffer_.get(),
- audio_bus_->frames(),
- params_.bits_per_sample() / 8);
- callback_->OnData(
- this, audio_bus_.get(), hw_delay_, normalized_volume);
- } else {
- LOG(WARNING) << "sio_read() returning less than expected frames: "
- << frames_read << " vs. " << params_.frames_per_buffer()
- << ". Dropping this buffer.";
- }
- }
- }
- void SndioAudioInputStream::Stop() {
- if (!device_handle_ || !callback_)
- return;
- StopAgc();
- pthread_join(thread_, NULL);
- sio_stop(device_handle_);
- callback_ = NULL;
- }
- void SndioAudioInputStream::Close() {
- if (device_handle_) {
- sio_close(device_handle_);
- audio_buffer_.reset();
- device_handle_ = NULL;
- }
- audio_manager_->ReleaseInputStream(this);
- }
- double SndioAudioInputStream::GetMaxVolume() {
- return static_cast<double>(SIO_MAXVOL);
- }
- void SndioAudioInputStream::SetVolume(double volume) {
- NOTIMPLEMENTED();
- }
- double SndioAudioInputStream::GetVolume() {
- long current_volume = 0;
- return static_cast<double>(current_volume);
- }
- bool SndioAudioInputStream::IsMuted() {
- return false;
- }
- } // namespace media
|