| Index: media/audio/win/wavein_input_win.cc
|
| diff --git a/media/audio/win/wavein_input_win.cc b/media/audio/win/wavein_input_win.cc
|
| deleted file mode 100644
|
| index 18bf53f96546eab9058896315f5983c7d7c07773..0000000000000000000000000000000000000000
|
| --- a/media/audio/win/wavein_input_win.cc
|
| +++ /dev/null
|
| @@ -1,325 +0,0 @@
|
| -// Copyright (c) 2012 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/win/wavein_input_win.h"
|
| -
|
| -#include "base/logging.h"
|
| -#include "media/audio/audio_device_description.h"
|
| -#include "media/audio/audio_io.h"
|
| -#include "media/audio/win/audio_manager_win.h"
|
| -#include "media/audio/win/device_enumeration_win.h"
|
| -#include "media/base/audio_bus.h"
|
| -
|
| -namespace media {
|
| -
|
| -// Our sound buffers are allocated once and kept in a linked list using the
|
| -// the WAVEHDR::dwUser variable. The last buffer points to the first buffer.
|
| -static WAVEHDR* GetNextBuffer(WAVEHDR* current) {
|
| - return reinterpret_cast<WAVEHDR*>(current->dwUser);
|
| -}
|
| -
|
| -PCMWaveInAudioInputStream::PCMWaveInAudioInputStream(
|
| - AudioManagerWin* manager,
|
| - const AudioParameters& params,
|
| - int num_buffers,
|
| - const std::string& device_id)
|
| - : state_(kStateEmpty),
|
| - manager_(manager),
|
| - callback_(NULL),
|
| - num_buffers_(num_buffers),
|
| - channels_(params.channels()),
|
| - device_id_(device_id),
|
| - wavein_(NULL),
|
| - buffer_(NULL),
|
| - audio_bus_(media::AudioBus::Create(params)) {
|
| - DCHECK_GT(num_buffers_, 0);
|
| - format_.wFormatTag = WAVE_FORMAT_PCM;
|
| - format_.nChannels = params.channels() > 2 ? 2 : params.channels();
|
| - format_.nSamplesPerSec = params.sample_rate();
|
| - format_.wBitsPerSample = params.bits_per_sample();
|
| - format_.cbSize = 0;
|
| - format_.nBlockAlign = (format_.nChannels * format_.wBitsPerSample) / 8;
|
| - format_.nAvgBytesPerSec = format_.nBlockAlign * format_.nSamplesPerSec;
|
| - buffer_size_ = params.frames_per_buffer() * format_.nBlockAlign;
|
| - // If we don't have a packet size we use 100ms.
|
| - if (!buffer_size_)
|
| - buffer_size_ = format_.nAvgBytesPerSec / 10;
|
| - // The event is auto-reset.
|
| - stopped_event_.Set(::CreateEventW(NULL, FALSE, FALSE, NULL));
|
| -}
|
| -
|
| -PCMWaveInAudioInputStream::~PCMWaveInAudioInputStream() {
|
| - DCHECK(NULL == wavein_);
|
| -}
|
| -
|
| -bool PCMWaveInAudioInputStream::Open() {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - if (state_ != kStateEmpty)
|
| - return false;
|
| - if (num_buffers_ < 2 || num_buffers_ > 10)
|
| - return false;
|
| -
|
| - // Convert the stored device id string into an unsigned integer
|
| - // corresponding to the selected device.
|
| - UINT device_id = WAVE_MAPPER;
|
| - if (!GetDeviceId(&device_id)) {
|
| - return false;
|
| - }
|
| -
|
| - // Open the specified input device for recording.
|
| - MMRESULT result = MMSYSERR_NOERROR;
|
| - result = ::waveInOpen(&wavein_, device_id, &format_,
|
| - reinterpret_cast<DWORD_PTR>(WaveCallback),
|
| - reinterpret_cast<DWORD_PTR>(this),
|
| - CALLBACK_FUNCTION);
|
| - if (result != MMSYSERR_NOERROR)
|
| - return false;
|
| -
|
| - SetupBuffers();
|
| - state_ = kStateReady;
|
| - return true;
|
| -}
|
| -
|
| -void PCMWaveInAudioInputStream::SetupBuffers() {
|
| - WAVEHDR* last = NULL;
|
| - WAVEHDR* first = NULL;
|
| - for (int ix = 0; ix != num_buffers_; ++ix) {
|
| - uint32_t sz = sizeof(WAVEHDR) + buffer_size_;
|
| - buffer_ = reinterpret_cast<WAVEHDR*>(new char[sz]);
|
| - buffer_->lpData = reinterpret_cast<char*>(buffer_) + sizeof(WAVEHDR);
|
| - buffer_->dwBufferLength = buffer_size_;
|
| - buffer_->dwBytesRecorded = 0;
|
| - buffer_->dwUser = reinterpret_cast<DWORD_PTR>(last);
|
| - buffer_->dwFlags = WHDR_DONE;
|
| - buffer_->dwLoops = 0;
|
| - if (ix == 0)
|
| - first = buffer_;
|
| - last = buffer_;
|
| - ::waveInPrepareHeader(wavein_, buffer_, sizeof(WAVEHDR));
|
| - }
|
| - // Fix the first buffer to point to the last one.
|
| - first->dwUser = reinterpret_cast<DWORD_PTR>(last);
|
| -}
|
| -
|
| -void PCMWaveInAudioInputStream::FreeBuffers() {
|
| - WAVEHDR* current = buffer_;
|
| - for (int ix = 0; ix != num_buffers_; ++ix) {
|
| - WAVEHDR* next = GetNextBuffer(current);
|
| - if (current->dwFlags & WHDR_PREPARED)
|
| - ::waveInUnprepareHeader(wavein_, current, sizeof(WAVEHDR));
|
| - delete[] reinterpret_cast<char*>(current);
|
| - current = next;
|
| - }
|
| - buffer_ = NULL;
|
| -}
|
| -
|
| -void PCMWaveInAudioInputStream::Start(AudioInputCallback* callback) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - if (state_ != kStateReady)
|
| - return;
|
| -
|
| - DCHECK(!callback_);
|
| - callback_ = callback;
|
| - state_ = kStateRecording;
|
| -
|
| - WAVEHDR* buffer = buffer_;
|
| - for (int ix = 0; ix != num_buffers_; ++ix) {
|
| - QueueNextPacket(buffer);
|
| - buffer = GetNextBuffer(buffer);
|
| - }
|
| - buffer = buffer_;
|
| -
|
| - MMRESULT result = ::waveInStart(wavein_);
|
| - if (result != MMSYSERR_NOERROR) {
|
| - HandleError(result);
|
| - state_ = kStateReady;
|
| - callback_ = NULL;
|
| - }
|
| -}
|
| -
|
| -// Stopping is tricky. First, no buffer should be locked by the audio driver
|
| -// or else the waveInReset() will deadlock and secondly, the callback should
|
| -// not be inside the AudioInputCallback's OnData because waveInReset()
|
| -// forcefully kills the callback thread.
|
| -void PCMWaveInAudioInputStream::Stop() {
|
| - DVLOG(1) << "PCMWaveInAudioInputStream::Stop()";
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - if (state_ != kStateRecording)
|
| - return;
|
| -
|
| - bool already_stopped = false;
|
| - {
|
| - // Tell the callback that we're stopping.
|
| - // As a result, |stopped_event_| will be signaled in callback method.
|
| - base::AutoLock auto_lock(lock_);
|
| - already_stopped = (callback_ == NULL);
|
| - callback_ = NULL;
|
| - }
|
| -
|
| - if (already_stopped)
|
| - return;
|
| -
|
| - // Wait for the callback to finish, it will signal us when ready to be reset.
|
| - DWORD wait = ::WaitForSingleObject(stopped_event_.Get(), INFINITE);
|
| - DCHECK_EQ(wait, WAIT_OBJECT_0);
|
| -
|
| - // Stop input and reset the current position to zero for |wavein_|.
|
| - // All pending buffers are marked as done and returned to the application.
|
| - MMRESULT res = ::waveInReset(wavein_);
|
| - DCHECK_EQ(res, static_cast<MMRESULT>(MMSYSERR_NOERROR));
|
| -
|
| - state_ = kStateReady;
|
| -}
|
| -
|
| -void PCMWaveInAudioInputStream::Close() {
|
| - DVLOG(1) << "PCMWaveInAudioInputStream::Close()";
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - // We should not call Close() while recording. Catch it with DCHECK and
|
| - // implement auto-stop just in case.
|
| - DCHECK_NE(state_, kStateRecording);
|
| - Stop();
|
| -
|
| - if (wavein_) {
|
| - FreeBuffers();
|
| -
|
| - // waveInClose() generates a WIM_CLOSE callback. In case Start() was never
|
| - // called, force a reset to ensure close succeeds.
|
| - MMRESULT res = ::waveInReset(wavein_);
|
| - DCHECK_EQ(res, static_cast<MMRESULT>(MMSYSERR_NOERROR));
|
| - res = ::waveInClose(wavein_);
|
| - DCHECK_EQ(res, static_cast<MMRESULT>(MMSYSERR_NOERROR));
|
| - state_ = kStateClosed;
|
| - wavein_ = NULL;
|
| - }
|
| -
|
| - // Tell the audio manager that we have been released. This can result in
|
| - // the manager destroying us in-place so this needs to be the last thing
|
| - // we do on this function.
|
| - manager_->ReleaseInputStream(this);
|
| -}
|
| -
|
| -double PCMWaveInAudioInputStream::GetMaxVolume() {
|
| - // TODO(henrika): Add volume support using the Audio Mixer API.
|
| - return 0.0;
|
| -}
|
| -
|
| -void PCMWaveInAudioInputStream::SetVolume(double volume) {
|
| - // TODO(henrika): Add volume support using the Audio Mixer API.
|
| -}
|
| -
|
| -double PCMWaveInAudioInputStream::GetVolume() {
|
| - // TODO(henrika): Add volume support using the Audio Mixer API.
|
| - return 0.0;
|
| -}
|
| -
|
| -bool PCMWaveInAudioInputStream::SetAutomaticGainControl(bool enabled) {
|
| - // TODO(henrika): Add AGC support when volume control has been added.
|
| - NOTIMPLEMENTED();
|
| - return false;
|
| -}
|
| -
|
| -bool PCMWaveInAudioInputStream::GetAutomaticGainControl() {
|
| - // TODO(henrika): Add AGC support when volume control has been added.
|
| - NOTIMPLEMENTED();
|
| - return false;
|
| -}
|
| -
|
| -bool PCMWaveInAudioInputStream::IsMuted() {
|
| - NOTIMPLEMENTED();
|
| - return false;
|
| -}
|
| -
|
| -void PCMWaveInAudioInputStream::HandleError(MMRESULT error) {
|
| - DLOG(WARNING) << "PCMWaveInAudio error " << error;
|
| - if (callback_)
|
| - callback_->OnError(this);
|
| -}
|
| -
|
| -void PCMWaveInAudioInputStream::QueueNextPacket(WAVEHDR *buffer) {
|
| - MMRESULT res = ::waveInAddBuffer(wavein_, buffer, sizeof(WAVEHDR));
|
| - if (res != MMSYSERR_NOERROR)
|
| - HandleError(res);
|
| -}
|
| -
|
| -bool PCMWaveInAudioInputStream::GetDeviceId(UINT* device_index) {
|
| - // Deliver the default input device id (WAVE_MAPPER) if the default
|
| - // device has been selected.
|
| - if (device_id_ == AudioDeviceDescription::kDefaultDeviceId) {
|
| - *device_index = WAVE_MAPPER;
|
| - return true;
|
| - }
|
| -
|
| - // Get list of all available and active devices.
|
| - AudioDeviceNames device_names;
|
| - if (!media::GetInputDeviceNamesWinXP(&device_names))
|
| - return false;
|
| -
|
| - if (device_names.empty())
|
| - return false;
|
| -
|
| - // Search the full list of devices and compare with the specified
|
| - // device id which was specified in the constructor. Stop comparing
|
| - // when a match is found and return the corresponding index.
|
| - UINT index = 0;
|
| - bool found_device = false;
|
| - AudioDeviceNames::const_iterator it = device_names.begin();
|
| - while (it != device_names.end()) {
|
| - if (it->unique_id.compare(device_id_) == 0) {
|
| - *device_index = index;
|
| - found_device = true;
|
| - break;
|
| - }
|
| - ++index;
|
| - ++it;
|
| - }
|
| -
|
| - return found_device;
|
| -}
|
| -
|
| -// Windows calls us back in this function when some events happen. Most notably
|
| -// when it has an audio buffer with recorded data.
|
| -void PCMWaveInAudioInputStream::WaveCallback(HWAVEIN hwi, UINT msg,
|
| - DWORD_PTR instance,
|
| - DWORD_PTR param1, DWORD_PTR) {
|
| - PCMWaveInAudioInputStream* obj =
|
| - reinterpret_cast<PCMWaveInAudioInputStream*>(instance);
|
| -
|
| - // The lock ensures that Stop() can't be called during a callback.
|
| - base::AutoLock auto_lock(obj->lock_);
|
| -
|
| - if (msg == WIM_DATA) {
|
| - // The WIM_DATA message is sent when waveform-audio data is present in
|
| - // the input buffer and the buffer is being returned to the application.
|
| - // The message can be sent when the buffer is full or after the
|
| - // waveInReset function is called.
|
| - if (obj->callback_) {
|
| - // TODO(henrika): the |volume| parameter is always set to zero since
|
| - // there is currently no support for controlling the microphone volume
|
| - // level.
|
| - WAVEHDR* buffer = reinterpret_cast<WAVEHDR*>(param1);
|
| - obj->audio_bus_->FromInterleaved(
|
| - reinterpret_cast<uint8_t*>(buffer->lpData), obj->audio_bus_->frames(),
|
| - obj->format_.wBitsPerSample / 8);
|
| - obj->callback_->OnData(
|
| - obj, obj->audio_bus_.get(), buffer->dwBytesRecorded, 0.0);
|
| -
|
| - // Queue the finished buffer back with the audio driver. Since we are
|
| - // reusing the same buffers we can get away without calling
|
| - // waveInPrepareHeader.
|
| - obj->QueueNextPacket(buffer);
|
| - } else {
|
| - // Main thread has called Stop() and set |callback_| to NULL and is
|
| - // now waiting to issue waveInReset which will kill this thread.
|
| - // We should not call AudioSourceCallback code anymore.
|
| - ::SetEvent(obj->stopped_event_.Get());
|
| - }
|
| - } else if (msg == WIM_CLOSE) {
|
| - // Intentionaly no-op for now.
|
| - } else if (msg == WIM_OPEN) {
|
| - // Intentionaly no-op for now.
|
| - }
|
| -}
|
| -
|
| -} // namespace media
|
|
|