summaryrefslogtreecommitdiff
path: root/media/audio
diff options
context:
space:
mode:
authorTorne (Richard Coles) <torne@google.com>2013-09-12 12:10:22 +0100
committerTorne (Richard Coles) <torne@google.com>2013-09-12 12:10:22 +0100
commit58537e28ecd584eab876aee8be7156509866d23a (patch)
tree8988984e52090aaadf33cff139d7dd212cd13656 /media/audio
parent0a1b11dee8e5cb2520121c300858fea6138e3c54 (diff)
downloadchromium_org-58537e28ecd584eab876aee8be7156509866d23a.tar.gz
Merge from Chromium at DEPS revision 222756
This commit was generated by merge_to_master.py. Change-Id: I40d7f32f195f328f005f230ea80d07092d48040e
Diffstat (limited to 'media/audio')
-rw-r--r--media/audio/android/audio_manager_android.cc17
-rw-r--r--media/audio/android/audio_manager_android.h3
-rw-r--r--media/audio/audio_input_controller.cc8
-rw-r--r--media/audio/audio_input_device.cc4
-rw-r--r--media/audio/audio_input_device_unittest.cc2
-rw-r--r--media/audio/audio_low_latency_input_output_unittest.cc3
-rw-r--r--media/audio/audio_manager.h39
-rw-r--r--media/audio/audio_manager_base.cc78
-rw-r--r--media/audio/audio_manager_base.h24
-rw-r--r--media/audio/audio_manager_unittest.cc145
-rw-r--r--media/audio/audio_output_controller.cc23
-rw-r--r--media/audio/audio_output_controller.h15
-rw-r--r--media/audio/audio_output_controller_unittest.cc4
-rw-r--r--media/audio/audio_output_dispatcher.cc2
-rw-r--r--media/audio/audio_output_dispatcher.h2
-rw-r--r--media/audio/audio_output_dispatcher_impl.cc6
-rw-r--r--media/audio/audio_output_dispatcher_impl.h1
-rw-r--r--media/audio/audio_output_proxy_unittest.cc57
-rw-r--r--media/audio/audio_output_resampler.cc8
-rw-r--r--media/audio/audio_output_resampler.h4
-rw-r--r--media/audio/cras/audio_manager_cras.cc8
-rw-r--r--media/audio/cras/audio_manager_cras.h2
-rw-r--r--media/audio/cras/cras_input.cc1
-rw-r--r--media/audio/ios/audio_manager_ios.h56
-rw-r--r--media/audio/ios/audio_manager_ios.mm140
-rw-r--r--media/audio/ios/audio_manager_ios_unittest.cc34
-rw-r--r--media/audio/ios/audio_session_util_ios.h17
-rw-r--r--media/audio/ios/audio_session_util_ios.mm40
-rw-r--r--media/audio/linux/alsa_output_unittest.cc6
-rw-r--r--media/audio/linux/audio_manager_linux.cc89
-rw-r--r--media/audio/linux/audio_manager_linux.h22
-rw-r--r--media/audio/mac/audio_auhal_mac_unittest.cc2
-rw-r--r--media/audio/mac/audio_input_mac.cc5
-rw-r--r--media/audio/mac/audio_low_latency_input_mac.cc32
-rw-r--r--media/audio/mac/audio_low_latency_input_mac.h3
-rw-r--r--media/audio/mac/audio_manager_mac.cc171
-rw-r--r--media/audio/mac/audio_manager_mac.h7
-rw-r--r--media/audio/mock_audio_manager.cc20
-rw-r--r--media/audio/mock_audio_manager.h9
-rw-r--r--media/audio/openbsd/audio_manager_openbsd.cc5
-rw-r--r--media/audio/openbsd/audio_manager_openbsd.h2
-rw-r--r--media/audio/pulse/audio_manager_pulse.cc52
-rw-r--r--media/audio/pulse/audio_manager_pulse.h6
-rw-r--r--media/audio/win/audio_low_latency_output_win.cc44
-rw-r--r--media/audio/win/audio_low_latency_output_win.h9
-rw-r--r--media/audio/win/audio_low_latency_output_win_unittest.cc4
-rw-r--r--media/audio/win/audio_manager_win.cc129
-rw-r--r--media/audio/win/audio_manager_win.h13
-rw-r--r--media/audio/win/audio_output_win_unittest.cc40
-rw-r--r--media/audio/win/audio_unified_win_unittest.cc15
-rw-r--r--media/audio/win/core_audio_util_win.cc76
-rw-r--r--media/audio/win/core_audio_util_win.h10
-rw-r--r--media/audio/win/core_audio_util_win_unittest.cc44
-rw-r--r--media/audio/win/device_enumeration_win.cc59
-rw-r--r--media/audio/win/device_enumeration_win.h16
55 files changed, 1033 insertions, 600 deletions
diff --git a/media/audio/android/audio_manager_android.cc b/media/audio/android/audio_manager_android.cc
index 164344aba0..e6eed7fea4 100644
--- a/media/audio/android/audio_manager_android.cc
+++ b/media/audio/android/audio_manager_android.cc
@@ -74,9 +74,12 @@ AudioParameters AudioManagerAndroid::GetInputStreamParameters(
}
AudioOutputStream* AudioManagerAndroid::MakeAudioOutputStream(
- const AudioParameters& params, const std::string& input_device_id) {
+ const AudioParameters& params,
+ const std::string& device_id,
+ const std::string& input_device_id) {
AudioOutputStream* stream =
- AudioManagerBase::MakeAudioOutputStream(params, std::string());
+ AudioManagerBase::MakeAudioOutputStream(params, std::string(),
+ std::string());
if (stream && output_stream_count() == 1) {
SetAudioMode(kAudioModeInCommunication);
RegisterHeadsetReceiver();
@@ -104,13 +107,16 @@ void AudioManagerAndroid::ReleaseInputStream(AudioInputStream* stream) {
}
AudioOutputStream* AudioManagerAndroid::MakeLinearOutputStream(
- const AudioParameters& params) {
+ const AudioParameters& params) {
DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
return new OpenSLESOutputStream(this, params);
}
AudioOutputStream* AudioManagerAndroid::MakeLowLatencyOutputStream(
- const AudioParameters& params, const std::string& input_device_id) {
+ const AudioParameters& params,
+ const std::string& device_id,
+ const std::string& input_device_id) {
+ DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
return new OpenSLESOutputStream(this, params);
}
@@ -140,7 +146,10 @@ int AudioManagerAndroid::GetOptimalOutputFrameSize(int sample_rate,
}
AudioParameters AudioManagerAndroid::GetPreferredOutputStreamParameters(
+ const std::string& output_device_id,
const AudioParameters& input_params) {
+ // TODO(tommi): Support |output_device_id|.
+ DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!";
ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
int sample_rate = GetNativeOutputSampleRate();
int buffer_size = GetOptimalOutputFrameSize(sample_rate, 2);
diff --git a/media/audio/android/audio_manager_android.h b/media/audio/android/audio_manager_android.h
index fa1c3736a3..ba5bed61e3 100644
--- a/media/audio/android/audio_manager_android.h
+++ b/media/audio/android/audio_manager_android.h
@@ -25,6 +25,7 @@ class MEDIA_EXPORT AudioManagerAndroid : public AudioManagerBase {
virtual AudioOutputStream* MakeAudioOutputStream(
const AudioParameters& params,
+ const std::string& device_id,
const std::string& input_device_id) OVERRIDE;
virtual AudioInputStream* MakeAudioInputStream(
const AudioParameters& params, const std::string& device_id) OVERRIDE;
@@ -36,6 +37,7 @@ class MEDIA_EXPORT AudioManagerAndroid : public AudioManagerBase {
const AudioParameters& params) OVERRIDE;
virtual AudioOutputStream* MakeLowLatencyOutputStream(
const AudioParameters& params,
+ const std::string& device_id,
const std::string& input_device_id) OVERRIDE;
virtual AudioInputStream* MakeLinearInputStream(
const AudioParameters& params, const std::string& device_id) OVERRIDE;
@@ -48,6 +50,7 @@ class MEDIA_EXPORT AudioManagerAndroid : public AudioManagerBase {
virtual ~AudioManagerAndroid();
virtual AudioParameters GetPreferredOutputStreamParameters(
+ const std::string& output_device_id,
const AudioParameters& input_params) OVERRIDE;
private:
diff --git a/media/audio/audio_input_controller.cc b/media/audio/audio_input_controller.cc
index d701337b51..ef94d1274d 100644
--- a/media/audio/audio_input_controller.cc
+++ b/media/audio/audio_input_controller.cc
@@ -19,16 +19,10 @@ const int kMaxInputChannels = 2;
// breakage (very hard to repro bugs!) on other platforms: See
// http://crbug.com/226327 and http://crbug.com/230972.
const int kTimerResetIntervalSeconds = 1;
-#if defined(OS_IOS)
-// The first callback on iOS is received after the current background
-// audio has faded away.
-const int kTimerInitialIntervalSeconds = 4;
-#else
// We have received reports that the timer can be too trigger happy on some
// Mac devices and the initial timer interval has therefore been increased
// from 1 second to 5 seconds.
const int kTimerInitialIntervalSeconds = 5;
-#endif // defined(OS_IOS)
}
namespace media {
@@ -179,7 +173,7 @@ void AudioInputController::DoCreate(AudioManager* audio_manager,
SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CreateTime");
// TODO(miu): See TODO at top of file. Until that's resolved, assume all
// platform audio input requires the |no_data_timer_| be used to auto-detect
- // errors. In reality, probably only Windows and IOS need to be treated as
+ // errors. In reality, probably only Windows needs to be treated as
// unreliable here.
DoCreateForStream(audio_manager->MakeAudioInputStream(params, device_id),
true);
diff --git a/media/audio/audio_input_device.cc b/media/audio/audio_input_device.cc
index 5477be6e63..d7685840ec 100644
--- a/media/audio/audio_input_device.cc
+++ b/media/audio/audio_input_device.cc
@@ -291,7 +291,9 @@ void AudioInputDevice::AudioThreadCallback::Process(int pending_data) {
uint8* ptr = static_cast<uint8*>(shared_memory_.memory());
ptr += current_segment_id_ * segment_length_;
AudioInputBuffer* buffer = reinterpret_cast<AudioInputBuffer*>(ptr);
- DCHECK_EQ(buffer->params.size,
+ // Usually this will be equal but in the case of low sample rate (e.g. 8kHz,
+ // the buffer may be bigger (on mac at least)).
+ DCHECK_GE(buffer->params.size,
segment_length_ - sizeof(AudioInputBufferParameters));
double volume = buffer->params.volume;
bool key_pressed = buffer->params.key_pressed;
diff --git a/media/audio/audio_input_device_unittest.cc b/media/audio/audio_input_device_unittest.cc
index dc211a48a9..61a97832f6 100644
--- a/media/audio/audio_input_device_unittest.cc
+++ b/media/audio/audio_input_device_unittest.cc
@@ -164,7 +164,7 @@ TEST_F(AudioInputDeviceTest, WinXPDeviceIdUnchanged) {
}
}
-TEST_F(AudioInputDeviceTest, ConvertToWinXPDeviceId) {
+TEST_F(AudioInputDeviceTest, ConvertToWinXPInputDeviceId) {
if (!CanRunAudioTest())
return;
diff --git a/media/audio/audio_low_latency_input_output_unittest.cc b/media/audio/audio_low_latency_input_output_unittest.cc
index 33729c45a0..a616761294 100644
--- a/media/audio/audio_low_latency_input_output_unittest.cc
+++ b/media/audio/audio_low_latency_input_output_unittest.cc
@@ -308,7 +308,8 @@ class AudioOutputStreamTraits {
static StreamType* CreateStream(AudioManager* audio_manager,
const AudioParameters& params) {
- return audio_manager->MakeAudioOutputStream(params, std::string());
+ return audio_manager->MakeAudioOutputStream(params, std::string(),
+ std::string());
}
};
diff --git a/media/audio/audio_manager.h b/media/audio/audio_manager.h
index cc5b95c819..891d2a2658 100644
--- a/media/audio/audio_manager.h
+++ b/media/audio/audio_manager.h
@@ -58,11 +58,16 @@ class MEDIA_EXPORT AudioManager {
// threads to avoid blocking the rest of the application.
virtual void ShowAudioInputSettings() = 0;
- // Appends a list of available input devices. It is not guaranteed that
- // all the devices in the list support all formats and sample rates for
+ // Appends a list of available input devices to |device_names|,
+ // which must initially be empty. It is not guaranteed that all the
+ // devices in the list support all formats and sample rates for
// recording.
virtual void GetAudioInputDeviceNames(AudioDeviceNames* device_names) = 0;
+ // Appends a list of available output devices to |device_names|,
+ // which must initially be empty.
+ virtual void GetAudioOutputDeviceNames(AudioDeviceNames* device_names) = 0;
+
// Factory for all the supported stream formats. |params| defines parameters
// of the audio stream to be created.
//
@@ -71,6 +76,14 @@ class MEDIA_EXPORT AudioManager {
// or three buffers are created, one will be locked for playback and one will
// be ready to be filled in the call to AudioSourceCallback::OnMoreData().
//
+ // To create a stream for the default output device, pass an empty string
+ // for |device_id|, otherwise the specified audio device will be opened.
+ //
+ // The |input_device_id| is used for low-latency unified streams
+ // (input+output) only and then only if the audio parameters specify a >0
+ // input channel count. In other cases this id is ignored and should be
+ // empty.
+ //
// Returns NULL if the combination of the parameters is not supported, or if
// we have reached some other platform specific limit.
//
@@ -82,14 +95,18 @@ class MEDIA_EXPORT AudioManager {
//
// Do not free the returned AudioOutputStream. It is owned by AudioManager.
virtual AudioOutputStream* MakeAudioOutputStream(
- const AudioParameters& params, const std::string& input_device_id) = 0;
+ const AudioParameters& params,
+ const std::string& device_id,
+ const std::string& input_device_id) = 0;
// Creates new audio output proxy. A proxy implements
// AudioOutputStream interface, but unlike regular output stream
// created with MakeAudioOutputStream() it opens device only when a
// sound is actually playing.
virtual AudioOutputStream* MakeAudioOutputStreamProxy(
- const AudioParameters& params, const std::string& input_device_id) = 0;
+ const AudioParameters& params,
+ const std::string& device_id,
+ const std::string& input_device_id) = 0;
// Factory to create audio recording streams.
// |channels| can be 1 or 2.
@@ -130,14 +147,28 @@ class MEDIA_EXPORT AudioManager {
// streams. It is a convenience interface to
// AudioManagerBase::GetPreferredOutputStreamParameters and each AudioManager
// does not need their own implementation to this interface.
+ // TODO(tommi): Remove this method and use GetOutputStreamParameteres instead.
virtual AudioParameters GetDefaultOutputStreamParameters() = 0;
+ // Returns the output hardware audio parameters for a specific output device.
+ virtual AudioParameters GetOutputStreamParameters(
+ const std::string& device_id) = 0;
+
// Returns the input hardware audio parameters of the specific device
// for opening input streams. Each AudioManager needs to implement their own
// version of this interface.
virtual AudioParameters GetInputStreamParameters(
const std::string& device_id) = 0;
+ // Returns the device id of an output device that belongs to the same hardware
+ // as the specified input device.
+ // If the hardware has only an input device (e.g. a webcam), the return value
+ // will be empty (which the caller can then interpret to be the default output
+ // device). Implementations that don't yet support this feature, must return
+ // an empty string.
+ virtual std::string GetAssociatedOutputDeviceID(
+ const std::string& input_device_id) = 0;
+
protected:
AudioManager();
diff --git a/media/audio/audio_manager_base.cc b/media/audio/audio_manager_base.cc
index db77f004e3..1477ce3c5a 100644
--- a/media/audio/audio_manager_base.cc
+++ b/media/audio/audio_manager_base.cc
@@ -38,15 +38,18 @@ const char AudioManagerBase::kDefaultDeviceId[] = "default";
struct AudioManagerBase::DispatcherParams {
DispatcherParams(const AudioParameters& input,
const AudioParameters& output,
- const std::string& device_id)
+ const std::string& output_device_id,
+ const std::string& input_device_id)
: input_params(input),
output_params(output),
- input_device_id(device_id) {}
+ input_device_id(input_device_id),
+ output_device_id(output_device_id) {}
~DispatcherParams() {}
const AudioParameters input_params;
const AudioParameters output_params;
const std::string input_device_id;
+ const std::string output_device_id;
scoped_refptr<AudioOutputDispatcher> dispatcher;
private:
@@ -65,6 +68,7 @@ class AudioManagerBase::CompareByParams {
// of the existing dispatcher are the same as the request dispatcher.
return (dispatcher_->input_params == dispatcher_in->input_params &&
dispatcher_->output_params == dispatcher_in->output_params &&
+ dispatcher_->output_device_id == dispatcher_in->output_device_id &&
(!dispatcher_->input_params.input_channels() ||
dispatcher_->input_device_id == dispatcher_in->input_device_id));
}
@@ -134,6 +138,7 @@ scoped_refptr<base::MessageLoopProxy> AudioManagerBase::GetWorkerLoop() {
AudioOutputStream* AudioManagerBase::MakeAudioOutputStream(
const AudioParameters& params,
+ const std::string& device_id,
const std::string& input_device_id) {
// TODO(miu): Fix ~50 call points across several unit test modules to call
// this method on the audio thread, then uncomment the following:
@@ -159,10 +164,12 @@ AudioOutputStream* AudioManagerBase::MakeAudioOutputStream(
AudioOutputStream* stream;
switch (params.format()) {
case AudioParameters::AUDIO_PCM_LINEAR:
+ DCHECK(device_id.empty())
+ << "AUDIO_PCM_LINEAR supports only the default device.";
stream = MakeLinearOutputStream(params);
break;
case AudioParameters::AUDIO_PCM_LOW_LATENCY:
- stream = MakeLowLatencyOutputStream(params, input_device_id);
+ stream = MakeLowLatencyOutputStream(params, device_id, input_device_id);
break;
case AudioParameters::AUDIO_FAKE:
stream = FakeAudioOutputStream::MakeFakeStream(this, params);
@@ -180,7 +187,8 @@ AudioOutputStream* AudioManagerBase::MakeAudioOutputStream(
}
AudioInputStream* AudioManagerBase::MakeAudioInputStream(
- const AudioParameters& params, const std::string& device_id) {
+ const AudioParameters& params,
+ const std::string& device_id) {
// TODO(miu): Fix ~20 call points across several unit test modules to call
// this method on the audio thread, then uncomment the following:
// DCHECK(message_loop_->BelongsToCurrentThread());
@@ -222,19 +230,26 @@ AudioInputStream* AudioManagerBase::MakeAudioInputStream(
}
AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy(
- const AudioParameters& params, const std::string& input_device_id) {
-#if defined(OS_IOS)
- // IOS implements audio input only.
- NOTIMPLEMENTED();
- return NULL;
-#else
+ const AudioParameters& params,
+ const std::string& device_id,
+ const std::string& input_device_id) {
DCHECK(message_loop_->BelongsToCurrentThread());
+ // If the caller supplied an empty device id to select the default device,
+ // we fetch the actual device id of the default device so that the lookup
+ // will find the correct device regardless of whether it was opened as
+ // "default" or via the specific id.
+ // NOTE: Implementations that don't yet support opening non-default output
+ // devices may return an empty string from GetDefaultOutputDeviceID().
+ std::string output_device_id = device_id.empty() ?
+ GetDefaultOutputDeviceID() : device_id;
+
// If we're not using AudioOutputResampler our output parameters are the same
// as our input parameters.
AudioParameters output_params = params;
if (params.format() == AudioParameters::AUDIO_PCM_LOW_LATENCY) {
- output_params = GetPreferredOutputStreamParameters(params);
+ output_params =
+ GetPreferredOutputStreamParameters(output_device_id, params);
// Ensure we only pass on valid output parameters.
if (!output_params.IsValid()) {
@@ -257,7 +272,8 @@ AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy(
}
DispatcherParams* dispatcher_params =
- new DispatcherParams(params, output_params, input_device_id);
+ new DispatcherParams(params, output_params, output_device_id,
+ input_device_id);
AudioOutputDispatchers::iterator it =
std::find_if(output_dispatchers_.begin(), output_dispatchers_.end(),
@@ -272,23 +288,30 @@ AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy(
scoped_refptr<AudioOutputDispatcher> dispatcher;
if (output_params.format() != AudioParameters::AUDIO_FAKE) {
dispatcher = new AudioOutputResampler(this, params, output_params,
- input_device_id, kCloseDelay);
+ output_device_id, input_device_id,
+ kCloseDelay);
} else {
dispatcher = new AudioOutputDispatcherImpl(this, output_params,
+ output_device_id,
input_device_id, kCloseDelay);
}
dispatcher_params->dispatcher = dispatcher;
output_dispatchers_.push_back(dispatcher_params);
return new AudioOutputProxy(dispatcher.get());
-#endif // defined(OS_IOS)
}
void AudioManagerBase::ShowAudioInputSettings() {
}
void AudioManagerBase::GetAudioInputDeviceNames(
- media::AudioDeviceNames* device_names) {
+ AudioDeviceNames* device_names) {
+}
+
+void AudioManagerBase::GetAudioOutputDeviceNames(
+ AudioDeviceNames* device_names) {
+ // TODO(joi): Remove this and keep pure virtual once implemented everywhere.
+ NOTREACHED() << "Don't use this yet, it's not ready on all platforms!";
}
void AudioManagerBase::ReleaseOutputStream(AudioOutputStream* stream) {
@@ -333,10 +356,6 @@ void AudioManagerBase::Shutdown() {
}
void AudioManagerBase::ShutdownOnAudioThread() {
-// IOS implements audio input only.
-#if defined(OS_IOS)
- return;
-#else
// This should always be running on the audio thread, but since we've cleared
// the audio_thread_ member pointer when we get here, we can't verify exactly
// what thread we're running on. The method is not public though and only
@@ -357,7 +376,6 @@ void AudioManagerBase::ShutdownOnAudioThread() {
}
output_dispatchers_.clear();
-#endif // defined(OS_IOS)
}
void AudioManagerBase::AddOutputDeviceChangeListener(
@@ -379,7 +397,14 @@ void AudioManagerBase::NotifyAllOutputDeviceChangeListeners() {
}
AudioParameters AudioManagerBase::GetDefaultOutputStreamParameters() {
- return GetPreferredOutputStreamParameters(AudioParameters());
+ return GetPreferredOutputStreamParameters(GetDefaultOutputDeviceID(),
+ AudioParameters());
+}
+
+AudioParameters AudioManagerBase::GetOutputStreamParameters(
+ const std::string& device_id) {
+ return GetPreferredOutputStreamParameters(device_id,
+ AudioParameters());
}
AudioParameters AudioManagerBase::GetInputStreamParameters(
@@ -388,4 +413,15 @@ AudioParameters AudioManagerBase::GetInputStreamParameters(
return AudioParameters();
}
+std::string AudioManagerBase::GetAssociatedOutputDeviceID(
+ const std::string& input_device_id) {
+ NOTIMPLEMENTED();
+ return "";
+}
+
+std::string AudioManagerBase::GetDefaultOutputDeviceID() {
+ NOTIMPLEMENTED();
+ return "";
+}
+
} // namespace media
diff --git a/media/audio/audio_manager_base.h b/media/audio/audio_manager_base.h
index 8b34d9fcf9..15c1b24066 100644
--- a/media/audio/audio_manager_base.h
+++ b/media/audio/audio_manager_base.h
@@ -47,10 +47,14 @@ class MEDIA_EXPORT AudioManagerBase : public AudioManager {
virtual void ShowAudioInputSettings() OVERRIDE;
virtual void GetAudioInputDeviceNames(
- media::AudioDeviceNames* device_names) OVERRIDE;
+ AudioDeviceNames* device_names) OVERRIDE;
+
+ virtual void GetAudioOutputDeviceNames(
+ AudioDeviceNames* device_names) OVERRIDE;
virtual AudioOutputStream* MakeAudioOutputStream(
const AudioParameters& params,
+ const std::string& device_id,
const std::string& input_device_id) OVERRIDE;
virtual AudioInputStream* MakeAudioInputStream(
@@ -58,6 +62,7 @@ class MEDIA_EXPORT AudioManagerBase : public AudioManager {
virtual AudioOutputStream* MakeAudioOutputStreamProxy(
const AudioParameters& params,
+ const std::string& device_id,
const std::string& input_device_id) OVERRIDE;
// Called internally by the audio stream when it has been closed.
@@ -72,7 +77,9 @@ class MEDIA_EXPORT AudioManagerBase : public AudioManager {
// Creates the output stream for the |AUDIO_PCM_LOW_LATENCY| format.
// |input_device_id| is used by unified IO to open the correct input device.
virtual AudioOutputStream* MakeLowLatencyOutputStream(
- const AudioParameters& params, const std::string& input_device_id) = 0;
+ const AudioParameters& params,
+ const std::string& device_id,
+ const std::string& input_device_id) = 0;
// Creates the input stream for the |AUDIO_PCM_LINEAR| format. The legacy
// name is also from |AUDIO_PCM_LINEAR|.
@@ -90,9 +97,15 @@ class MEDIA_EXPORT AudioManagerBase : public AudioManager {
AudioDeviceListener* listener) OVERRIDE;
virtual AudioParameters GetDefaultOutputStreamParameters() OVERRIDE;
+ virtual AudioParameters GetOutputStreamParameters(
+ const std::string& device_id) OVERRIDE;
+
virtual AudioParameters GetInputStreamParameters(
const std::string& device_id) OVERRIDE;
+ virtual std::string GetAssociatedOutputDeviceID(
+ const std::string& input_device_id) OVERRIDE;
+
protected:
AudioManagerBase();
@@ -115,9 +128,16 @@ class MEDIA_EXPORT AudioManagerBase : public AudioManager {
// will decide if they should return the values from |input_params| or the
// default hardware values. If the |input_params| is invalid, it will return
// the default hardware audio parameters.
+ // If |output_device_id| is empty, the implementation must treat that as
+ // a request for the default output device.
virtual AudioParameters GetPreferredOutputStreamParameters(
+ const std::string& output_device_id,
const AudioParameters& input_params) = 0;
+ // Returns the ID of the default audio output device.
+ // Implementations that don't yet support this should return an empty string.
+ virtual std::string GetDefaultOutputDeviceID();
+
// Get number of input or output streams.
int input_stream_count() { return num_input_streams_; }
int output_stream_count() { return num_output_streams_; }
diff --git a/media/audio/audio_manager_unittest.cc b/media/audio/audio_manager_unittest.cc
new file mode 100644
index 0000000000..96300c9a83
--- /dev/null
+++ b/media/audio/audio_manager_unittest.cc
@@ -0,0 +1,145 @@
+// 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 "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "media/audio/audio_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_LINUX)
+#include "media/audio/linux/audio_manager_linux.h"
+#endif // defined(OS_LINUX)
+
+#if defined(OS_WIN)
+#include "media/audio/win/audio_manager_win.h"
+#endif // defined(OS_WIN)
+
+#if defined(USE_PULSEAUDIO)
+#include "media/audio/pulse/audio_manager_pulse.h"
+#endif // defined(USE_PULSEAUDIO)
+
+namespace media {
+
+void GetAudioOutputDeviceNamesImpl(AudioManager* audio_manager) {
+ AudioDeviceNames device_names;
+ audio_manager->GetAudioOutputDeviceNames(&device_names);
+
+ VLOG(2) << "Got " << device_names.size() << " audio output devices.";
+ for (AudioDeviceNames::iterator it = device_names.begin();
+ it != device_names.end();
+ ++it) {
+ EXPECT_FALSE(it->unique_id.empty());
+ EXPECT_FALSE(it->device_name.empty());
+ VLOG(2) << "Device ID(" << it->unique_id << "), label: " << it->device_name;
+ }
+}
+
+// So that tests herein can be friends of AudioManagerWin.
+//
+// TODO(joi): Make this go away by unifying audio_manager_unittest.cc
+// and audio_input_device_unittest.cc
+class AudioManagerTest : public ::testing::Test {
+ public:
+ bool SetupForSecondTest(AudioManager* amw) {
+#if defined(OS_WIN)
+ AudioManagerWin* audio_manager_win = static_cast<AudioManagerWin*>(amw);
+ if (audio_manager_win->enumeration_type() ==
+ AudioManagerWin::kWaveEnumeration) {
+ // This will be true only if running on Windows XP.
+ VLOG(2) << "AudioManagerWin on WinXP; nothing more to test.";
+ } else {
+ VLOG(2) << "Testing AudioManagerWin in fallback WinXP mode.";
+ audio_manager_win->SetEnumerationType(AudioManagerWin::kWaveEnumeration);
+ return true;
+ }
+#endif // defined(OS_WIN)
+ return false;
+ }
+};
+
+TEST_F(AudioManagerTest, GetAudioOutputDeviceNames) {
+ // On Linux, we may be able to test both the Alsa and Pulseaudio
+ // versions of the audio manager.
+#if defined(USE_PULSEAUDIO)
+ {
+ VLOG(2) << "Testing AudioManagerPulse.";
+ scoped_ptr<AudioManager> pulse_audio_manager(AudioManagerPulse::Create());
+ if (pulse_audio_manager.get())
+ GetAudioOutputDeviceNamesImpl(pulse_audio_manager.get());
+ else
+ LOG(WARNING) << "No pulseaudio on this system.";
+ }
+#endif // defined(USE_PULSEAUDIO)
+#if defined(USE_ALSA)
+ {
+ VLOG(2) << "Testing AudioManagerLinux.";
+ scoped_ptr<AudioManager> alsa_audio_manager(new AudioManagerLinux());
+ GetAudioOutputDeviceNamesImpl(alsa_audio_manager.get());
+ }
+#endif // defined(USE_ALSA)
+
+#if defined(OS_MACOSX)
+ VLOG(2) << "Testing platform-default AudioManager.";
+ scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
+ GetAudioOutputDeviceNamesImpl(audio_manager.get());
+#endif // defined(OS_MACOSX)
+
+#if defined(OS_WIN)
+ {
+ // TODO(joi): Unify the tests in audio_input_device_unittest.cc
+ // with the tests in this file, and reuse the Windows-specific
+ // bits from that file.
+ VLOG(2) << "Testing AudioManagerWin in its default mode.";
+ scoped_ptr<AudioManager> audio_manager_win(AudioManager::Create());
+ GetAudioOutputDeviceNamesImpl(audio_manager_win.get());
+
+ if (SetupForSecondTest(audio_manager_win.get())) {
+ GetAudioOutputDeviceNamesImpl(audio_manager_win.get());
+ }
+ }
+#endif // defined(OS_WIN)
+}
+
+TEST_F(AudioManagerTest, GetDefaultOutputStreamParameters) {
+#if defined(OS_WIN) || defined(OS_MACOSX)
+ scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
+ ASSERT_TRUE(audio_manager);
+ if (!audio_manager->HasAudioOutputDevices())
+ return;
+
+ AudioParameters params = audio_manager->GetDefaultOutputStreamParameters();
+ EXPECT_TRUE(params.IsValid());
+#endif // defined(OS_WIN) || defined(OS_MACOSX)
+}
+
+TEST_F(AudioManagerTest, GetAssociatedOutputDeviceID) {
+#if defined(OS_WIN) || defined(OS_MACOSX)
+ scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
+ ASSERT_TRUE(audio_manager);
+ if (!audio_manager->HasAudioOutputDevices() ||
+ !audio_manager->HasAudioInputDevices()) {
+ return;
+ }
+
+ AudioDeviceNames device_names;
+ audio_manager->GetAudioInputDeviceNames(&device_names);
+ bool found_an_associated_device = false;
+ for (AudioDeviceNames::iterator it = device_names.begin();
+ it != device_names.end();
+ ++it) {
+ EXPECT_FALSE(it->unique_id.empty());
+ EXPECT_FALSE(it->device_name.empty());
+ std::string output_device_id(
+ audio_manager->GetAssociatedOutputDeviceID(it->unique_id));
+ if (!output_device_id.empty()) {
+ VLOG(2) << it->unique_id << " matches with " << output_device_id;
+ found_an_associated_device = true;
+ }
+ }
+
+ EXPECT_TRUE(found_an_associated_device);
+#endif // defined(OS_WIN) || defined(OS_MACOSX)
+}
+
+} // namespace media
diff --git a/media/audio/audio_output_controller.cc b/media/audio/audio_output_controller.cc
index f7f4cf8240..1784c9b69a 100644
--- a/media/audio/audio_output_controller.cc
+++ b/media/audio/audio_output_controller.cc
@@ -32,14 +32,17 @@ static const int kPowerMeasurementsPerSecond = 30;
const int AudioOutputController::kPollNumAttempts = 3;
const int AudioOutputController::kPollPauseInMilliseconds = 3;
-AudioOutputController::AudioOutputController(AudioManager* audio_manager,
- EventHandler* handler,
- const AudioParameters& params,
- const std::string& input_device_id,
- SyncReader* sync_reader)
+AudioOutputController::AudioOutputController(
+ AudioManager* audio_manager,
+ EventHandler* handler,
+ const AudioParameters& params,
+ const std::string& output_device_id,
+ const std::string& input_device_id,
+ SyncReader* sync_reader)
: audio_manager_(audio_manager),
params_(params),
handler_(handler),
+ output_device_id_(output_device_id),
input_device_id_(input_device_id),
stream_(NULL),
diverting_to_stream_(NULL),
@@ -67,6 +70,7 @@ scoped_refptr<AudioOutputController> AudioOutputController::Create(
AudioManager* audio_manager,
EventHandler* event_handler,
const AudioParameters& params,
+ const std::string& output_device_id,
const std::string& input_device_id,
SyncReader* sync_reader) {
DCHECK(audio_manager);
@@ -76,7 +80,8 @@ scoped_refptr<AudioOutputController> AudioOutputController::Create(
return NULL;
scoped_refptr<AudioOutputController> controller(new AudioOutputController(
- audio_manager, event_handler, params, input_device_id, sync_reader));
+ audio_manager, event_handler, params, output_device_id, input_device_id,
+ sync_reader));
controller->message_loop_->PostTask(FROM_HERE, base::Bind(
&AudioOutputController::DoCreate, controller, false));
return controller;
@@ -114,8 +119,10 @@ void AudioOutputController::DoCreate(bool is_for_device_change) {
DoStopCloseAndClearStream(); // Calls RemoveOutputDeviceChangeListener().
DCHECK_EQ(kEmpty, state_);
- stream_ = diverting_to_stream_ ? diverting_to_stream_ :
- audio_manager_->MakeAudioOutputStreamProxy(params_, input_device_id_);
+ stream_ = diverting_to_stream_ ?
+ diverting_to_stream_ :
+ audio_manager_->MakeAudioOutputStreamProxy(params_, output_device_id_,
+ input_device_id_);
if (!stream_) {
state_ = kError;
handler_->OnError();
diff --git a/media/audio/audio_output_controller.h b/media/audio/audio_output_controller.h
index 38a2c03f59..387214e1d0 100644
--- a/media/audio/audio_output_controller.h
+++ b/media/audio/audio_output_controller.h
@@ -101,10 +101,14 @@ class MEDIA_EXPORT AudioOutputController
// thread, and if this is successful, the |event_handler| will receive an
// OnCreated() call from the same audio manager thread. |audio_manager| must
// outlive AudioOutputController.
+ // The |output_device_id| can be either empty (default device) or specify a
+ // specific hardware device for audio output. The |input_device_id| is
+ // used only for unified audio when opening up input and output at the same
+ // time (controlled by |params.input_channel_count()|).
static scoped_refptr<AudioOutputController> Create(
AudioManager* audio_manager, EventHandler* event_handler,
- const AudioParameters& params, const std::string& input_device_id,
- SyncReader* sync_reader);
+ const AudioParameters& params, const std::string& output_device_id,
+ const std::string& input_device_id, SyncReader* sync_reader);
// Methods to control playback of the stream.
@@ -166,6 +170,7 @@ class MEDIA_EXPORT AudioOutputController
AudioOutputController(AudioManager* audio_manager, EventHandler* handler,
const AudioParameters& params,
+ const std::string& output_device_id,
const std::string& input_device_id,
SyncReader* sync_reader);
@@ -198,8 +203,12 @@ class MEDIA_EXPORT AudioOutputController
const AudioParameters params_;
EventHandler* const handler_;
+ // Specifies the device id of the output device to open or empty for the
+ // default output device.
+ const std::string output_device_id_;
+
// Used by the unified IO to open the correct input device.
- std::string input_device_id_;
+ const std::string input_device_id_;
AudioOutputStream* stream_;
diff --git a/media/audio/audio_output_controller_unittest.cc b/media/audio/audio_output_controller_unittest.cc
index 128cc07716..37305c3978 100644
--- a/media/audio/audio_output_controller_unittest.cc
+++ b/media/audio/audio_output_controller_unittest.cc
@@ -29,8 +29,6 @@ static const int kSampleRate = AudioParameters::kAudioCDSampleRate;
static const int kBitsPerSample = 16;
static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO;
static const int kSamplesPerPacket = kSampleRate / 100;
-static const int kHardwareBufferSize = kSamplesPerPacket *
- ChannelLayoutToChannelCount(kChannelLayout) * kBitsPerSample / 8;
static const double kTestVolume = 0.25;
class MockAudioOutputControllerEventHandler
@@ -122,7 +120,7 @@ class AudioOutputControllerTest : public testing::Test {
controller_ = AudioOutputController::Create(
audio_manager_.get(), &mock_event_handler_, params_, std::string(),
- &mock_sync_reader_);
+ std::string(), &mock_sync_reader_);
if (controller_.get())
controller_->SetVolume(kTestVolume);
diff --git a/media/audio/audio_output_dispatcher.cc b/media/audio/audio_output_dispatcher.cc
index 06206d7be7..a151c449f0 100644
--- a/media/audio/audio_output_dispatcher.cc
+++ b/media/audio/audio_output_dispatcher.cc
@@ -11,10 +11,12 @@ namespace media {
AudioOutputDispatcher::AudioOutputDispatcher(
AudioManager* audio_manager,
const AudioParameters& params,
+ const std::string& output_device_id,
const std::string& input_device_id)
: audio_manager_(audio_manager),
message_loop_(base::MessageLoop::current()),
params_(params),
+ output_device_id_(output_device_id),
input_device_id_(input_device_id) {
// We expect to be instantiated on the audio thread. Otherwise the
// message_loop_ member will point to the wrong message loop!
diff --git a/media/audio/audio_output_dispatcher.h b/media/audio/audio_output_dispatcher.h
index a79fd94477..30266ed6a9 100644
--- a/media/audio/audio_output_dispatcher.h
+++ b/media/audio/audio_output_dispatcher.h
@@ -38,6 +38,7 @@ class MEDIA_EXPORT AudioOutputDispatcher
public:
AudioOutputDispatcher(AudioManager* audio_manager,
const AudioParameters& params,
+ const std::string& output_device_id,
const std::string& input_device_id);
// Called by AudioOutputProxy to open the stream.
@@ -79,6 +80,7 @@ class MEDIA_EXPORT AudioOutputDispatcher
AudioManager* audio_manager_;
base::MessageLoop* message_loop_;
AudioParameters params_;
+ const std::string output_device_id_;
const std::string input_device_id_;
private:
diff --git a/media/audio/audio_output_dispatcher_impl.cc b/media/audio/audio_output_dispatcher_impl.cc
index 1df8e7ddd5..bcdcd65146 100644
--- a/media/audio/audio_output_dispatcher_impl.cc
+++ b/media/audio/audio_output_dispatcher_impl.cc
@@ -19,9 +19,11 @@ namespace media {
AudioOutputDispatcherImpl::AudioOutputDispatcherImpl(
AudioManager* audio_manager,
const AudioParameters& params,
+ const std::string& output_device_id,
const std::string& input_device_id,
const base::TimeDelta& close_delay)
- : AudioOutputDispatcher(audio_manager, params, input_device_id),
+ : AudioOutputDispatcher(audio_manager, params, output_device_id,
+ input_device_id),
pause_delay_(base::TimeDelta::FromMicroseconds(
2 * params.frames_per_buffer() * base::Time::kMicrosecondsPerSecond /
static_cast<float>(params.sample_rate()))),
@@ -168,7 +170,7 @@ void AudioOutputDispatcherImpl::Shutdown() {
bool AudioOutputDispatcherImpl::CreateAndOpenStream() {
DCHECK_EQ(base::MessageLoop::current(), message_loop_);
AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream(
- params_, input_device_id_);
+ params_, output_device_id_, input_device_id_);
if (!stream)
return false;
diff --git a/media/audio/audio_output_dispatcher_impl.h b/media/audio/audio_output_dispatcher_impl.h
index 06fe3ebeaf..b59f835f9b 100644
--- a/media/audio/audio_output_dispatcher_impl.h
+++ b/media/audio/audio_output_dispatcher_impl.h
@@ -35,6 +35,7 @@ class MEDIA_EXPORT AudioOutputDispatcherImpl : public AudioOutputDispatcher {
// the audio device is closed.
AudioOutputDispatcherImpl(AudioManager* audio_manager,
const AudioParameters& params,
+ const std::string& output_device_id,
const std::string& input_device_id,
const base::TimeDelta& close_delay);
diff --git a/media/audio/audio_output_proxy_unittest.cc b/media/audio/audio_output_proxy_unittest.cc
index de95b0661e..1806ce6613 100644
--- a/media/audio/audio_output_proxy_unittest.cc
+++ b/media/audio/audio_output_proxy_unittest.cc
@@ -95,10 +95,14 @@ class MockAudioManager : public AudioManagerBase {
MOCK_METHOD0(HasAudioOutputDevices, bool());
MOCK_METHOD0(HasAudioInputDevices, bool());
MOCK_METHOD0(GetAudioInputDeviceModel, string16());
- MOCK_METHOD2(MakeAudioOutputStream, AudioOutputStream*(
- const AudioParameters& params, const std::string& input_device_id));
- MOCK_METHOD2(MakeAudioOutputStreamProxy, AudioOutputStream*(
- const AudioParameters& params, const std::string& input_device_id));
+ MOCK_METHOD3(MakeAudioOutputStream, AudioOutputStream*(
+ const AudioParameters& params,
+ const std::string& device_id,
+ const std::string& input_device_id));
+ MOCK_METHOD3(MakeAudioOutputStreamProxy, AudioOutputStream*(
+ const AudioParameters& params,
+ const std::string& device_id,
+ const std::string& input_device_id));
MOCK_METHOD2(MakeAudioInputStream, AudioInputStream*(
const AudioParameters& params, const std::string& device_id));
MOCK_METHOD0(ShowAudioInputSettings, void());
@@ -108,14 +112,15 @@ class MockAudioManager : public AudioManagerBase {
MOCK_METHOD1(MakeLinearOutputStream, AudioOutputStream*(
const AudioParameters& params));
- MOCK_METHOD2(MakeLowLatencyOutputStream, AudioOutputStream*(
- const AudioParameters& params, const std::string& input_device_id));
+ MOCK_METHOD3(MakeLowLatencyOutputStream, AudioOutputStream*(
+ const AudioParameters& params, const std::string& device_id,
+ const std::string& input_device_id));
MOCK_METHOD2(MakeLinearInputStream, AudioInputStream*(
const AudioParameters& params, const std::string& device_id));
MOCK_METHOD2(MakeLowLatencyInputStream, AudioInputStream*(
const AudioParameters& params, const std::string& device_id));
- MOCK_METHOD1(GetPreferredOutputStreamParameters, AudioParameters(
- const AudioParameters& params));
+ MOCK_METHOD2(GetPreferredOutputStreamParameters, AudioParameters(
+ const std::string& device_id, const AudioParameters& params));
};
class MockAudioSourceCallback : public AudioOutputStream::AudioSourceCallback {
@@ -161,6 +166,7 @@ class AudioOutputProxyTest : public testing::Test {
dispatcher_impl_ = new AudioOutputDispatcherImpl(&manager(),
params_,
std::string(),
+ std::string(),
close_delay);
// Necessary to know how long the dispatcher will wait before posting
@@ -186,7 +192,7 @@ class AudioOutputProxyTest : public testing::Test {
void OpenAndClose(AudioOutputDispatcher* dispatcher) {
MockAudioOutputStream stream(&manager_, params_);
- EXPECT_CALL(manager(), MakeAudioOutputStream(_, _))
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _))
.WillOnce(Return(&stream));
EXPECT_CALL(stream, Open())
.WillOnce(Return(true));
@@ -203,7 +209,7 @@ class AudioOutputProxyTest : public testing::Test {
void StartAndStop(AudioOutputDispatcher* dispatcher) {
MockAudioOutputStream stream(&manager_, params_);
- EXPECT_CALL(manager(), MakeAudioOutputStream(_, _))
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _))
.WillOnce(Return(&stream));
EXPECT_CALL(stream, Open())
.WillOnce(Return(true));
@@ -229,7 +235,7 @@ class AudioOutputProxyTest : public testing::Test {
void CloseAfterStop(AudioOutputDispatcher* dispatcher) {
MockAudioOutputStream stream(&manager_, params_);
- EXPECT_CALL(manager(), MakeAudioOutputStream(_, _))
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _))
.WillOnce(Return(&stream));
EXPECT_CALL(stream, Open())
.WillOnce(Return(true));
@@ -261,7 +267,7 @@ class AudioOutputProxyTest : public testing::Test {
void TwoStreams(AudioOutputDispatcher* dispatcher) {
MockAudioOutputStream stream(&manager_, params_);
- EXPECT_CALL(manager(), MakeAudioOutputStream(_, _))
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _))
.WillOnce(Return(&stream));
EXPECT_CALL(stream, Open())
.WillOnce(Return(true));
@@ -283,7 +289,7 @@ class AudioOutputProxyTest : public testing::Test {
void OpenFailed(AudioOutputDispatcher* dispatcher) {
MockAudioOutputStream stream(&manager_, params_);
- EXPECT_CALL(manager(), MakeAudioOutputStream(_, _))
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _))
.WillOnce(Return(&stream));
EXPECT_CALL(stream, Open())
.WillOnce(Return(false));
@@ -301,7 +307,7 @@ class AudioOutputProxyTest : public testing::Test {
void CreateAndWait(AudioOutputDispatcher* dispatcher) {
MockAudioOutputStream stream(&manager_, params_);
- EXPECT_CALL(manager(), MakeAudioOutputStream(_, _))
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _))
.WillOnce(Return(&stream));
EXPECT_CALL(stream, Open())
.WillOnce(Return(true));
@@ -328,7 +334,7 @@ class AudioOutputProxyTest : public testing::Test {
MockAudioOutputStream stream1(&manager_, params_);
MockAudioOutputStream stream2(&manager_, params_);
- EXPECT_CALL(manager(), MakeAudioOutputStream(_, _))
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _))
.WillOnce(Return(&stream1))
.WillOnce(Return(&stream2));
@@ -366,7 +372,7 @@ class AudioOutputProxyTest : public testing::Test {
MockAudioOutputStream stream1(&manager_, params_);
MockAudioOutputStream stream2(&manager_, params_);
- EXPECT_CALL(manager(), MakeAudioOutputStream(_, _))
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _))
.WillOnce(Return(&stream1))
.WillOnce(Return(&stream2));
@@ -406,7 +412,7 @@ class AudioOutputProxyTest : public testing::Test {
void StartFailed(AudioOutputDispatcher* dispatcher) {
MockAudioOutputStream stream(&manager_, params_);
- EXPECT_CALL(manager(), MakeAudioOutputStream(_, _))
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _))
.WillOnce(Return(&stream));
EXPECT_CALL(stream, Open())
.WillOnce(Return(true));
@@ -425,7 +431,7 @@ class AudioOutputProxyTest : public testing::Test {
Mock::VerifyAndClear(&stream);
// |stream| is closed at this point. Start() should reopen it again.
- EXPECT_CALL(manager(), MakeAudioOutputStream(_, _))
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _))
.Times(2)
.WillRepeatedly(Return(reinterpret_cast<AudioOutputStream*>(NULL)));
@@ -467,7 +473,8 @@ class AudioOutputResamplerTest : public AudioOutputProxyTest {
AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO,
16000, 16, 1024);
resampler_ = new AudioOutputResampler(
- &manager(), params_, resampler_params_, std::string(), close_delay);
+ &manager(), params_, resampler_params_, std::string(), std::string(),
+ close_delay);
}
virtual void OnStart() OVERRIDE {
@@ -568,7 +575,7 @@ TEST_F(AudioOutputResamplerTest, StartFailed) { StartFailed(resampler_.get()); }
// ensure AudioOutputResampler falls back to the high latency path.
TEST_F(AudioOutputResamplerTest, LowLatencyCreateFailedFallback) {
MockAudioOutputStream stream(&manager_, params_);
- EXPECT_CALL(manager(), MakeAudioOutputStream(_, _))
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _))
.Times(2)
.WillOnce(Return(static_cast<AudioOutputStream*>(NULL)))
.WillRepeatedly(Return(&stream));
@@ -588,7 +595,7 @@ TEST_F(AudioOutputResamplerTest, LowLatencyCreateFailedFallback) {
TEST_F(AudioOutputResamplerTest, LowLatencyOpenFailedFallback) {
MockAudioOutputStream failed_stream(&manager_, params_);
MockAudioOutputStream okay_stream(&manager_, params_);
- EXPECT_CALL(manager(), MakeAudioOutputStream(_, _))
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _))
.Times(2)
.WillOnce(Return(&failed_stream))
.WillRepeatedly(Return(&okay_stream));
@@ -619,7 +626,7 @@ TEST_F(AudioOutputResamplerTest, HighLatencyFallbackFailed) {
#else
static const int kFallbackCount = 1;
#endif
- EXPECT_CALL(manager(), MakeAudioOutputStream(_, _))
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _))
.Times(kFallbackCount)
.WillRepeatedly(Return(static_cast<AudioOutputStream*>(NULL)));
@@ -630,7 +637,7 @@ TEST_F(AudioOutputResamplerTest, HighLatencyFallbackFailed) {
testing::Property(&AudioParameters::sample_rate, params_.sample_rate()),
testing::Property(
&AudioParameters::frames_per_buffer, params_.frames_per_buffer())),
- _))
+ _, _))
.Times(1)
.WillOnce(Return(&okay_stream));
EXPECT_CALL(okay_stream, Open())
@@ -655,7 +662,7 @@ TEST_F(AudioOutputResamplerTest, AllFallbackFailed) {
#else
static const int kFallbackCount = 2;
#endif
- EXPECT_CALL(manager(), MakeAudioOutputStream(_, _))
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _))
.Times(kFallbackCount)
.WillRepeatedly(Return(static_cast<AudioOutputStream*>(NULL)));
@@ -673,7 +680,7 @@ TEST_F(AudioOutputResamplerTest, LowLatencyOpenEventuallyFails) {
MockAudioOutputStream stream3(&manager_, params_);
// Setup the mock such that all three streams are successfully created.
- EXPECT_CALL(manager(), MakeAudioOutputStream(_, _))
+ EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _))
.WillOnce(Return(&stream1))
.WillOnce(Return(&stream2))
.WillOnce(Return(&stream3))
diff --git a/media/audio/audio_output_resampler.cc b/media/audio/audio_output_resampler.cc
index 6db0e2fb2f..da424ec124 100644
--- a/media/audio/audio_output_resampler.cc
+++ b/media/audio/audio_output_resampler.cc
@@ -147,12 +147,13 @@ static AudioParameters SetupFallbackParams(
AudioOutputResampler::AudioOutputResampler(AudioManager* audio_manager,
const AudioParameters& input_params,
const AudioParameters& output_params,
+ const std::string& output_device_id,
const std::string& input_device_id,
const base::TimeDelta& close_delay)
- : AudioOutputDispatcher(audio_manager, input_params, input_device_id),
+ : AudioOutputDispatcher(audio_manager, input_params, output_device_id,
+ input_device_id),
close_delay_(close_delay),
output_params_(output_params),
- input_device_id_(input_device_id),
streams_opened_(false) {
DCHECK(input_params.IsValid());
DCHECK(output_params.IsValid());
@@ -172,7 +173,8 @@ void AudioOutputResampler::Initialize() {
DCHECK(!streams_opened_);
DCHECK(callbacks_.empty());
dispatcher_ = new AudioOutputDispatcherImpl(
- audio_manager_, output_params_, input_device_id_, close_delay_);
+ audio_manager_, output_params_, output_device_id_, input_device_id_,
+ close_delay_);
}
bool AudioOutputResampler::OpenStream() {
diff --git a/media/audio/audio_output_resampler.h b/media/audio/audio_output_resampler.h
index df9e4320b5..f9a75ac38f 100644
--- a/media/audio/audio_output_resampler.h
+++ b/media/audio/audio_output_resampler.h
@@ -40,6 +40,7 @@ class MEDIA_EXPORT AudioOutputResampler : public AudioOutputDispatcher {
AudioOutputResampler(AudioManager* audio_manager,
const AudioParameters& input_params,
const AudioParameters& output_params,
+ const std::string& output_device_id,
const std::string& input_device_id,
const base::TimeDelta& close_delay);
@@ -74,9 +75,6 @@ class MEDIA_EXPORT AudioOutputResampler : public AudioOutputDispatcher {
// AudioParameters used to setup the output stream.
AudioParameters output_params_;
- // Device ID to be used by the unified IO to open the correct input device.
- const std::string input_device_id_;
-
// Whether any streams have been opened through |dispatcher_|, if so we can't
// fallback on future OpenStream() failures.
bool streams_opened_;
diff --git a/media/audio/cras/audio_manager_cras.cc b/media/audio/cras/audio_manager_cras.cc
index 165d642922..276487557e 100644
--- a/media/audio/cras/audio_manager_cras.cc
+++ b/media/audio/cras/audio_manager_cras.cc
@@ -76,7 +76,10 @@ AudioOutputStream* AudioManagerCras::MakeLinearOutputStream(
}
AudioOutputStream* AudioManagerCras::MakeLowLatencyOutputStream(
- const AudioParameters& params, const std::string& input_device_id) {
+ const AudioParameters& params,
+ const std::string& device_id,
+ const std::string& input_device_id) {
+ DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
// TODO(dgreid): Open the correct input device for unified IO.
return MakeOutputStream(params);
@@ -95,7 +98,10 @@ AudioInputStream* AudioManagerCras::MakeLowLatencyInputStream(
}
AudioParameters AudioManagerCras::GetPreferredOutputStreamParameters(
+ const std::string& output_device_id,
const AudioParameters& input_params) {
+ // TODO(tommi): Support |output_device_id|.
+ DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!";
static const int kDefaultOutputBufferSize = 512;
ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
diff --git a/media/audio/cras/audio_manager_cras.h b/media/audio/cras/audio_manager_cras.h
index fdc5b02688..41e1876ac8 100644
--- a/media/audio/cras/audio_manager_cras.h
+++ b/media/audio/cras/audio_manager_cras.h
@@ -35,6 +35,7 @@ class MEDIA_EXPORT AudioManagerCras : public AudioManagerBase {
const AudioParameters& params) OVERRIDE;
virtual AudioOutputStream* MakeLowLatencyOutputStream(
const AudioParameters& params,
+ const std::string& device_id,
const std::string& input_device_id) OVERRIDE;
virtual AudioInputStream* MakeLinearInputStream(
const AudioParameters& params, const std::string& device_id) OVERRIDE;
@@ -45,6 +46,7 @@ class MEDIA_EXPORT AudioManagerCras : public AudioManagerBase {
virtual ~AudioManagerCras();
virtual AudioParameters GetPreferredOutputStreamParameters(
+ const std::string& output_device_id,
const AudioParameters& input_params) OVERRIDE;
private:
diff --git a/media/audio/cras/cras_input.cc b/media/audio/cras/cras_input.cc
index a82fe283f7..363dc68227 100644
--- a/media/audio/cras/cras_input.cc
+++ b/media/audio/cras/cras_input.cc
@@ -114,7 +114,6 @@ void CrasInputStream::Start(AudioInputCallback* callback) {
StartAgc();
callback_ = callback;
- LOG(ERROR) << "Input Start";
// Prepare |audio_format| and |stream_params| for the stream we
// will create.
diff --git a/media/audio/ios/audio_manager_ios.h b/media/audio/ios/audio_manager_ios.h
deleted file mode 100644
index 19751502fd..0000000000
--- a/media/audio/ios/audio_manager_ios.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 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.
-
-#ifndef MEDIA_AUDIO_IOS_AUDIO_MANAGER_IOS_H_
-#define MEDIA_AUDIO_IOS_AUDIO_MANAGER_IOS_H_
-
-#include "base/basictypes.h"
-#include "media/audio/audio_manager_base.h"
-
-namespace media {
-
-class PCMQueueInAudioInputStream;
-
-// iOS implementation of the AudioManager singleton. Supports only audio input.
-class MEDIA_EXPORT AudioManagerIOS : public AudioManagerBase {
- public:
- AudioManagerIOS();
-
- // Implementation of AudioManager.
- virtual bool HasAudioOutputDevices() OVERRIDE;
- virtual bool HasAudioInputDevices() OVERRIDE;
- virtual AudioOutputStream* MakeAudioOutputStream(
- const AudioParameters& params,
- const std::string& input_device_id) OVERRIDE;
- virtual AudioInputStream* MakeAudioInputStream(
- const AudioParameters& params, const std::string& device_id) OVERRIDE;
- virtual AudioParameters GetInputStreamParameters(
- const std::string& device_id) OVERRIDE;
-
- // Implementation of AudioManagerBase.
- virtual AudioOutputStream* MakeLinearOutputStream(
- const AudioParameters& params) OVERRIDE;
- virtual AudioOutputStream* MakeLowLatencyOutputStream(
- const AudioParameters& params,
- const std::string& input_device_id) OVERRIDE;
- virtual AudioInputStream* MakeLinearInputStream(
- const AudioParameters& params, const std::string& device_id) OVERRIDE;
- virtual AudioInputStream* MakeLowLatencyInputStream(
- const AudioParameters& params, const std::string& device_id) OVERRIDE;
- virtual void ReleaseOutputStream(AudioOutputStream* stream) OVERRIDE;
- virtual void ReleaseInputStream(AudioInputStream* stream) OVERRIDE;
-
- protected:
- virtual ~AudioManagerIOS();
-
- virtual AudioParameters GetPreferredOutputStreamParameters(
- const AudioParameters& input_params) OVERRIDE;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(AudioManagerIOS);
-};
-
-} // namespace media
-
-#endif // MEDIA_AUDIO_IOS_AUDIO_MANAGER_IOS_H_
diff --git a/media/audio/ios/audio_manager_ios.mm b/media/audio/ios/audio_manager_ios.mm
deleted file mode 100644
index 49479302ef..0000000000
--- a/media/audio/ios/audio_manager_ios.mm
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright 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/ios/audio_manager_ios.h"
-
-#import <AudioToolbox/AudioToolbox.h>
-#import <AVFoundation/AVFoundation.h>
-
-#include "base/sys_info.h"
-#include "media/audio/audio_parameters.h"
-#include "media/audio/fake_audio_input_stream.h"
-#include "media/audio/ios/audio_session_util_ios.h"
-#include "media/audio/mac/audio_input_mac.h"
-#include "media/base/channel_layout.h"
-#include "media/base/limits.h"
-
-namespace media {
-
-enum { kMaxInputChannels = 2 };
-
-AudioManagerIOS::AudioManagerIOS() {
-}
-
-AudioManagerIOS::~AudioManagerIOS() {
- Shutdown();
-}
-
-bool AudioManagerIOS::HasAudioOutputDevices() {
- return false;
-}
-
-bool AudioManagerIOS::HasAudioInputDevices() {
- if (!InitAudioSessionIOS())
- return false;
- // Note that the |kAudioSessionProperty_AudioInputAvailable| property is a
- // 32-bit integer, not a boolean.
- UInt32 property_size;
- OSStatus error =
- AudioSessionGetPropertySize(kAudioSessionProperty_AudioInputAvailable,
- &property_size);
- if (error != kAudioSessionNoError)
- return false;
- UInt32 audio_input_is_available = false;
- DCHECK(property_size == sizeof(audio_input_is_available));
- error = AudioSessionGetProperty(kAudioSessionProperty_AudioInputAvailable,
- &property_size,
- &audio_input_is_available);
- return error == kAudioSessionNoError ? audio_input_is_available : false;
-}
-
-AudioParameters AudioManagerIOS::GetInputStreamParameters(
- const std::string& device_id) {
- // TODO(xians): figure out the right input sample rate and buffer size to
- // achieve the best audio performance for iOS devices.
- // TODO(xians): query the native channel layout for the specific device.
- static const int kDefaultSampleRate = 48000;
- static const int kDefaultBufferSize = 2048;
- return AudioParameters(
- AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO,
- kDefaultSampleRate, 16, kDefaultBufferSize);
-}
-
-AudioOutputStream* AudioManagerIOS::MakeAudioOutputStream(
- const AudioParameters& params, const std::string& input_device_id) {
- NOTIMPLEMENTED(); // Only input is supported on iOS.
- return NULL;
-}
-
-AudioInputStream* AudioManagerIOS::MakeAudioInputStream(
- const AudioParameters& params, const std::string& device_id) {
- // Current line of iOS devices has only one audio input.
- // Ignore the device_id (unittest uses a test value in it).
- if (!params.IsValid() || (params.channels() > kMaxInputChannels))
- return NULL;
-
- if (params.format() == AudioParameters::AUDIO_FAKE)
- return FakeAudioInputStream::MakeFakeStream(this, params);
- else if (params.format() == AudioParameters::AUDIO_PCM_LINEAR)
- return new PCMQueueInAudioInputStream(this, params);
- return NULL;
-}
-
-AudioOutputStream* AudioManagerIOS::MakeLinearOutputStream(
- const AudioParameters& params) {
- NOTIMPLEMENTED(); // Only input is supported on iOS.
- return NULL;
-}
-
-AudioOutputStream* AudioManagerIOS::MakeLowLatencyOutputStream(
- const AudioParameters& params, const std::string& input_device_id) {
- NOTIMPLEMENTED(); // Only input is supported on iOS.
- return NULL;
-}
-
-AudioInputStream* AudioManagerIOS::MakeLinearInputStream(
- const AudioParameters& params, const std::string& device_id) {
- return MakeAudioInputStream(params, device_id);
-}
-
-AudioInputStream* AudioManagerIOS::MakeLowLatencyInputStream(
- const AudioParameters& params, const std::string& device_id) {
- NOTIMPLEMENTED(); // Only linear audio input is supported on iOS.
- return MakeAudioInputStream(params, device_id);
-}
-
-
-AudioParameters AudioManagerIOS::GetPreferredOutputStreamParameters(
- const AudioParameters& input_params) {
- // TODO(xians): handle the case when input_params is valid.
- // TODO(xians): figure out the right output sample rate and sample rate to
- // achieve the best audio performance for iOS devices.
- // TODO(xians): add support to --audio-buffer-size flag.
- static const int kDefaultSampleRate = 48000;
- static const int kDefaultBufferSize = 2048;
- if (input_params.IsValid()) {
- NOTREACHED();
- }
-
- return AudioParameters(
- AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO,
- kDefaultSampleRate, 16, kDefaultBufferSize);
-}
-
-// Called by the stream when it has been released by calling Close().
-void AudioManagerIOS::ReleaseOutputStream(AudioOutputStream* stream) {
- NOTIMPLEMENTED(); // Only input is supported on iOS.
-}
-
-// Called by the stream when it has been released by calling Close().
-void AudioManagerIOS::ReleaseInputStream(AudioInputStream* stream) {
- delete stream;
-}
-
-// static
-AudioManager* CreateAudioManager() {
- return new AudioManagerIOS();
-}
-
-} // namespace media
diff --git a/media/audio/ios/audio_manager_ios_unittest.cc b/media/audio/ios/audio_manager_ios_unittest.cc
deleted file mode 100644
index 30ebc04f20..0000000000
--- a/media/audio/ios/audio_manager_ios_unittest.cc
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 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 "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "media/audio/audio_io.h"
-#include "media/audio/audio_manager.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using namespace media;
-
-// Test that input is supported and output is not.
-TEST(IOSAudioTest, AudioSupport) {
- scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
- ASSERT_TRUE(NULL != audio_manager.get());
- ASSERT_FALSE(audio_manager->HasAudioOutputDevices());
- ASSERT_TRUE(audio_manager->HasAudioInputDevices());
-}
-
-// Test that input stream can be opened and closed.
-TEST(IOSAudioTest, InputStreamOpenAndClose) {
- scoped_ptr<AudioManager> audio_manager(AudioManager::Create());
- ASSERT_TRUE(NULL != audio_manager.get());
- if (!audio_manager->HasAudioInputDevices())
- return;
- AudioInputStream* ias = audio_manager->MakeAudioInputStream(
- AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
- 8000, 16, 1024),
- std::string("test_device"));
- ASSERT_TRUE(NULL != ias);
- EXPECT_TRUE(ias->Open());
- ias->Close();
-}
diff --git a/media/audio/ios/audio_session_util_ios.h b/media/audio/ios/audio_session_util_ios.h
deleted file mode 100644
index 175db91fae..0000000000
--- a/media/audio/ios/audio_session_util_ios.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 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.
-
-#ifndef MEDIA_AUDIO_IOS_AUDIO_SESSION_UTIL_IOS_H_
-#define MEDIA_AUDIO_IOS_AUDIO_SESSION_UTIL_IOS_H_
-
-namespace media {
-
-// Initializes and configures the audio session, returning a bool indicating
-// whether initialization was successful. Can be called multiple times.
-// Safe to call from any thread.
-bool InitAudioSessionIOS();
-
-} // namespace media
-
-#endif // MEDIA_AUDIO_IOS_AUDIO_SESSION_UTIL_IOS_H_
diff --git a/media/audio/ios/audio_session_util_ios.mm b/media/audio/ios/audio_session_util_ios.mm
deleted file mode 100644
index a4071a04cc..0000000000
--- a/media/audio/ios/audio_session_util_ios.mm
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 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/ios/audio_session_util_ios.h"
-
-#include <AVFoundation/AVFoundation.h>
-
-#include "base/logging.h"
-
-namespace media {
-
-bool InitAudioSessionIOS() {
- static bool kSessionInitialized = false;
- static dispatch_once_t once = 0;
- dispatch_once(&once, ^{
- OSStatus error = AudioSessionInitialize(NULL, NULL, NULL, NULL);
- if (error != kAudioSessionNoError)
- DLOG(ERROR) << "AudioSessionInitialize OSStatus error: " << error;
- BOOL result = [[AVAudioSession sharedInstance]
- setCategory:AVAudioSessionCategoryPlayAndRecord
- error:nil];
- if (!result)
- DLOG(ERROR) << "AVAudioSession setCategory failed";
- UInt32 allowMixing = true;
- AudioSessionSetProperty(
- kAudioSessionProperty_OverrideCategoryMixWithOthers,
- sizeof(allowMixing), &allowMixing);
- UInt32 defaultToSpeaker = true;
- AudioSessionSetProperty(
- kAudioSessionProperty_OverrideCategoryDefaultToSpeaker,
- sizeof(defaultToSpeaker),
- &defaultToSpeaker);
- // Speech input cannot be used if either of these two conditions fail.
- kSessionInitialized = (error == kAudioSessionNoError) && result;
- });
- return kSessionInitialized;
-}
-
-} // namespace media
diff --git a/media/audio/linux/alsa_output_unittest.cc b/media/audio/linux/alsa_output_unittest.cc
index 32456360f4..82fbab94c1 100644
--- a/media/audio/linux/alsa_output_unittest.cc
+++ b/media/audio/linux/alsa_output_unittest.cc
@@ -83,8 +83,10 @@ class MockAudioManagerLinux : public AudioManagerLinux {
MOCK_METHOD0(HasAudioInputDevices, bool());
MOCK_METHOD1(MakeLinearOutputStream, AudioOutputStream*(
const AudioParameters& params));
- MOCK_METHOD2(MakeLowLatencyOutputStream, AudioOutputStream*(
- const AudioParameters& params, const std::string& input_device_id));
+ MOCK_METHOD3(MakeLowLatencyOutputStream, AudioOutputStream*(
+ const AudioParameters& params,
+ const std::string& device_id,
+ const std::string& input_device_id));
MOCK_METHOD2(MakeLowLatencyInputStream, AudioInputStream*(
const AudioParameters& params, const std::string& device_id));
diff --git a/media/audio/linux/audio_manager_linux.cc b/media/audio/linux/audio_manager_linux.cc
index 38253e2e65..7596c2fe25 100644
--- a/media/audio/linux/audio_manager_linux.cc
+++ b/media/audio/linux/audio_manager_linux.cc
@@ -42,9 +42,9 @@ static const int kDefaultSampleRate = 48000;
// hence surround devices are not stored in the list.
static const char* kInvalidAudioInputDevices[] = {
"default",
+ "dmix",
"null",
"pulse",
- "dmix",
"surround",
};
@@ -105,7 +105,13 @@ void AudioManagerLinux::ShowAudioInputSettings() {
void AudioManagerLinux::GetAudioInputDeviceNames(
media::AudioDeviceNames* device_names) {
DCHECK(device_names->empty());
- GetAlsaAudioInputDevices(device_names);
+ GetAlsaAudioDevices(kStreamCapture, device_names);
+}
+
+void AudioManagerLinux::GetAudioOutputDeviceNames(
+ media::AudioDeviceNames* device_names) {
+ DCHECK(device_names->empty());
+ GetAlsaAudioDevices(kStreamPlayback, device_names);
}
AudioParameters AudioManagerLinux::GetInputStreamParameters(
@@ -117,7 +123,8 @@ AudioParameters AudioManagerLinux::GetInputStreamParameters(
kDefaultSampleRate, 16, kDefaultInputBufferSize);
}
-void AudioManagerLinux::GetAlsaAudioInputDevices(
+void AudioManagerLinux::GetAlsaAudioDevices(
+ StreamType type,
media::AudioDeviceNames* device_names) {
// Constants specified by the ALSA API for device hints.
static const char kPcmInterfaceName[] = "pcm";
@@ -128,37 +135,40 @@ void AudioManagerLinux::GetAlsaAudioInputDevices(
void** hints = NULL;
int error = wrapper_->DeviceNameHint(card, kPcmInterfaceName, &hints);
if (!error) {
- GetAlsaDevicesInfo(hints, device_names);
+ GetAlsaDevicesInfo(type, hints, device_names);
// Destroy the hints now that we're done with it.
wrapper_->DeviceNameFreeHint(hints);
} else {
- DLOG(WARNING) << "GetAudioInputDevices: unable to get device hints: "
+ DLOG(WARNING) << "GetAlsaAudioDevices: unable to get device hints: "
<< wrapper_->StrError(error);
}
}
}
void AudioManagerLinux::GetAlsaDevicesInfo(
- void** hints, media::AudioDeviceNames* device_names) {
+ AudioManagerLinux::StreamType type,
+ void** hints,
+ media::AudioDeviceNames* device_names) {
static const char kIoHintName[] = "IOID";
static const char kNameHintName[] = "NAME";
static const char kDescriptionHintName[] = "DESC";
- static const char kOutputDevice[] = "Output";
+
+ const char* unwanted_device_type = UnwantedDeviceTypeWhenEnumerating(type);
for (void** hint_iter = hints; *hint_iter != NULL; hint_iter++) {
- // Only examine devices that are input capable. Valid values are
+ // Only examine devices of the right type. Valid values are
// "Input", "Output", and NULL which means both input and output.
scoped_ptr_malloc<char> io(wrapper_->DeviceNameGetHint(*hint_iter,
kIoHintName));
- if (io != NULL && strcmp(kOutputDevice, io.get()) == 0)
+ if (io != NULL && strcmp(unwanted_device_type, io.get()) == 0)
continue;
- // Found an input device, prepend the default device since we always want
- // it to be on the top of the list for all platforms. And there is no
- // duplicate counting here since it is only done if the list is still empty.
- // Note, pulse has exclusively opened the default device, so we must open
- // the device via the "default" moniker.
+ // Found a device, prepend the default device since we always want
+ // it to be on the top of the list for all platforms. And there is
+ // no duplicate counting here since it is only done if the list is
+ // still empty. Note, pulse has exclusively opened the default
+ // device, so we must open the device via the "default" moniker.
if (device_names->empty()) {
device_names->push_front(media::AudioDeviceName(
AudioManagerBase::kDefaultDeviceName,
@@ -170,7 +180,7 @@ void AudioManagerLinux::GetAlsaDevicesInfo(
wrapper_->DeviceNameGetHint(*hint_iter, kNameHintName));
// Find out if the device is available.
- if (IsAlsaDeviceAvailable(unique_device_name.get())) {
+ if (IsAlsaDeviceAvailable(type, unique_device_name.get())) {
// Get the description for the device.
scoped_ptr_malloc<char> desc(wrapper_->DeviceNameGetHint(
*hint_iter, kDescriptionHintName));
@@ -196,25 +206,46 @@ void AudioManagerLinux::GetAlsaDevicesInfo(
}
}
-bool AudioManagerLinux::IsAlsaDeviceAvailable(const char* device_name) {
+// static
+bool AudioManagerLinux::IsAlsaDeviceAvailable(
+ AudioManagerLinux::StreamType type,
+ const char* device_name) {
if (!device_name)
return false;
- // Check if the device is in the list of invalid devices.
- for (size_t i = 0; i < arraysize(kInvalidAudioInputDevices); ++i) {
- if (strncmp(kInvalidAudioInputDevices[i], device_name,
- strlen(kInvalidAudioInputDevices[i])) == 0)
- return false;
+ // We do prefix matches on the device name to see whether to include
+ // it or not.
+ if (type == kStreamCapture) {
+ // Check if the device is in the list of invalid devices.
+ for (size_t i = 0; i < arraysize(kInvalidAudioInputDevices); ++i) {
+ if (strncmp(kInvalidAudioInputDevices[i], device_name,
+ strlen(kInvalidAudioInputDevices[i])) == 0)
+ return false;
+ }
+ return true;
+ } else {
+ DCHECK_EQ(kStreamPlayback, type);
+ // We prefer the device type that maps straight to hardware but
+ // goes through software conversion if needed (e.g. incompatible
+ // sample rate).
+ // TODO(joi): Should we prefer "hw" instead?
+ static const char kDeviceTypeDesired[] = "plughw";
+ return strncmp(kDeviceTypeDesired,
+ device_name,
+ arraysize(kDeviceTypeDesired) - 1) == 0;
}
+}
- return true;
+// static
+const char* AudioManagerLinux::UnwantedDeviceTypeWhenEnumerating(
+ AudioManagerLinux::StreamType wanted_type) {
+ return wanted_type == kStreamPlayback ? "Input" : "Output";
}
-bool AudioManagerLinux::HasAnyAlsaAudioDevice(StreamType stream) {
+bool AudioManagerLinux::HasAnyAlsaAudioDevice(
+ AudioManagerLinux::StreamType stream) {
static const char kPcmInterfaceName[] = "pcm";
static const char kIoHintName[] = "IOID";
- const char* kNotWantedDevice =
- (stream == kStreamPlayback ? "Input" : "Output");
void** hints = NULL;
bool has_device = false;
int card = -1;
@@ -230,7 +261,8 @@ bool AudioManagerLinux::HasAnyAlsaAudioDevice(StreamType stream) {
// "Input", "Output", and NULL which means both input and output.
scoped_ptr_malloc<char> io(wrapper_->DeviceNameGetHint(*hint_iter,
kIoHintName));
- if (io != NULL && strcmp(kNotWantedDevice, io.get()) == 0)
+ const char* unwanted_type = UnwantedDeviceTypeWhenEnumerating(stream);
+ if (io != NULL && strcmp(unwanted_type, io.get()) == 0)
continue; // Wrong type, skip the device.
// Found an input device.
@@ -258,7 +290,9 @@ AudioOutputStream* AudioManagerLinux::MakeLinearOutputStream(
AudioOutputStream* AudioManagerLinux::MakeLowLatencyOutputStream(
const AudioParameters& params,
+ const std::string& device_id,
const std::string& input_device_id) {
+ DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
// TODO(xians): Use input_device_id for unified IO.
return MakeOutputStream(params);
@@ -277,7 +311,10 @@ AudioInputStream* AudioManagerLinux::MakeLowLatencyInputStream(
}
AudioParameters AudioManagerLinux::GetPreferredOutputStreamParameters(
+ const std::string& output_device_id,
const AudioParameters& input_params) {
+ // TODO(tommi): Support |output_device_id|.
+ DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!";
static const int kDefaultOutputBufferSize = 2048;
ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
int sample_rate = kDefaultSampleRate;
diff --git a/media/audio/linux/audio_manager_linux.h b/media/audio/linux/audio_manager_linux.h
index 28abaa116e..2258e81eb9 100644
--- a/media/audio/linux/audio_manager_linux.h
+++ b/media/audio/linux/audio_manager_linux.h
@@ -27,6 +27,8 @@ class MEDIA_EXPORT AudioManagerLinux : public AudioManagerBase {
virtual void ShowAudioInputSettings() OVERRIDE;
virtual void GetAudioInputDeviceNames(media::AudioDeviceNames* device_names)
OVERRIDE;
+ virtual void GetAudioOutputDeviceNames(media::AudioDeviceNames* device_names)
+ OVERRIDE;
virtual AudioParameters GetInputStreamParameters(
const std::string& device_id) OVERRIDE;
@@ -35,6 +37,7 @@ class MEDIA_EXPORT AudioManagerLinux : public AudioManagerBase {
const AudioParameters& params) OVERRIDE;
virtual AudioOutputStream* MakeLowLatencyOutputStream(
const AudioParameters& params,
+ const std::string& device_id,
const std::string& input_device_id) OVERRIDE;
virtual AudioInputStream* MakeLinearInputStream(
const AudioParameters& params, const std::string& device_id) OVERRIDE;
@@ -45,6 +48,7 @@ class MEDIA_EXPORT AudioManagerLinux : public AudioManagerBase {
virtual ~AudioManagerLinux();
virtual AudioParameters GetPreferredOutputStreamParameters(
+ const std::string& output_device_id,
const AudioParameters& input_params) OVERRIDE;
private:
@@ -53,14 +57,22 @@ class MEDIA_EXPORT AudioManagerLinux : public AudioManagerBase {
kStreamCapture,
};
- // Gets a list of available ALSA input devices.
- void GetAlsaAudioInputDevices(media::AudioDeviceNames* device_names);
+ // Gets a list of available ALSA devices.
+ void GetAlsaAudioDevices(StreamType type,
+ media::AudioDeviceNames* device_names);
- // Gets the ALSA devices' names and ids.
- void GetAlsaDevicesInfo(void** hint, media::AudioDeviceNames* device_names);
+ // Gets the ALSA devices' names and ids that support streams of the
+ // given type.
+ void GetAlsaDevicesInfo(StreamType type,
+ void** hint,
+ media::AudioDeviceNames* device_names);
// Checks if the specific ALSA device is available.
- bool IsAlsaDeviceAvailable(const char* device_name);
+ static bool IsAlsaDeviceAvailable(StreamType type,
+ const char* device_name);
+
+ static const char* UnwantedDeviceTypeWhenEnumerating(
+ StreamType wanted_type);
// Returns true if a device is present for the given stream type.
bool HasAnyAlsaAudioDevice(StreamType stream);
diff --git a/media/audio/mac/audio_auhal_mac_unittest.cc b/media/audio/mac/audio_auhal_mac_unittest.cc
index b4cf8c64cc..9b699ff10f 100644
--- a/media/audio/mac/audio_auhal_mac_unittest.cc
+++ b/media/audio/mac/audio_auhal_mac_unittest.cc
@@ -101,7 +101,7 @@ class AudioOutputStreamWrapper {
samples_per_packet_);
AudioOutputStream* aos = audio_man_->MakeAudioOutputStream(params,
- std::string());
+ std::string(), std::string());
EXPECT_TRUE(aos);
return aos;
}
diff --git a/media/audio/mac/audio_input_mac.cc b/media/audio/mac/audio_input_mac.cc
index 06af6d11c1..7930567fd9 100644
--- a/media/audio/mac/audio_input_mac.cc
+++ b/media/audio/mac/audio_input_mac.cc
@@ -4,15 +4,14 @@
#include "media/audio/mac/audio_input_mac.h"
+#include <CoreServices/CoreServices.h>
+
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/mac/mac_logging.h"
#include "media/audio/audio_manager_base.h"
#include "media/audio/audio_util.h"
-#if !defined(OS_IOS)
-#include <CoreServices/CoreServices.h>
-#endif
namespace media {
diff --git a/media/audio/mac/audio_low_latency_input_mac.cc b/media/audio/mac/audio_low_latency_input_mac.cc
index 17a87b0a7d..d97f453ca9 100644
--- a/media/audio/mac/audio_low_latency_input_mac.cc
+++ b/media/audio/mac/audio_low_latency_input_mac.cc
@@ -35,7 +35,9 @@ static std::ostream& operator<<(std::ostream& os,
// for more details and background regarding this implementation.
AUAudioInputStream::AUAudioInputStream(
- AudioManagerMac* manager, const AudioParameters& params,
+ AudioManagerMac* manager,
+ const AudioParameters& input_params,
+ const AudioParameters& output_params,
AudioDeviceID audio_device_id)
: manager_(manager),
sink_(NULL),
@@ -48,15 +50,15 @@ AUAudioInputStream::AUAudioInputStream(
DCHECK(manager_);
// Set up the desired (output) format specified by the client.
- format_.mSampleRate = params.sample_rate();
+ format_.mSampleRate = input_params.sample_rate();
format_.mFormatID = kAudioFormatLinearPCM;
format_.mFormatFlags = kLinearPCMFormatFlagIsPacked |
kLinearPCMFormatFlagIsSignedInteger;
- format_.mBitsPerChannel = params.bits_per_sample();
- format_.mChannelsPerFrame = params.channels();
+ format_.mBitsPerChannel = input_params.bits_per_sample();
+ format_.mChannelsPerFrame = input_params.channels();
format_.mFramesPerPacket = 1; // uncompressed audio
format_.mBytesPerPacket = (format_.mBitsPerChannel *
- params.channels()) / 8;
+ input_params.channels()) / 8;
format_.mBytesPerFrame = format_.mBytesPerPacket;
format_.mReserved = 0;
@@ -68,10 +70,7 @@ AUAudioInputStream::AUAudioInputStream(
// Note that we use the same native buffer size as for the output side here
// since the AUHAL implementation requires that both capture and render side
// use the same buffer size. See http://crbug.com/154352 for more details.
- // TODO(xians): Get the audio parameters from the right device.
- const AudioParameters parameters =
- manager_->GetInputStreamParameters(AudioManagerBase::kDefaultDeviceId);
- number_of_frames_ = parameters.frames_per_buffer();
+ number_of_frames_ = output_params.frames_per_buffer();
DVLOG(1) << "Size of data buffer in frames : " << number_of_frames_;
// Derive size (in bytes) of the buffers that we will render to.
@@ -85,7 +84,7 @@ AUAudioInputStream::AUAudioInputStream(
audio_buffer_list_.mNumberBuffers = 1;
AudioBuffer* audio_buffer = audio_buffer_list_.mBuffers;
- audio_buffer->mNumberChannels = params.channels();
+ audio_buffer->mNumberChannels = input_params.channels();
audio_buffer->mDataByteSize = data_byte_size;
audio_buffer->mData = audio_data_buffer_.get();
@@ -93,9 +92,16 @@ AUAudioInputStream::AUAudioInputStream(
// until a requested size is ready to be sent to the client.
// It is not possible to ask for less than |kAudioFramesPerCallback| number of
// audio frames.
- const size_t requested_size_frames =
- params.GetBytesPerBuffer() / format_.mBytesPerPacket;
- DCHECK_GE(requested_size_frames, number_of_frames_);
+ size_t requested_size_frames =
+ input_params.GetBytesPerBuffer() / format_.mBytesPerPacket;
+ if (requested_size_frames < number_of_frames_) {
+ // For devices that only support a low sample rate like 8kHz, we adjust the
+ // buffer size to match number_of_frames_. The value of number_of_frames_
+ // in this case has not been calculated based on hardware settings but
+ // rather our hardcoded defaults (see ChooseBufferSize).
+ requested_size_frames = number_of_frames_;
+ }
+
requested_size_bytes_ = requested_size_frames * format_.mBytesPerFrame;
DVLOG(1) << "Requested buffer size in bytes : " << requested_size_bytes_;
DLOG_IF(INFO, requested_size_frames > number_of_frames_) << "FIFO is used";
diff --git a/media/audio/mac/audio_low_latency_input_mac.h b/media/audio/mac/audio_low_latency_input_mac.h
index 736bf082f5..04592d2cec 100644
--- a/media/audio/mac/audio_low_latency_input_mac.h
+++ b/media/audio/mac/audio_low_latency_input_mac.h
@@ -57,7 +57,8 @@ class AUAudioInputStream : public AgcAudioStream<AudioInputStream> {
// The ctor takes all the usual parameters, plus |manager| which is the
// the audio manager who is creating this object.
AUAudioInputStream(AudioManagerMac* manager,
- const AudioParameters& params,
+ const AudioParameters& input_params,
+ const AudioParameters& output_params,
AudioDeviceID audio_device_id);
// The dtor is typically called by the AudioManager only and it is usually
// triggered by calling AudioInputStream::Close().
diff --git a/media/audio/mac/audio_manager_mac.cc b/media/audio/mac/audio_manager_mac.cc
index c0c18ee2cc..8e4b969854 100644
--- a/media/audio/mac/audio_manager_mac.cc
+++ b/media/audio/mac/audio_manager_mac.cc
@@ -81,11 +81,10 @@ bool AudioManagerMac::HasUnifiedDefaultIO() {
return input_id == output_id;
}
+// Retrieves information on audio devices, and prepends the default
+// device to the list if the list is non-empty.
static void GetAudioDeviceInfo(bool is_input,
media::AudioDeviceNames* device_names) {
- DCHECK(device_names);
- device_names->clear();
-
// Query the number of total devices.
AudioObjectPropertyAddress property_address = {
kAudioHardwarePropertyDevices,
@@ -176,6 +175,16 @@ static void GetAudioDeviceInfo(bool is_input,
if (name)
CFRelease(name);
}
+
+ if (!device_names->empty()) {
+ // Prepend the default device to the list since we always want it to be
+ // on the top of the list for all platforms. There is no duplicate
+ // counting here since the default device has been abstracted out before.
+ media::AudioDeviceName name;
+ name.device_name = AudioManagerBase::kDefaultDeviceName;
+ name.unique_id = AudioManagerBase::kDefaultDeviceId;
+ device_names->push_front(name);
+ }
}
static AudioDeviceID GetAudioDeviceIdByUId(bool is_input,
@@ -189,7 +198,7 @@ static AudioDeviceID GetAudioDeviceIdByUId(bool is_input,
UInt32 device_size = sizeof(audio_device_id);
OSStatus result = -1;
- if (device_id == AudioManagerBase::kDefaultDeviceId) {
+ if (device_id == AudioManagerBase::kDefaultDeviceId || device_id.empty()) {
// Default Device.
property_address.mSelector = is_input ?
kAudioHardwarePropertyDefaultInputDevice :
@@ -263,7 +272,7 @@ bool AudioManagerMac::HasAudioInputDevices() {
return HasAudioHardware(kAudioHardwarePropertyDefaultInputDevice);
}
-// TODO(crogers): There are several places on the OSX specific code which
+// TODO(xians): There are several places on the OSX specific code which
// could benefit from these helper functions.
bool AudioManagerMac::GetDefaultInputDevice(
AudioDeviceID* device) {
@@ -397,16 +406,14 @@ int AudioManagerMac::HardwareSampleRate() {
void AudioManagerMac::GetAudioInputDeviceNames(
media::AudioDeviceNames* device_names) {
+ DCHECK(device_names->empty());
GetAudioDeviceInfo(true, device_names);
- if (!device_names->empty()) {
- // Prepend the default device to the list since we always want it to be
- // on the top of the list for all platforms. There is no duplicate
- // counting here since the default device has been abstracted out before.
- media::AudioDeviceName name;
- name.device_name = AudioManagerBase::kDefaultDeviceName;
- name.unique_id = AudioManagerBase::kDefaultDeviceId;
- device_names->push_front(name);
- }
+}
+
+void AudioManagerMac::GetAudioOutputDeviceNames(
+ media::AudioDeviceNames* device_names) {
+ DCHECK(device_names->empty());
+ GetAudioDeviceInfo(false, device_names);
}
AudioParameters AudioManagerMac::GetInputStreamParameters(
@@ -443,21 +450,86 @@ AudioParameters AudioManagerMac::GetInputStreamParameters(
sample_rate, 16, buffer_size);
}
+std::string AudioManagerMac::GetAssociatedOutputDeviceID(
+ const std::string& input_device_id) {
+ AudioDeviceID device = GetAudioDeviceIdByUId(true, input_device_id);
+ if (device == kAudioObjectUnknown)
+ return std::string();
+
+ UInt32 size = 0;
+ AudioObjectPropertyAddress pa = {
+ kAudioDevicePropertyRelatedDevices,
+ kAudioDevicePropertyScopeOutput,
+ kAudioObjectPropertyElementMaster
+ };
+ OSStatus result = AudioObjectGetPropertyDataSize(device, &pa, 0, 0, &size);
+ if (result || !size)
+ return std::string();
+
+ int device_count = size / sizeof(AudioDeviceID);
+ scoped_ptr_malloc<AudioDeviceID>
+ devices(reinterpret_cast<AudioDeviceID*>(malloc(size)));
+ result = AudioObjectGetPropertyData(
+ device, &pa, 0, NULL, &size, devices.get());
+ if (result)
+ return std::string();
+
+ for (int i = 0; i < device_count; ++i) {
+ // Get the number of output channels of the device.
+ pa.mSelector = kAudioDevicePropertyStreams;
+ size = 0;
+ result = AudioObjectGetPropertyDataSize(devices.get()[i],
+ &pa,
+ 0,
+ NULL,
+ &size);
+ if (result || !size)
+ continue; // Skip if there aren't any output channels.
+
+ // Get device UID.
+ CFStringRef uid = NULL;
+ size = sizeof(uid);
+ pa.mSelector = kAudioDevicePropertyDeviceUID;
+ result = AudioObjectGetPropertyData(devices.get()[i],
+ &pa,
+ 0,
+ NULL,
+ &size,
+ &uid);
+ if (result || !uid)
+ continue;
+
+ std::string ret(base::SysCFStringRefToUTF8(uid));
+ CFRelease(uid);
+ return ret;
+ }
+
+ // No matching device found.
+ return std::string();
+}
+
AudioOutputStream* AudioManagerMac::MakeLinearOutputStream(
const AudioParameters& params) {
- return MakeLowLatencyOutputStream(params, std::string());
+ return MakeLowLatencyOutputStream(params, std::string(), std::string());
}
AudioOutputStream* AudioManagerMac::MakeLowLatencyOutputStream(
- const AudioParameters& params, const std::string& input_device_id) {
+ const AudioParameters& params,
+ const std::string& device_id,
+ const std::string& input_device_id) {
// Handle basic output with no input channels.
if (params.input_channels() == 0) {
- AudioDeviceID device = kAudioObjectUnknown;
- GetDefaultOutputDevice(&device);
+ AudioDeviceID device = GetAudioDeviceIdByUId(false, device_id);
+ if (device == kAudioObjectUnknown) {
+ DLOG(ERROR) << "Failed to open output device: " << device_id;
+ return NULL;
+ }
return new AUHALStream(this, params, device);
}
- // TODO(crogers): support more than stereo input.
+ DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
+
+ // TODO(xians): support more than stereo input.
if (params.input_channels() != 2) {
// WebAudio is currently hard-coded to 2 channels so we should not
// see this case.
@@ -494,7 +566,7 @@ AudioOutputStream* AudioManagerMac::MakeLowLatencyOutputStream(
// different and arbitrary combinations of input and output devices
// even running at different sample-rates.
// kAudioDeviceUnknown translates to "use default" here.
- // TODO(crogers): consider tracking UMA stats on AUHALStream
+ // TODO(xians): consider tracking UMA stats on AUHALStream
// versus AudioSynchronizedStream.
AudioDeviceID audio_device_id = GetAudioDeviceIdByUId(true, input_device_id);
if (audio_device_id == kAudioObjectUnknown)
@@ -506,6 +578,33 @@ AudioOutputStream* AudioManagerMac::MakeLowLatencyOutputStream(
kAudioDeviceUnknown);
}
+std::string AudioManagerMac::GetDefaultOutputDeviceID() {
+ AudioDeviceID device_id = kAudioObjectUnknown;
+ if (!GetDefaultOutputDevice(&device_id))
+ return std::string();
+
+ const AudioObjectPropertyAddress property_address = {
+ kAudioDevicePropertyDeviceUID,
+ kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMaster
+ };
+ CFStringRef device_uid = NULL;
+ UInt32 size = sizeof(device_uid);
+ OSStatus status = AudioObjectGetPropertyData(device_id,
+ &property_address,
+ 0,
+ NULL,
+ &size,
+ &device_uid);
+ if (status != kAudioHardwareNoError || !device_uid)
+ return std::string();
+
+ std::string ret(base::SysCFStringRefToUTF8(device_uid));
+ CFRelease(device_uid);
+
+ return ret;
+}
+
AudioInputStream* AudioManagerMac::MakeLinearInputStream(
const AudioParameters& params, const std::string& device_id) {
DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
@@ -515,27 +614,47 @@ AudioInputStream* AudioManagerMac::MakeLinearInputStream(
AudioInputStream* AudioManagerMac::MakeLowLatencyInputStream(
const AudioParameters& params, const std::string& device_id) {
DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
- // Gets the AudioDeviceID that refers to the AudioOutputDevice with the device
+ // Gets the AudioDeviceID that refers to the AudioInputDevice with the device
// unique id. This AudioDeviceID is used to set the device for Audio Unit.
AudioDeviceID audio_device_id = GetAudioDeviceIdByUId(true, device_id);
AudioInputStream* stream = NULL;
- if (audio_device_id != kAudioObjectUnknown)
- stream = new AUAudioInputStream(this, params, audio_device_id);
+ if (audio_device_id != kAudioObjectUnknown) {
+ // AUAudioInputStream needs to be fed the preferred audio output parameters
+ // of the matching device so that the buffer size of both input and output
+ // can be matched. See constructor of AUAudioInputStream for more.
+ const std::string associated_output_device(
+ GetAssociatedOutputDeviceID(device_id));
+ const AudioParameters output_params =
+ GetPreferredOutputStreamParameters(
+ associated_output_device.empty() ?
+ AudioManagerBase::kDefaultDeviceId : associated_output_device,
+ params);
+ stream = new AUAudioInputStream(this, params, output_params,
+ audio_device_id);
+ }
return stream;
}
AudioParameters AudioManagerMac::GetPreferredOutputStreamParameters(
+ const std::string& output_device_id,
const AudioParameters& input_params) {
+ AudioDeviceID device = GetAudioDeviceIdByUId(false, output_device_id);
+ if (device == kAudioObjectUnknown) {
+ DLOG(ERROR) << "Invalid output device " << output_device_id;
+ return AudioParameters();
+ }
+
int hardware_channels = 2;
- if (!GetDefaultOutputChannels(&hardware_channels)) {
+ if (!GetDeviceChannels(device, kAudioDevicePropertyScopeOutput,
+ &hardware_channels)) {
// Fallback to stereo.
hardware_channels = 2;
}
ChannelLayout channel_layout = GuessChannelLayout(hardware_channels);
- const int hardware_sample_rate = AUAudioOutputStream::HardwareSampleRate();
+ const int hardware_sample_rate = HardwareSampleRateForDevice(device);
const int buffer_size = ChooseBufferSize(hardware_sample_rate);
int input_channels = 0;
@@ -543,7 +662,7 @@ AudioParameters AudioManagerMac::GetPreferredOutputStreamParameters(
input_channels = input_params.input_channels();
if (input_channels > 0) {
- // TODO(crogers): given the limitations of the AudioOutputStream
+ // TODO(xians): given the limitations of the AudioOutputStream
// back-ends used with synchronized I/O, we hard-code to stereo.
// Specifically, this is a limitation of AudioSynchronizedStream which
// can be removed as part of the work to consolidate these back-ends.
diff --git a/media/audio/mac/audio_manager_mac.h b/media/audio/mac/audio_manager_mac.h
index cd3cc2e94b..9757315920 100644
--- a/media/audio/mac/audio_manager_mac.h
+++ b/media/audio/mac/audio_manager_mac.h
@@ -29,19 +29,25 @@ class MEDIA_EXPORT AudioManagerMac : public AudioManagerBase {
virtual bool HasAudioInputDevices() OVERRIDE;
virtual void GetAudioInputDeviceNames(media::AudioDeviceNames* device_names)
OVERRIDE;
+ virtual void GetAudioOutputDeviceNames(media::AudioDeviceNames* device_names)
+ OVERRIDE;
virtual AudioParameters GetInputStreamParameters(
const std::string& device_id) OVERRIDE;
+ virtual std::string GetAssociatedOutputDeviceID(
+ const std::string& input_device_id) OVERRIDE;
// Implementation of AudioManagerBase.
virtual AudioOutputStream* MakeLinearOutputStream(
const AudioParameters& params) OVERRIDE;
virtual AudioOutputStream* MakeLowLatencyOutputStream(
const AudioParameters& params,
+ const std::string& device_id,
const std::string& input_device_id) OVERRIDE;
virtual AudioInputStream* MakeLinearInputStream(
const AudioParameters& params, const std::string& device_id) OVERRIDE;
virtual AudioInputStream* MakeLowLatencyInputStream(
const AudioParameters& params, const std::string& device_id) OVERRIDE;
+ virtual std::string GetDefaultOutputDeviceID() OVERRIDE;
static bool GetDefaultInputDevice(AudioDeviceID* device);
static bool GetDefaultOutputDevice(AudioDeviceID* device);
@@ -64,6 +70,7 @@ class MEDIA_EXPORT AudioManagerMac : public AudioManagerBase {
virtual ~AudioManagerMac();
virtual AudioParameters GetPreferredOutputStreamParameters(
+ const std::string& output_device_id,
const AudioParameters& input_params) OVERRIDE;
private:
diff --git a/media/audio/mock_audio_manager.cc b/media/audio/mock_audio_manager.cc
index 60898bd61b..2ab2b708da 100644
--- a/media/audio/mock_audio_manager.cc
+++ b/media/audio/mock_audio_manager.cc
@@ -36,15 +36,21 @@ void MockAudioManager::GetAudioInputDeviceNames(
media::AudioDeviceNames* device_names) {
}
+void MockAudioManager::GetAudioOutputDeviceNames(
+ media::AudioDeviceNames* device_names) {
+}
+
media::AudioOutputStream* MockAudioManager::MakeAudioOutputStream(
- const media::AudioParameters& params,
- const std::string& input_device_id) {
+ const media::AudioParameters& params,
+ const std::string& device_id,
+ const std::string& input_device_id) {
NOTREACHED();
return NULL;
}
media::AudioOutputStream* MockAudioManager::MakeAudioOutputStreamProxy(
const media::AudioParameters& params,
+ const std::string& device_id,
const std::string& input_device_id) {
NOTREACHED();
return NULL;
@@ -77,9 +83,19 @@ AudioParameters MockAudioManager::GetDefaultOutputStreamParameters() {
return AudioParameters();
}
+AudioParameters MockAudioManager::GetOutputStreamParameters(
+ const std::string& device_id) {
+ return AudioParameters();
+}
+
AudioParameters MockAudioManager::GetInputStreamParameters(
const std::string& device_id) {
return AudioParameters();
}
+std::string MockAudioManager::GetAssociatedOutputDeviceID(
+ const std::string& input_device_id) {
+ return std::string();
+}
+
} // namespace media.
diff --git a/media/audio/mock_audio_manager.h b/media/audio/mock_audio_manager.h
index eee84b1643..7bc30f578e 100644
--- a/media/audio/mock_audio_manager.h
+++ b/media/audio/mock_audio_manager.h
@@ -34,12 +34,17 @@ class MockAudioManager : public media::AudioManager {
virtual void GetAudioInputDeviceNames(
media::AudioDeviceNames* device_names) OVERRIDE;
+ virtual void GetAudioOutputDeviceNames(
+ media::AudioDeviceNames* device_names) OVERRIDE;
+
virtual media::AudioOutputStream* MakeAudioOutputStream(
const media::AudioParameters& params,
+ const std::string& device_id,
const std::string& input_device_id) OVERRIDE;
virtual media::AudioOutputStream* MakeAudioOutputStreamProxy(
const media::AudioParameters& params,
+ const std::string& device_id,
const std::string& input_device_id) OVERRIDE;
virtual media::AudioInputStream* MakeAudioInputStream(
@@ -55,8 +60,12 @@ class MockAudioManager : public media::AudioManager {
AudioDeviceListener* listener) OVERRIDE;
virtual AudioParameters GetDefaultOutputStreamParameters() OVERRIDE;
+ virtual AudioParameters GetOutputStreamParameters(
+ const std::string& device_id) OVERRIDE;
virtual AudioParameters GetInputStreamParameters(
const std::string& device_id) OVERRIDE;
+ virtual std::string GetAssociatedOutputDeviceID(
+ const std::string& input_device_id) OVERRIDE;
private:
virtual ~MockAudioManager();
diff --git a/media/audio/openbsd/audio_manager_openbsd.cc b/media/audio/openbsd/audio_manager_openbsd.cc
index 4005aeb98f..a97ea8f625 100644
--- a/media/audio/openbsd/audio_manager_openbsd.cc
+++ b/media/audio/openbsd/audio_manager_openbsd.cc
@@ -92,7 +92,9 @@ AudioOutputStream* AudioManagerOpenBSD::MakeLinearOutputStream(
AudioOutputStream* AudioManagerOpenBSD::MakeLowLatencyOutputStream(
const AudioParameters& params,
+ const std::string& device_id,
const std::string& input_device_id) {
+ DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format);
return MakeOutputStream(params);
}
@@ -112,7 +114,10 @@ AudioInputStream* AudioManagerOpenBSD::MakeLowLatencyInputStream(
}
AudioParameters AudioManagerOpenBSD::GetPreferredOutputStreamParameters(
+ const std::string& output_device_id,
const AudioParameters& input_params) {
+ // TODO(tommi): Support |output_device_id|.
+ DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!";
static const int kDefaultOutputBufferSize = 512;
ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
diff --git a/media/audio/openbsd/audio_manager_openbsd.h b/media/audio/openbsd/audio_manager_openbsd.h
index a1adcb6c86..e4bb3948d2 100644
--- a/media/audio/openbsd/audio_manager_openbsd.h
+++ b/media/audio/openbsd/audio_manager_openbsd.h
@@ -27,6 +27,7 @@ class MEDIA_EXPORT AudioManagerOpenBSD : public AudioManagerBase {
const AudioParameters& params) OVERRIDE;
virtual AudioOutputStream* MakeLowLatencyOutputStream(
const AudioParameters& params,
+ const std::string& device_id,
const std::string& input_device_id) OVERRIDE;
virtual AudioInputStream* MakeLinearInputStream(
const AudioParameters& params, const std::string& device_id) OVERRIDE;
@@ -37,6 +38,7 @@ class MEDIA_EXPORT AudioManagerOpenBSD : public AudioManagerBase {
virtual ~AudioManagerOpenBSD();
virtual AudioParameters GetPreferredOutputStreamParameters(
+ const std::string& output_device_id,
const AudioParameters& input_params) OVERRIDE;
private:
diff --git a/media/audio/pulse/audio_manager_pulse.cc b/media/audio/pulse/audio_manager_pulse.cc
index dcdd328222..5c09f14905 100644
--- a/media/audio/pulse/audio_manager_pulse.cc
+++ b/media/audio/pulse/audio_manager_pulse.cc
@@ -66,19 +66,13 @@ AudioManagerPulse::~AudioManagerPulse() {
// Implementation of AudioManager.
bool AudioManagerPulse::HasAudioOutputDevices() {
- DCHECK(input_mainloop_);
- DCHECK(input_context_);
- media::AudioDeviceNames devices;
- AutoPulseLock auto_lock(input_mainloop_);
- devices_ = &devices;
- pa_operation* operation = pa_context_get_sink_info_list(
- input_context_, OutputDevicesInfoCallback, this);
- WaitForOperationCompletion(input_mainloop_, operation);
+ AudioDeviceNames devices;
+ GetAudioOutputDeviceNames(&devices);
return !devices.empty();
}
bool AudioManagerPulse::HasAudioInputDevices() {
- media::AudioDeviceNames devices;
+ AudioDeviceNames devices;
GetAudioInputDeviceNames(&devices);
return !devices.empty();
}
@@ -87,18 +81,24 @@ void AudioManagerPulse::ShowAudioInputSettings() {
AudioManagerLinux::ShowLinuxAudioInputSettings();
}
-void AudioManagerPulse::GetAudioInputDeviceNames(
- media::AudioDeviceNames* device_names) {
+void AudioManagerPulse::GetAudioDeviceNames(
+ bool input, media::AudioDeviceNames* device_names) {
DCHECK(device_names->empty());
DCHECK(input_mainloop_);
DCHECK(input_context_);
AutoPulseLock auto_lock(input_mainloop_);
devices_ = device_names;
- pa_operation* operation = pa_context_get_source_info_list(
+ pa_operation* operation = NULL;
+ if (input) {
+ operation = pa_context_get_source_info_list(
input_context_, InputDevicesInfoCallback, this);
+ } else {
+ operation = pa_context_get_sink_info_list(
+ input_context_, OutputDevicesInfoCallback, this);
+ }
WaitForOperationCompletion(input_mainloop_, operation);
- // Append the default device on the top of the list if the list is not empty.
+ // Prepend the default device if the list is not empty.
if (!device_names->empty()) {
device_names->push_front(
AudioDeviceName(AudioManagerBase::kDefaultDeviceName,
@@ -106,6 +106,16 @@ void AudioManagerPulse::GetAudioInputDeviceNames(
}
}
+void AudioManagerPulse::GetAudioInputDeviceNames(
+ AudioDeviceNames* device_names) {
+ GetAudioDeviceNames(true, device_names);
+}
+
+void AudioManagerPulse::GetAudioOutputDeviceNames(
+ AudioDeviceNames* device_names) {
+ GetAudioDeviceNames(false, device_names);
+}
+
AudioParameters AudioManagerPulse::GetInputStreamParameters(
const std::string& device_id) {
static const int kDefaultInputBufferSize = 1024;
@@ -123,7 +133,10 @@ AudioOutputStream* AudioManagerPulse::MakeLinearOutputStream(
}
AudioOutputStream* AudioManagerPulse::MakeLowLatencyOutputStream(
- const AudioParameters& params, const std::string& input_device_id) {
+ const AudioParameters& params,
+ const std::string& device_id,
+ const std::string& input_device_id) {
+ DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!";
DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
return MakeOutputStream(params, input_device_id);
}
@@ -141,7 +154,10 @@ AudioInputStream* AudioManagerPulse::MakeLowLatencyInputStream(
}
AudioParameters AudioManagerPulse::GetPreferredOutputStreamParameters(
+ const std::string& output_device_id,
const AudioParameters& input_params) {
+ // TODO(tommi): Support |output_device_id|.
+ DLOG_IF(ERROR, !output_device_id.empty()) << "Not implemented!";
static const int kDefaultOutputBufferSize = 512;
ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
@@ -286,8 +302,8 @@ void AudioManagerPulse::InputDevicesInfoCallback(pa_context* context,
// Exclude the output devices.
if (info->monitor_of_sink == PA_INVALID_INDEX) {
- manager->devices_->push_back(media::AudioDeviceName(info->description,
- info->name));
+ manager->devices_->push_back(AudioDeviceName(info->description,
+ info->name));
}
}
@@ -302,8 +318,8 @@ void AudioManagerPulse::OutputDevicesInfoCallback(pa_context* context,
return;
}
- manager->devices_->push_back(media::AudioDeviceName(info->description,
- info->name));
+ manager->devices_->push_back(AudioDeviceName(info->description,
+ info->name));
}
void AudioManagerPulse::SampleRateInfoCallback(pa_context* context,
diff --git a/media/audio/pulse/audio_manager_pulse.h b/media/audio/pulse/audio_manager_pulse.h
index 6dfebaeff3..8fc4310cba 100644
--- a/media/audio/pulse/audio_manager_pulse.h
+++ b/media/audio/pulse/audio_manager_pulse.h
@@ -27,6 +27,8 @@ class MEDIA_EXPORT AudioManagerPulse : public AudioManagerBase {
virtual void ShowAudioInputSettings() OVERRIDE;
virtual void GetAudioInputDeviceNames(media::AudioDeviceNames* device_names)
OVERRIDE;
+ virtual void GetAudioOutputDeviceNames(media::AudioDeviceNames* device_names)
+ OVERRIDE;
virtual AudioParameters GetInputStreamParameters(
const std::string& device_id) OVERRIDE;
@@ -35,6 +37,7 @@ class MEDIA_EXPORT AudioManagerPulse : public AudioManagerBase {
const AudioParameters& params) OVERRIDE;
virtual AudioOutputStream* MakeLowLatencyOutputStream(
const AudioParameters& params,
+ const std::string& device_id,
const std::string& input_device_id) OVERRIDE;
virtual AudioInputStream* MakeLinearInputStream(
const AudioParameters& params, const std::string& device_id) OVERRIDE;
@@ -43,12 +46,15 @@ class MEDIA_EXPORT AudioManagerPulse : public AudioManagerBase {
protected:
virtual AudioParameters GetPreferredOutputStreamParameters(
+ const std::string& output_device_id,
const AudioParameters& input_params) OVERRIDE;
private:
bool Init();
void DestroyPulse();
+ void GetAudioDeviceNames(bool input, media::AudioDeviceNames* device_names);
+
// Callback to get the devices' info like names, used by GetInputDevices().
static void InputDevicesInfoCallback(pa_context* context,
const pa_source_info* info,
diff --git a/media/audio/win/audio_low_latency_output_win.cc b/media/audio/win/audio_low_latency_output_win.cc
index b2098b0209..c889c03ef2 100644
--- a/media/audio/win/audio_low_latency_output_win.cc
+++ b/media/audio/win/audio_low_latency_output_win.cc
@@ -111,14 +111,26 @@ ChannelLayout WASAPIAudioOutputStream::HardwareChannelLayout() {
}
// static
-int WASAPIAudioOutputStream::HardwareSampleRate() {
+int WASAPIAudioOutputStream::HardwareSampleRate(const std::string& device_id) {
WAVEFORMATPCMEX format;
- return SUCCEEDED(CoreAudioUtil::GetDefaultSharedModeMixFormat(
- eRender, eConsole, &format)) ?
- static_cast<int>(format.Format.nSamplesPerSec) : 0;
+ ScopedComPtr<IAudioClient> client;
+ if (device_id.empty()) {
+ client = CoreAudioUtil::CreateDefaultClient(eRender, eConsole);
+ } else {
+ ScopedComPtr<IMMDevice> device(CoreAudioUtil::CreateDevice(device_id));
+ if (!device)
+ return 0;
+ client = CoreAudioUtil::CreateClient(device);
+ }
+
+ if (!client || FAILED(CoreAudioUtil::GetSharedModeMixFormat(client, &format)))
+ return 0;
+
+ return static_cast<int>(format.Format.nSamplesPerSec);
}
WASAPIAudioOutputStream::WASAPIAudioOutputStream(AudioManagerWin* manager,
+ const std::string& device_id,
const AudioParameters& params,
ERole device_role)
: creating_thread_id_(base::PlatformThread::CurrentId()),
@@ -127,6 +139,7 @@ WASAPIAudioOutputStream::WASAPIAudioOutputStream(AudioManagerWin* manager,
audio_parameters_are_valid_(false),
volume_(1.0),
endpoint_buffer_size_frames_(0),
+ device_id_(device_id),
device_role_(device_role),
share_mode_(GetShareMode()),
num_written_frames_(0),
@@ -142,12 +155,16 @@ WASAPIAudioOutputStream::WASAPIAudioOutputStream(AudioManagerWin* manager,
// channel count are excluded) to the preferred (native) audio parameters.
// Open() will fail if this is not the case.
AudioParameters preferred_params;
- HRESULT hr = CoreAudioUtil::GetPreferredAudioParameters(
- eRender, device_role, &preferred_params);
+ HRESULT hr = device_id_.empty() ?
+ CoreAudioUtil::GetPreferredAudioParameters(eRender, device_role,
+ &preferred_params) :
+ CoreAudioUtil::GetPreferredAudioParameters(device_id_,
+ &preferred_params);
audio_parameters_are_valid_ = SUCCEEDED(hr) &&
CompareAudioParametersNoBitDepthOrChannels(params, preferred_params);
LOG_IF(WARNING, !audio_parameters_are_valid_)
- << "Input and preferred parameters are not identical.";
+ << "Input and preferred parameters are not identical. "
+ << "Device id: " << device_id_;
}
// Load the Avrt DLL if not already loaded. Required to support MMCSS.
@@ -203,7 +220,6 @@ bool WASAPIAudioOutputStream::Open() {
if (opened_)
return true;
-
// Audio parameters must be identical to the preferred set of parameters
// if shared mode (default) is utilized.
if (share_mode_ == AUDCLNT_SHAREMODE_SHARED) {
@@ -214,8 +230,16 @@ bool WASAPIAudioOutputStream::Open() {
}
// Create an IAudioClient interface for the default rendering IMMDevice.
- ScopedComPtr<IAudioClient> audio_client =
- CoreAudioUtil::CreateDefaultClient(eRender, device_role_);
+ ScopedComPtr<IAudioClient> audio_client;
+ if (device_id_.empty()) {
+ audio_client = CoreAudioUtil::CreateDefaultClient(eRender, device_role_);
+ } else {
+ ScopedComPtr<IMMDevice> device(CoreAudioUtil::CreateDevice(device_id_));
+ DLOG_IF(ERROR, !device) << "Failed to open device: " << device_id_;
+ if (device)
+ audio_client = CoreAudioUtil::CreateClient(device);
+ }
+
if (!audio_client)
return false;
diff --git a/media/audio/win/audio_low_latency_output_win.h b/media/audio/win/audio_low_latency_output_win.h
index b0e990bb1a..7884d8840f 100644
--- a/media/audio/win/audio_low_latency_output_win.h
+++ b/media/audio/win/audio_low_latency_output_win.h
@@ -122,6 +122,7 @@ class MEDIA_EXPORT WASAPIAudioOutputStream :
// The ctor takes all the usual parameters, plus |manager| which is the
// the audio manager who is creating this object.
WASAPIAudioOutputStream(AudioManagerWin* manager,
+ const std::string& device_id,
const AudioParameters& params,
ERole device_role);
@@ -149,8 +150,9 @@ class MEDIA_EXPORT WASAPIAudioOutputStream :
static ChannelLayout HardwareChannelLayout();
// Retrieves the sample rate the audio engine uses for its internal
- // processing/mixing of shared-mode streams for the default endpoint device.
- static int HardwareSampleRate();
+ // processing/mixing of shared-mode streams. To fetch the settings for the
+ // default device, pass an empty string as the |device_id|.
+ static int HardwareSampleRate(const std::string& device_id);
// Returns AUDCLNT_SHAREMODE_EXCLUSIVE if --enable-exclusive-mode is used
// as command-line flag and AUDCLNT_SHAREMODE_SHARED otherwise (default).
@@ -219,6 +221,9 @@ class MEDIA_EXPORT WASAPIAudioOutputStream :
// Length of the audio endpoint buffer.
uint32 endpoint_buffer_size_frames_;
+ // The target device id or an empty string for the default device.
+ const std::string device_id_;
+
// Defines the role that the system has assigned to an audio endpoint device.
ERole device_role_;
diff --git a/media/audio/win/audio_low_latency_output_win_unittest.cc b/media/audio/win/audio_low_latency_output_win_unittest.cc
index 8c3e366c0c..1f78facf91 100644
--- a/media/audio/win/audio_low_latency_output_win_unittest.cc
+++ b/media/audio/win/audio_low_latency_output_win_unittest.cc
@@ -234,7 +234,7 @@ class AudioOutputStreamWrapper {
AudioOutputStream* aos = audio_man_->MakeAudioOutputStream(
AudioParameters(format_, channel_layout_, sample_rate_,
bits_per_sample_, samples_per_packet_),
- std::string());
+ std::string(), std::string());
EXPECT_TRUE(aos);
return aos;
}
@@ -268,7 +268,7 @@ TEST(WASAPIAudioOutputStreamTest, HardwareSampleRate) {
// Default device intended for games, system notification sounds,
// and voice commands.
int fs = static_cast<int>(
- WASAPIAudioOutputStream::HardwareSampleRate());
+ WASAPIAudioOutputStream::HardwareSampleRate(std::string()));
EXPECT_GE(fs, 0);
}
diff --git a/media/audio/win/audio_manager_win.cc b/media/audio/win/audio_manager_win.cc
index a753e554cb..e3a95883b2 100644
--- a/media/audio/win/audio_manager_win.cc
+++ b/media/audio/win/audio_manager_win.cc
@@ -240,27 +240,44 @@ void AudioManagerWin::ShowAudioInputSettings() {
base::LaunchProcess(command_line, base::LaunchOptions(), NULL);
}
-void AudioManagerWin::GetAudioInputDeviceNames(
- media::AudioDeviceNames* device_names) {
+void AudioManagerWin::GetAudioDeviceNamesImpl(
+ bool input,
+ AudioDeviceNames* device_names) {
+ DCHECK(device_names->empty());
DCHECK(enumeration_type() != kUninitializedEnumeration);
// Enumerate all active audio-endpoint capture devices.
if (enumeration_type() == kWaveEnumeration) {
// Utilize the Wave API for Windows XP.
- media::GetInputDeviceNamesWinXP(device_names);
+ if (input)
+ GetInputDeviceNamesWinXP(device_names);
+ else
+ GetOutputDeviceNamesWinXP(device_names);
} else {
// Utilize the MMDevice API (part of Core Audio) for Vista and higher.
- media::GetInputDeviceNamesWin(device_names);
+ if (input)
+ GetInputDeviceNamesWin(device_names);
+ else
+ GetOutputDeviceNamesWin(device_names);
}
// Always add default device parameters as first element.
if (!device_names->empty()) {
- media::AudioDeviceName name;
+ AudioDeviceName name;
name.device_name = AudioManagerBase::kDefaultDeviceName;
name.unique_id = AudioManagerBase::kDefaultDeviceId;
device_names->push_front(name);
}
}
+void AudioManagerWin::GetAudioInputDeviceNames(AudioDeviceNames* device_names) {
+ GetAudioDeviceNamesImpl(true, device_names);
+}
+
+void AudioManagerWin::GetAudioOutputDeviceNames(
+ AudioDeviceNames* device_names) {
+ GetAudioDeviceNamesImpl(false, device_names);
+}
+
AudioParameters AudioManagerWin::GetInputStreamParameters(
const std::string& device_id) {
int sample_rate = 48000;
@@ -280,6 +297,11 @@ AudioParameters AudioManagerWin::GetInputStreamParameters(
sample_rate, 16, kFallbackBufferSize);
}
+std::string AudioManagerWin::GetAssociatedOutputDeviceID(
+ const std::string& input_device_id) {
+ return CoreAudioUtil::GetMatchingOutputDeviceID(input_device_id);
+}
+
// Factory for the implementations of AudioOutputStream for AUDIO_PCM_LINEAR
// mode.
// - PCMWaveOutAudioOutputStream: Based on the waveOut API.
@@ -291,7 +313,7 @@ AudioOutputStream* AudioManagerWin::MakeLinearOutputStream(
return new PCMWaveOutAudioOutputStream(this,
params,
- media::NumberOfWaveOutBuffers(),
+ NumberOfWaveOutBuffers(),
WAVE_MAPPER);
}
@@ -301,25 +323,31 @@ AudioOutputStream* AudioManagerWin::MakeLinearOutputStream(
// - PCMWaveOutAudioOutputStream: Based on the waveOut API.
// - WASAPIAudioOutputStream: Based on Core Audio (WASAPI) API.
AudioOutputStream* AudioManagerWin::MakeLowLatencyOutputStream(
- const AudioParameters& params, const std::string& input_device_id) {
+ const AudioParameters& params,
+ const std::string& device_id,
+ const std::string& input_device_id) {
DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
if (params.channels() > kWinMaxChannels)
return NULL;
if (!CoreAudioUtil::IsSupported()) {
// Fall back to Windows Wave implementation on Windows XP or lower.
+ DLOG_IF(ERROR, !device_id.empty())
+ << "Opening by device id not supported by PCMWaveOutAudioOutputStream";
DVLOG(1) << "Using WaveOut since WASAPI requires at least Vista.";
return new PCMWaveOutAudioOutputStream(
- this, params, media::NumberOfWaveOutBuffers(), WAVE_MAPPER);
+ this, params, NumberOfWaveOutBuffers(), WAVE_MAPPER);
}
- // TODO(crogers): support more than stereo input.
+ // TODO(rtoy): support more than stereo input.
if (params.input_channels() > 0) {
DVLOG(1) << "WASAPIUnifiedStream is created.";
+ DLOG_IF(ERROR, !device_id.empty())
+ << "Opening by device id not supported by WASAPIUnifiedStream";
return new WASAPIUnifiedStream(this, params, input_device_id);
}
- return new WASAPIAudioOutputStream(this, params, eConsole);
+ return new WASAPIAudioOutputStream(this, device_id, params, eConsole);
}
// Factory for the implementations of AudioInputStream for AUDIO_PCM_LINEAR
@@ -347,55 +375,68 @@ AudioInputStream* AudioManagerWin::MakeLowLatencyInputStream(
return stream;
}
+std::string AudioManagerWin::GetDefaultOutputDeviceID() {
+ if (!CoreAudioUtil::IsSupported())
+ return std::string();
+ return CoreAudioUtil::GetDefaultOutputDeviceID();
+}
+
AudioParameters AudioManagerWin::GetPreferredOutputStreamParameters(
+ const std::string& output_device_id,
const AudioParameters& input_params) {
+ const bool core_audio_supported = CoreAudioUtil::IsSupported();
+ DLOG_IF(ERROR, !core_audio_supported && !output_device_id.empty())
+ << "CoreAudio is required to open non-default devices.";
+
const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
int sample_rate = 48000;
int buffer_size = kFallbackBufferSize;
int bits_per_sample = 16;
int input_channels = 0;
- bool use_input_params = !CoreAudioUtil::IsSupported();
- if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio)) {
- // TODO(crogers): tune these values for best possible WebAudio performance.
- // WebRTC works well at 48kHz and a buffer size of 480 samples will be used
- // for this case. Note that exclusive mode is experimental.
- // This sample rate will be combined with a buffer size of 256 samples,
- // which corresponds to an output delay of ~5.33ms.
- sample_rate = 48000;
- buffer_size = 256;
- if (input_params.IsValid())
- channel_layout = input_params.channel_layout();
- } else if (!use_input_params) {
- // Hardware sample-rate on Windows can be configured, so we must query.
- // TODO(henrika): improve possibility to specify an audio endpoint.
- // Use the default device (same as for Wave) for now to be compatible.
- int hw_sample_rate = WASAPIAudioOutputStream::HardwareSampleRate();
-
- AudioParameters params;
- HRESULT hr = CoreAudioUtil::GetPreferredAudioParameters(eRender, eConsole,
- &params);
- int hw_buffer_size =
- FAILED(hr) ? kFallbackBufferSize : params.frames_per_buffer();
- channel_layout = WASAPIAudioOutputStream::HardwareChannelLayout();
-
- // TODO(henrika): Figure out the right thing to do here.
- if (hw_sample_rate && hw_buffer_size) {
- sample_rate = hw_sample_rate;
- buffer_size = hw_buffer_size;
+ bool use_input_params = !core_audio_supported;
+ if (core_audio_supported) {
+ if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio)) {
+ // TODO(rtoy): tune these values for best possible WebAudio
+ // performance. WebRTC works well at 48kHz and a buffer size of 480
+ // samples will be used for this case. Note that exclusive mode is
+ // experimental. This sample rate will be combined with a buffer size of
+ // 256 samples, which corresponds to an output delay of ~5.33ms.
+ sample_rate = 48000;
+ buffer_size = 256;
+ if (input_params.IsValid())
+ channel_layout = input_params.channel_layout();
} else {
- use_input_params = true;
+ AudioParameters params;
+ HRESULT hr = CoreAudioUtil::GetPreferredAudioParameters(
+ output_device_id.empty() ?
+ GetDefaultOutputDeviceID() : output_device_id,
+ &params);
+ if (SUCCEEDED(hr)) {
+ bits_per_sample = params.bits_per_sample();
+ buffer_size = params.frames_per_buffer();
+ channel_layout = params.channel_layout();
+ sample_rate = params.sample_rate();
+ } else {
+ use_input_params = true;
+ }
}
}
if (input_params.IsValid()) {
- if (cmd_line->HasSwitch(switches::kTrySupportedChannelLayouts) &&
- CoreAudioUtil::IsSupported()) {
+ if (core_audio_supported &&
+ cmd_line->HasSwitch(switches::kTrySupportedChannelLayouts)) {
// Check if it is possible to open up at the specified input channel
// layout but avoid checking if the specified layout is the same as the
// hardware (preferred) layout. We do this extra check to avoid the
// CoreAudioUtil::IsChannelLayoutSupported() overhead in most cases.
if (input_params.channel_layout() != channel_layout) {
+ // TODO(henrika): Use |output_device_id| here.
+ // Internally, IsChannelLayoutSupported does many of the operations
+ // that have already been done such as opening up a client and fetching
+ // the WAVEFORMATPCMEX format. Ideally we should only do that once and
+ // do it for the requested device. Then here, we can check the layout
+ // from the data we already hold.
if (CoreAudioUtil::IsChannelLayoutSupported(
eRender, eConsole, input_params.channel_layout())) {
// Open up using the same channel layout as the source if it is
@@ -413,10 +454,10 @@ AudioParameters AudioManagerWin::GetPreferredOutputStreamParameters(
// equal to the input values, AudioOutputResampler will skip resampling
// and bit per sample differences (since the input parameters will match
// the output parameters).
- sample_rate = input_params.sample_rate();
bits_per_sample = input_params.bits_per_sample();
- channel_layout = input_params.channel_layout();
buffer_size = input_params.frames_per_buffer();
+ channel_layout = input_params.channel_layout();
+ sample_rate = input_params.sample_rate();
}
}
@@ -435,7 +476,7 @@ AudioInputStream* AudioManagerWin::CreatePCMWaveInAudioInputStream(
std::string xp_device_id = device_id;
if (device_id != AudioManagerBase::kDefaultDeviceId &&
enumeration_type_ == kMMDeviceEnumeration) {
- xp_device_id = media::ConvertToWinXPDeviceId(device_id);
+ xp_device_id = ConvertToWinXPInputDeviceId(device_id);
if (xp_device_id.empty()) {
DLOG(ERROR) << "Cannot find a waveIn device which matches the device ID "
<< device_id;
diff --git a/media/audio/win/audio_manager_win.h b/media/audio/win/audio_manager_win.h
index 65cc73bbd6..b3e8de9286 100644
--- a/media/audio/win/audio_manager_win.h
+++ b/media/audio/win/audio_manager_win.h
@@ -25,26 +25,33 @@ class MEDIA_EXPORT AudioManagerWin : public AudioManagerBase {
virtual bool HasAudioInputDevices() OVERRIDE;
virtual string16 GetAudioInputDeviceModel() OVERRIDE;
virtual void ShowAudioInputSettings() OVERRIDE;
- virtual void GetAudioInputDeviceNames(media::AudioDeviceNames* device_names)
+ virtual void GetAudioInputDeviceNames(AudioDeviceNames* device_names)
+ OVERRIDE;
+ virtual void GetAudioOutputDeviceNames(AudioDeviceNames* device_names)
OVERRIDE;
virtual AudioParameters GetInputStreamParameters(
const std::string& device_id) OVERRIDE;
+ virtual std::string GetAssociatedOutputDeviceID(
+ const std::string& input_device_id) OVERRIDE;
// Implementation of AudioManagerBase.
virtual AudioOutputStream* MakeLinearOutputStream(
const AudioParameters& params) OVERRIDE;
virtual AudioOutputStream* MakeLowLatencyOutputStream(
const AudioParameters& params,
+ const std::string& device_id,
const std::string& input_device_id) OVERRIDE;
virtual AudioInputStream* MakeLinearInputStream(
const AudioParameters& params, const std::string& device_id) OVERRIDE;
virtual AudioInputStream* MakeLowLatencyInputStream(
const AudioParameters& params, const std::string& device_id) OVERRIDE;
+ virtual std::string GetDefaultOutputDeviceID() OVERRIDE;
protected:
virtual ~AudioManagerWin();
virtual AudioParameters GetPreferredOutputStreamParameters(
+ const std::string& output_device_id,
const AudioParameters& input_params) OVERRIDE;
private:
@@ -55,6 +62,8 @@ class MEDIA_EXPORT AudioManagerWin : public AudioManagerBase {
};
// Allow unit test to modify the utilized enumeration API.
+ // TODO(joi): Collapse these tests into one.
+ friend class AudioManagerTest;
friend class AudioInputDeviceTest;
EnumerationType enumeration_type_;
@@ -76,6 +85,8 @@ class MEDIA_EXPORT AudioManagerWin : public AudioManagerBase {
void CreateDeviceListener();
void DestroyDeviceListener();
+ void GetAudioDeviceNamesImpl(bool input, AudioDeviceNames* device_names);
+
// Listen for output device changes.
scoped_ptr<AudioDeviceListenerWin> output_device_listener_;
diff --git a/media/audio/win/audio_output_win_unittest.cc b/media/audio/win/audio_output_win_unittest.cc
index 4e13d84f3d..7ce146b0ab 100644
--- a/media/audio/win/audio_output_win_unittest.cc
+++ b/media/audio/win/audio_output_win_unittest.cc
@@ -185,7 +185,7 @@ TEST(WinAudioTest, PCMWaveStreamGetAndClose) {
AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
8000, 16, 256),
- std::string());
+ std::string(), std::string());
ASSERT_TRUE(NULL != oas);
oas->Close();
}
@@ -201,29 +201,29 @@ TEST(WinAudioTest, SanityOnMakeParams) {
AudioParameters::Format fmt = AudioParameters::AUDIO_PCM_LINEAR;
EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
AudioParameters(fmt, CHANNEL_LAYOUT_UNSUPPORTED, 8000, 16, 256),
- std::string()));
+ std::string(), std::string()));
EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 1024 * 1024, 16, 256),
- std::string()));
+ std::string(), std::string()));
EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
AudioParameters(fmt, CHANNEL_LAYOUT_STEREO, 8000, 80, 256),
- std::string()));
+ std::string(), std::string()));
EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
AudioParameters(fmt, CHANNEL_LAYOUT_UNSUPPORTED, 8000, 16, 256),
- std::string()));
+ std::string(), std::string()));
EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
AudioParameters(fmt, CHANNEL_LAYOUT_STEREO, -8000, 16, 256),
- std::string()));
+ std::string(), std::string()));
EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16, -100),
- std::string()));
+ std::string(), std::string()));
EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16, 0),
- std::string()));
+ std::string(), std::string()));
EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream(
AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16,
media::limits::kMaxSamplesPerPacket + 1),
- std::string()));
+ std::string(), std::string()));
}
// Test that it can be opened and closed.
@@ -237,7 +237,7 @@ TEST(WinAudioTest, PCMWaveStreamOpenAndClose) {
AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
8000, 16, 256),
- std::string());
+ std::string(), std::string());
ASSERT_TRUE(NULL != oas);
EXPECT_TRUE(oas->Open());
oas->Close();
@@ -254,7 +254,7 @@ TEST(WinAudioTest, PCMWaveStreamOpenLimit) {
AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
8000, 16, 1024 * 1024 * 1024),
- std::string());
+ std::string(), std::string());
EXPECT_TRUE(NULL == oas);
if (oas)
oas->Close();
@@ -273,7 +273,7 @@ TEST(WinAudioTest, PCMWaveSlowSource) {
AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
16000, 16, 256),
- std::string());
+ std::string(), std::string());
ASSERT_TRUE(NULL != oas);
TestSourceLaggy test_laggy(2, 90);
EXPECT_TRUE(oas->Open());
@@ -302,7 +302,7 @@ TEST(WinAudioTest, PCMWaveStreamPlaySlowLoop) {
AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
AudioParameters::kAudioCDSampleRate, 16, samples_100_ms),
- std::string());
+ std::string(), std::string());
ASSERT_TRUE(NULL != oas);
SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate);
@@ -333,7 +333,7 @@ TEST(WinAudioTest, PCMWaveStreamPlay200HzTone44Kss) {
AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
AudioParameters::kAudioCDSampleRate, 16, samples_100_ms),
- std::string());
+ std::string(), std::string());
ASSERT_TRUE(NULL != oas);
SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate);
@@ -362,7 +362,7 @@ TEST(WinAudioTest, PCMWaveStreamPlay200HzTone22Kss) {
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
AudioParameters::kAudioCDSampleRate / 2, 16,
samples_100_ms),
- std::string());
+ std::string(), std::string());
ASSERT_TRUE(NULL != oas);
SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate/2);
@@ -402,7 +402,7 @@ TEST(WinAudioTest, PushSourceFile16KHz) {
AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
kSampleRate, 16, kSamples100ms),
- std::string());
+ std::string(), std::string());
ASSERT_TRUE(NULL != oas);
EXPECT_TRUE(oas->Open());
@@ -439,7 +439,7 @@ TEST(WinAudioTest, PCMWaveStreamPlayTwice200HzTone44Kss) {
AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
AudioParameters::kAudioCDSampleRate, 16, samples_100_ms),
- std::string());
+ std::string(), std::string());
ASSERT_TRUE(NULL != oas);
SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate);
@@ -486,7 +486,7 @@ TEST(WinAudioTest, PCMWaveStreamPlay200HzToneLowLatency) {
AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY,
CHANNEL_LAYOUT_MONO, sample_rate,
16, n * samples_10_ms),
- std::string());
+ std::string(), std::string());
ASSERT_TRUE(NULL != oas);
SineWaveAudioSource source(1, 200, sample_rate);
@@ -520,7 +520,7 @@ TEST(WinAudioTest, PCMWaveStreamPendingBytes) {
AudioOutputStream* oas = audio_man->MakeAudioOutputStream(
AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
AudioParameters::kAudioCDSampleRate, 16, samples_100_ms),
- std::string());
+ std::string(), std::string());
ASSERT_TRUE(NULL != oas);
NiceMock<MockAudioSource> source;
@@ -680,7 +680,7 @@ TEST(WinAudioTest, SyncSocketBasic) {
AudioOutputStream* oas = audio_man->MakeAudioOutputStream(params,
- std::string());
+ std::string(), std::string());
ASSERT_TRUE(NULL != oas);
ASSERT_TRUE(oas->Open());
diff --git a/media/audio/win/audio_unified_win_unittest.cc b/media/audio/win/audio_unified_win_unittest.cc
index cfd17aea14..011c36348b 100644
--- a/media/audio/win/audio_unified_win_unittest.cc
+++ b/media/audio/win/audio_unified_win_unittest.cc
@@ -196,13 +196,13 @@ class AudioUnifiedStreamWrapper {
// Creates an AudioOutputStream object using default parameters.
WASAPIUnifiedStream* Create() {
- return static_cast<WASAPIUnifiedStream*> (CreateOutputStream());
+ return static_cast<WASAPIUnifiedStream*>(CreateOutputStream());
}
// Creates an AudioOutputStream object using default parameters but a
// specified input device.
WASAPIUnifiedStream* Create(const std::string device_id) {
- return static_cast<WASAPIUnifiedStream*> (CreateOutputStream(device_id));
+ return static_cast<WASAPIUnifiedStream*>(CreateOutputStream(device_id));
}
AudioParameters::Format format() const { return params_.format(); }
@@ -223,20 +223,21 @@ class AudioUnifiedStreamWrapper {
CoreAudioUtil::CreateDefaultDevice(eCapture, eConsole);
AudioDeviceName name;
EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetDeviceName(audio_device, &name)));
- const std::string& device_id = name.unique_id;
- EXPECT_TRUE(CoreAudioUtil::DeviceIsDefault(eCapture, eConsole, device_id));
+ const std::string& input_device_id = name.unique_id;
+ EXPECT_TRUE(CoreAudioUtil::DeviceIsDefault(eCapture, eConsole,
+ input_device_id));
// Create the unified audio I/O stream using the default input device.
AudioOutputStream* aos = audio_man_->MakeAudioOutputStream(params_,
- device_id);
+ "", input_device_id);
EXPECT_TRUE(aos);
return aos;
}
- AudioOutputStream* CreateOutputStream(const std::string& device_id) {
+ AudioOutputStream* CreateOutputStream(const std::string& input_device_id) {
// Create the unified audio I/O stream using the specified input device.
AudioOutputStream* aos = audio_man_->MakeAudioOutputStream(params_,
- device_id);
+ "", input_device_id);
EXPECT_TRUE(aos);
return aos;
}
diff --git a/media/audio/win/core_audio_util_win.cc b/media/audio/win/core_audio_util_win.cc
index 73d7b11171..4adfdda090 100644
--- a/media/audio/win/core_audio_util_win.cc
+++ b/media/audio/win/core_audio_util_win.cc
@@ -123,7 +123,7 @@ static std::ostream& operator<<(std::ostream& os,
return os;
}
-bool LoadAudiosesDll() {
+static bool LoadAudiosesDll() {
static const wchar_t* const kAudiosesDLL =
L"%WINDIR%\\system32\\audioses.dll";
@@ -132,7 +132,7 @@ bool LoadAudiosesDll() {
return (LoadLibraryExW(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) != NULL);
}
-bool CanCreateDeviceEnumerator() {
+static bool CanCreateDeviceEnumerator() {
ScopedComPtr<IMMDeviceEnumerator> device_enumerator;
HRESULT hr = device_enumerator.CreateInstance(__uuidof(MMDeviceEnumerator),
NULL, CLSCTX_INPROC_SERVER);
@@ -144,6 +144,14 @@ bool CanCreateDeviceEnumerator() {
return SUCCEEDED(hr);
}
+static std::string GetDeviceID(IMMDevice* device) {
+ ScopedCoMem<WCHAR> device_id_com;
+ std::string device_id;
+ if (SUCCEEDED(device->GetId(&device_id_com)))
+ WideToUTF8(device_id_com, wcslen(device_id_com), &device_id);
+ return device_id;
+}
+
bool CoreAudioUtil::IsSupported() {
// It is possible to force usage of WaveXxx APIs by using a command line flag.
const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
@@ -263,6 +271,12 @@ ScopedComPtr<IMMDevice> CoreAudioUtil::CreateDefaultDevice(EDataFlow data_flow,
return endpoint_device;
}
+std::string CoreAudioUtil::GetDefaultOutputDeviceID() {
+ DCHECK(IsSupported());
+ ScopedComPtr<IMMDevice> device(CreateDefaultDevice(eRender, eConsole));
+ return device ? GetDeviceID(device) : std::string();
+}
+
ScopedComPtr<IMMDevice> CoreAudioUtil::CreateDevice(
const std::string& device_id) {
DCHECK(IsSupported());
@@ -289,17 +303,14 @@ HRESULT CoreAudioUtil::GetDeviceName(IMMDevice* device, AudioDeviceName* name) {
// Retrieve unique name of endpoint device.
// Example: "{0.0.1.00000000}.{8db6020f-18e3-4f25-b6f5-7726c9122574}".
AudioDeviceName device_name;
- ScopedCoMem<WCHAR> endpoint_device_id;
- HRESULT hr = device->GetId(&endpoint_device_id);
- if (FAILED(hr))
- return hr;
- WideToUTF8(endpoint_device_id, wcslen(endpoint_device_id),
- &device_name.unique_id);
+ device_name.unique_id = GetDeviceID(device);
+ if (device_name.unique_id.empty())
+ return E_FAIL;
// Retrieve user-friendly name of endpoint device.
// Example: "Microphone (Realtek High Definition Audio)".
ScopedComPtr<IPropertyStore> properties;
- hr = device->OpenPropertyStore(STGM_READ, properties.Receive());
+ HRESULT hr = device->OpenPropertyStore(STGM_READ, properties.Receive());
if (FAILED(hr))
return hr;
base::win::ScopedPropVariant friendly_name;
@@ -365,6 +376,41 @@ std::string CoreAudioUtil::GetAudioControllerID(IMMDevice* device,
return controller_id;
}
+std::string CoreAudioUtil::GetMatchingOutputDeviceID(
+ const std::string& input_device_id) {
+ ScopedComPtr<IMMDevice> input_device(CreateDevice(input_device_id));
+ if (!input_device)
+ return std::string();
+
+ // See if we can get id of the associated controller.
+ ScopedComPtr<IMMDeviceEnumerator> enumerator(CreateDeviceEnumerator());
+ std::string controller_id(GetAudioControllerID(input_device, enumerator));
+ if (controller_id.empty())
+ return std::string();
+
+ // Now enumerate the available (and active) output devices and see if any of
+ // them is associated with the same controller.
+ ScopedComPtr<IMMDeviceCollection> collection;
+ enumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE,
+ collection.Receive());
+ if (!collection)
+ return std::string();
+
+ UINT count = 0;
+ collection->GetCount(&count);
+ ScopedComPtr<IMMDevice> output_device;
+ for (UINT i = 0; i < count; ++i) {
+ collection->Item(i, output_device.Receive());
+ std::string output_controller_id(CoreAudioUtil::GetAudioControllerID(
+ output_device, enumerator));
+ if (output_controller_id == controller_id)
+ break;
+ output_device = NULL;
+ }
+
+ return output_device ? GetDeviceID(output_device) : std::string();
+}
+
std::string CoreAudioUtil::GetFriendlyName(const std::string& device_id) {
DCHECK(IsSupported());
ScopedComPtr<IMMDevice> audio_device = CreateDevice(device_id);
@@ -387,16 +433,8 @@ bool CoreAudioUtil::DeviceIsDefault(EDataFlow flow,
if (!device)
return false;
- ScopedCoMem<WCHAR> default_device_id;
- HRESULT hr = device->GetId(&default_device_id);
- if (FAILED(hr))
- return false;
-
- std::string str_default;
- WideToUTF8(default_device_id, wcslen(default_device_id), &str_default);
- if (device_id.compare(str_default) != 0)
- return false;
- return true;
+ std::string str_default(GetDeviceID(device));
+ return device_id.compare(str_default) == 0;
}
EDataFlow CoreAudioUtil::GetDataFlow(IMMDevice* device) {
diff --git a/media/audio/win/core_audio_util_win.h b/media/audio/win/core_audio_util_win.h
index 154a33a8a4..cdf6dfb11d 100644
--- a/media/audio/win/core_audio_util_win.h
+++ b/media/audio/win/core_audio_util_win.h
@@ -59,6 +59,10 @@ class MEDIA_EXPORT CoreAudioUtil {
static ScopedComPtr<IMMDevice> CreateDefaultDevice(
EDataFlow data_flow, ERole role);
+ // Returns the device id of the default output device or an empty string
+ // if no such device exists or if the default device has been disabled.
+ static std::string GetDefaultOutputDeviceID();
+
// Creates an endpoint device that is specified by a unique endpoint device-
// identification string.
static ScopedComPtr<IMMDevice> CreateDevice(const std::string& device_id);
@@ -80,6 +84,12 @@ class MEDIA_EXPORT CoreAudioUtil {
static std::string GetAudioControllerID(IMMDevice* device,
IMMDeviceEnumerator* enumerator);
+ // Accepts an id of an input device and finds a matching output device id.
+ // If the associated hardware does not have an audio output device (e.g.
+ // a webcam with a mic), an empty string is returned.
+ static std::string GetMatchingOutputDeviceID(
+ const std::string& input_device_id);
+
// Gets the user-friendly name of the endpoint device which is represented
// by a unique id in |device_id|.
static std::string GetFriendlyName(const std::string& device_id);
diff --git a/media/audio/win/core_audio_util_win_unittest.cc b/media/audio/win/core_audio_util_win_unittest.cc
index f18c6118e1..abef868202 100644
--- a/media/audio/win/core_audio_util_win_unittest.cc
+++ b/media/audio/win/core_audio_util_win_unittest.cc
@@ -3,7 +3,9 @@
// found in the LICENSE file.
#include "base/memory/scoped_ptr.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
+#include "base/win/scoped_co_mem.h"
#include "base/win/scoped_com_initializer.h"
#include "base/win/scoped_handle.h"
#include "media/audio/win/core_audio_util_win.h"
@@ -475,6 +477,46 @@ TEST_F(CoreAudioUtilWinTest, FillRenderEndpointBufferWithSilence) {
EXPECT_EQ(num_queued_frames, endpoint_buffer_size);
}
-//
+// This test can only succeed on a machine that has audio hardware
+// that has both input and output devices. Currently this is the case
+// with our test bots and the CanRunAudioTest() method should make sure
+// that the test won't run in unsupported environments, but be warned.
+TEST_F(CoreAudioUtilWinTest, GetMatchingOutputDeviceID) {
+ if (!CanRunAudioTest())
+ return;
+
+ bool found_a_pair = false;
+
+ ScopedComPtr<IMMDeviceEnumerator> enumerator(
+ CoreAudioUtil::CreateDeviceEnumerator());
+ ASSERT_TRUE(enumerator);
+
+ // Enumerate all active input and output devices and fetch the ID of
+ // the associated device.
+ ScopedComPtr<IMMDeviceCollection> collection;
+ ASSERT_TRUE(SUCCEEDED(enumerator->EnumAudioEndpoints(eCapture,
+ DEVICE_STATE_ACTIVE, collection.Receive())));
+ UINT count = 0;
+ collection->GetCount(&count);
+ for (UINT i = 0; i < count && !found_a_pair; ++i) {
+ ScopedComPtr<IMMDevice> device;
+ collection->Item(i, device.Receive());
+ base::win::ScopedCoMem<WCHAR> wide_id;
+ device->GetId(&wide_id);
+ std::string id;
+ WideToUTF8(wide_id, wcslen(wide_id), &id);
+ found_a_pair = !CoreAudioUtil::GetMatchingOutputDeviceID(id).empty();
+ }
+
+ EXPECT_TRUE(found_a_pair);
+}
+
+TEST_F(CoreAudioUtilWinTest, GetDefaultOutputDeviceID) {
+ if (!CanRunAudioTest())
+ return;
+
+ std::string default_device_id(CoreAudioUtil::GetDefaultOutputDeviceID());
+ EXPECT_FALSE(default_device_id.empty());
+}
} // namespace media
diff --git a/media/audio/win/device_enumeration_win.cc b/media/audio/win/device_enumeration_win.cc
index 36ed2913ff..50d0b7aa0e 100644
--- a/media/audio/win/device_enumeration_win.cc
+++ b/media/audio/win/device_enumeration_win.cc
@@ -8,13 +8,13 @@
#include "media/audio/win/audio_manager_win.h"
+#include "base/basictypes.h"
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/scoped_co_mem.h"
#include "base/win/scoped_comptr.h"
#include "base/win/scoped_propvariant.h"
-using media::AudioDeviceNames;
using base::win::ScopedComPtr;
using base::win::ScopedCoMem;
@@ -25,7 +25,10 @@ using base::win::ScopedCoMem;
namespace media {
-bool GetInputDeviceNamesWin(AudioDeviceNames* device_names) {
+namespace {
+
+bool GetDeviceNamesWinImpl(EDataFlow data_flow,
+ AudioDeviceNames* device_names) {
// It is assumed that this method is called from a COM thread, i.e.,
// CoInitializeEx() is not called here again to avoid STA/MTA conflicts.
ScopedComPtr<IMMDeviceEnumerator> enumerator;
@@ -37,24 +40,24 @@ bool GetInputDeviceNamesWin(AudioDeviceNames* device_names) {
return false;
}
- // Generate a collection of active audio capture endpoint devices.
+ // Generate a collection of active audio endpoint devices.
// This method will succeed even if all devices are disabled.
ScopedComPtr<IMMDeviceCollection> collection;
- hr = enumerator->EnumAudioEndpoints(eCapture,
+ hr = enumerator->EnumAudioEndpoints(data_flow,
DEVICE_STATE_ACTIVE,
collection.Receive());
if (FAILED(hr))
return false;
- // Retrieve the number of active capture devices.
+ // Retrieve the number of active devices.
UINT number_of_active_devices = 0;
collection->GetCount(&number_of_active_devices);
if (number_of_active_devices == 0)
return true;
- media::AudioDeviceName device;
+ AudioDeviceName device;
- // Loop over all active capture devices and add friendly name and
+ // Loop over all active devices and add friendly name and
// unique ID to the |device_names| list.
for (UINT i = 0; i < number_of_active_devices; ++i) {
// Retrieve unique name of endpoint device.
@@ -92,14 +95,22 @@ bool GetInputDeviceNamesWin(AudioDeviceNames* device_names) {
return true;
}
-bool GetInputDeviceNamesWinXP(AudioDeviceNames* device_names) {
+// The waveform API is weird in that it has completely separate but
+// almost identical functions and structs for input devices vs. output
+// devices. We deal with this by implementing the logic as a templated
+// function that takes the functions and struct type to use as
+// template parameters.
+template <UINT (__stdcall *NumDevsFunc)(),
+ typename CAPSSTRUCT,
+ MMRESULT (__stdcall *DevCapsFunc)(UINT_PTR, CAPSSTRUCT*, UINT)>
+bool GetDeviceNamesWinXPImpl(AudioDeviceNames* device_names) {
// Retrieve the number of active waveform input devices.
- UINT number_of_active_devices = waveInGetNumDevs();
+ UINT number_of_active_devices = NumDevsFunc();
if (number_of_active_devices == 0)
return true;
- media::AudioDeviceName device;
- WAVEINCAPS capabilities;
+ AudioDeviceName device;
+ CAPSSTRUCT capabilities;
MMRESULT err = MMSYSERR_NOERROR;
// Loop over all active capture devices and add friendly name and
@@ -108,7 +119,7 @@ bool GetInputDeviceNamesWinXP(AudioDeviceNames* device_names) {
// there is no safe method to retrieve a unique device name on XP.
for (UINT i = 0; i < number_of_active_devices; ++i) {
// Retrieve the capabilities of the specified waveform-audio input device.
- err = waveInGetDevCaps(i, &capabilities, sizeof(capabilities));
+ err = DevCapsFunc(i, &capabilities, sizeof(capabilities));
if (err != MMSYSERR_NOERROR)
continue;
@@ -118,7 +129,7 @@ bool GetInputDeviceNamesWinXP(AudioDeviceNames* device_names) {
device.device_name = WideToUTF8(capabilities.szPname);
// Store the "unique" name (we use same as friendly name on Windows XP).
- device.unique_id = WideToUTF8(capabilities.szPname);
+ device.unique_id = device.device_name;
// Add combination of user-friendly and unique name to the output list.
device_names->push_back(device);
@@ -127,7 +138,27 @@ bool GetInputDeviceNamesWinXP(AudioDeviceNames* device_names) {
return true;
}
-std::string ConvertToWinXPDeviceId(const std::string& device_id) {
+} // namespace
+
+bool GetInputDeviceNamesWin(AudioDeviceNames* device_names) {
+ return GetDeviceNamesWinImpl(eCapture, device_names);
+}
+
+bool GetOutputDeviceNamesWin(AudioDeviceNames* device_names) {
+ return GetDeviceNamesWinImpl(eRender, device_names);
+}
+
+bool GetInputDeviceNamesWinXP(AudioDeviceNames* device_names) {
+ return GetDeviceNamesWinXPImpl<
+ waveInGetNumDevs, WAVEINCAPSW, waveInGetDevCapsW>(device_names);
+}
+
+bool GetOutputDeviceNamesWinXP(AudioDeviceNames* device_names) {
+ return GetDeviceNamesWinXPImpl<
+ waveOutGetNumDevs, WAVEOUTCAPSW, waveOutGetDevCapsW>(device_names);
+}
+
+std::string ConvertToWinXPInputDeviceId(const std::string& device_id) {
UINT number_of_active_devices = waveInGetNumDevs();
MMRESULT result = MMSYSERR_NOERROR;
diff --git a/media/audio/win/device_enumeration_win.h b/media/audio/win/device_enumeration_win.h
index 3d44670a6d..e61a331842 100644
--- a/media/audio/win/device_enumeration_win.h
+++ b/media/audio/win/device_enumeration_win.h
@@ -11,28 +11,32 @@
namespace media {
-// Returns a list of audio input device structures (name and unique device ID)
-// using the MMDevice API which is supported on Windows Vista and higher.
+// Returns a list of audio input or output device structures (name and
+// unique device ID) using the MMDevice API which is supported on
+// Windows Vista and higher.
// Example record in the output list:
// - device_name: "Microphone (Realtek High Definition Audio)".
// - unique_id: "{0.0.1.00000000}.{8db6020f-18e3-4f25-b6f5-7726c9122574}"
// This method must be called from a COM thread using MTA.
bool GetInputDeviceNamesWin(media::AudioDeviceNames* device_names);
+bool GetOutputDeviceNamesWin(media::AudioDeviceNames* device_names);
-// Returns a list of audio input device structures (name and unique device ID)
-// using the WaveIn API which is supported on Windows XP and higher.
+// Returns a list of audio input or output device structures (name and
+// unique device ID) using the WaveIn API which is supported on
+// Windows XP and higher.
// Example record in the output list:
// - device_name: "Microphone (Realtek High Defini".
// - unique_id: "Microphone (Realtek High Defini" (same as friendly name).
bool GetInputDeviceNamesWinXP(media::AudioDeviceNames* device_names);
+bool GetOutputDeviceNamesWinXP(media::AudioDeviceNames* device_names);
-// Converts a device ID generated by |GetInputDeviceNamesWin()| to the
+// Converts an input device ID generated by |GetInputDeviceNamesWin()| to the
// corresponding ID by |GetInputDeviceNamesWinXP()|. Returns an empty string on
// failure.
// Example input and output:
// - input ID: "{0.0.1.00000000}.{8db6020f-18e3-4f25-b6f5-7726c9122574}"
// - output ID: "Microphone (Realtek High Defini"
-std::string ConvertToWinXPDeviceId(const std::string& device_id);
+std::string ConvertToWinXPInputDeviceId(const std::string& device_id);
} // namespace media