diff options
65 files changed, 513 insertions, 218 deletions
diff --git a/chrome/browser/notifications/notification_audio_controller.cc b/chrome/browser/notifications/notification_audio_controller.cc index 4fd26c6..ec7f090 100644 --- a/chrome/browser/notifications/notification_audio_controller.cc +++ b/chrome/browser/notifications/notification_audio_controller.cc @@ -251,7 +251,7 @@ bool NotificationAudioController::AudioHandler::StartPlayingSound( if (!params.IsValid()) return false; - stream_ = audio_manager_->MakeAudioOutputStreamProxy(params); + stream_ = audio_manager_->MakeAudioOutputStreamProxy(params, std::string()); if (!stream_->Open()) { DLOG(ERROR) << "Failed to open the output stream"; stream_->Close(); diff --git a/content/browser/renderer_host/media/audio_input_device_manager.cc b/content/browser/renderer_host/media/audio_input_device_manager.cc index 762381b..7a7ecda 100644 --- a/content/browser/renderer_host/media/audio_input_device_manager.cc +++ b/content/browser/renderer_host/media/audio_input_device_manager.cc @@ -29,6 +29,13 @@ AudioInputDeviceManager::AudioInputDeviceManager( next_capture_session_id_(kFirstSessionId), use_fake_device_(false), audio_manager_(audio_manager) { + // TODO(xians): Remove this fake_device after the unittests do not need it. + StreamDeviceInfo fake_device(MEDIA_DEVICE_AUDIO_CAPTURE, + media::AudioManagerBase::kDefaultDeviceName, + media::AudioManagerBase::kDefaultDeviceId, + 44100, media::CHANNEL_LAYOUT_STEREO, false); + fake_device.session_id = kFakeOpenSessionId; + devices_.push_back(fake_device); } AudioInputDeviceManager::~AudioInputDeviceManager() { @@ -88,7 +95,8 @@ void AudioInputDeviceManager::Close(int session_id) { if (device == devices_.end()) return; const MediaStreamType stream_type = device->device.type; - devices_.erase(device); + if (session_id != kFakeOpenSessionId) + devices_.erase(device); // Post a callback through the listener on IO thread since // MediaStreamManager is expecting the callback asynchronously. @@ -134,6 +142,14 @@ void AudioInputDeviceManager::EnumerateOnDeviceThread( stream_type, it->device_name, it->unique_id, false)); } + // If the |use_fake_device_| flag is on, inject the fake device if there is + // no available device on the OS. + if (use_fake_device_ && devices->empty()) { + devices->push_back(StreamDeviceInfo( + stream_type, media::AudioManagerBase::kDefaultDeviceName, + media::AudioManagerBase::kDefaultDeviceId, false)); + } + // Return the device list through the listener by posting a task on // IO thread since MediaStreamManager handles the callback asynchronously. BrowserThread::PostTask( @@ -147,14 +163,21 @@ void AudioInputDeviceManager::OpenOnDeviceThread( int session_id, const StreamDeviceInfo& info) { DCHECK(IsOnDeviceThread()); - // Get the preferred sample rate and channel configuration for the - // audio device. - media::AudioParameters params = - audio_manager_->GetInputStreamParameters(info.device.id); - StreamDeviceInfo out(info.device.type, info.device.name, info.device.id, - params.sample_rate(), params.channel_layout(), false); + 0, 0, false); out.session_id = session_id; + if (use_fake_device_) { + // Don't need to query the hardware information if using fake device. + out.device.sample_rate = 44100; + out.device.channel_layout = media::CHANNEL_LAYOUT_STEREO; + } else { + // Get the preferred sample rate and channel configuration for the + // audio device. + media::AudioParameters params = + audio_manager_->GetInputStreamParameters(info.device.id); + out.device.sample_rate = params.sample_rate(); + out.device.channel_layout = params.channel_layout(); + } // Return the |session_id| through the listener by posting a task on // IO thread since MediaStreamManager handles the callback asynchronously. diff --git a/content/browser/renderer_host/media/audio_input_renderer_host.cc b/content/browser/renderer_host/media/audio_input_renderer_host.cc index e97bad7..e672046 100644 --- a/content/browser/renderer_host/media/audio_input_renderer_host.cc +++ b/content/browser/renderer_host/media/audio_input_renderer_host.cc @@ -213,9 +213,19 @@ void AudioInputRendererHost::OnCreateStream( return; } + media::AudioParameters audio_params(config.params); + if (media_stream_manager_->audio_input_device_manager()-> + ShouldUseFakeDevice()) { + audio_params.Reset( + media::AudioParameters::AUDIO_FAKE, + config.params.channel_layout(), config.params.channels(), 0, + config.params.sample_rate(), config.params.bits_per_sample(), + config.params.frames_per_buffer()); + } + // Check if we have the permission to open the device and which device to use. std::string device_id = media::AudioManagerBase::kDefaultDeviceId; - if (session_id != AudioInputDeviceManager::kFakeOpenSessionId) { + if (audio_params.format() != media::AudioParameters::AUDIO_FAKE) { const StreamDeviceInfo* info = media_stream_manager_-> audio_input_device_manager()->GetOpenedDeviceInfoById(session_id); if (!info) { @@ -228,16 +238,6 @@ void AudioInputRendererHost::OnCreateStream( device_id = info->device.id; } - media::AudioParameters audio_params(config.params); - if (media_stream_manager_->audio_input_device_manager()-> - ShouldUseFakeDevice()) { - audio_params.Reset( - media::AudioParameters::AUDIO_FAKE, - config.params.channel_layout(), config.params.channels(), 0, - config.params.sample_rate(), config.params.bits_per_sample(), - config.params.frames_per_buffer()); - } - // Create a new AudioEntry structure. scoped_ptr<AudioEntry> entry(new AudioEntry()); diff --git a/content/browser/renderer_host/media/audio_input_renderer_host.h b/content/browser/renderer_host/media/audio_input_renderer_host.h index 077a1cc..ae52a54 100644 --- a/content/browser/renderer_host/media/audio_input_renderer_host.h +++ b/content/browser/renderer_host/media/audio_input_renderer_host.h @@ -89,8 +89,7 @@ class CONTENT_EXPORT AudioInputRendererHost // Creates an audio input stream with the specified format whose data is // consumed by an entity in the render view referenced by |render_view_id|. // |session_id| is used to find out which device to be used for the stream. - // When it is AudioInputDeviceManager::kFakeOpenSessionId, it uses the the - // default device. Upon success/failure, the peer is notified via the + // Upon success/failure, the peer is notified via the // NotifyStreamCreated message. void OnCreateStream(int stream_id, int render_view_id, diff --git a/content/browser/renderer_host/media/audio_renderer_host.cc b/content/browser/renderer_host/media/audio_renderer_host.cc index 59bb567..0c8c310 100644 --- a/content/browser/renderer_host/media/audio_renderer_host.cc +++ b/content/browser/renderer_host/media/audio_renderer_host.cc @@ -12,12 +12,15 @@ #include "base/shared_memory.h" #include "content/browser/browser_main_loop.h" #include "content/browser/media/media_internals.h" +#include "content/browser/renderer_host/media/audio_input_device_manager.h" #include "content/browser/renderer_host/media/audio_mirroring_manager.h" #include "content/browser/renderer_host/media/audio_sync_reader.h" +#include "content/browser/renderer_host/media/media_stream_manager.h" #include "content/common/media/audio_messages.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/media_observer.h" #include "content/public/common/content_switches.h" +#include "media/audio/audio_manager_base.h" #include "media/audio/shared_memory_util.h" #include "media/base/audio_bus.h" #include "media/base/limits.h" @@ -33,6 +36,7 @@ class AudioRendererHost::AudioEntry int stream_id, int render_view_id, const media::AudioParameters& params, + const std::string& input_device_id, scoped_ptr<base::SharedMemory> shared_memory, scoped_ptr<media::AudioOutputController::SyncReader> reader); virtual ~AudioEntry(); @@ -84,13 +88,14 @@ class AudioRendererHost::AudioEntry AudioRendererHost::AudioEntry::AudioEntry( AudioRendererHost* host, int stream_id, int render_view_id, const media::AudioParameters& params, + const std::string& input_device_id, scoped_ptr<base::SharedMemory> shared_memory, scoped_ptr<media::AudioOutputController::SyncReader> reader) : host_(host), stream_id_(stream_id), render_view_id_(render_view_id), controller_(media::AudioOutputController::Create( - host->audio_manager_, this, params, reader.get())), + host->audio_manager_, this, params, input_device_id, reader.get())), shared_memory_(shared_memory.Pass()), reader_(reader.Pass()) { DCHECK(controller_.get()); @@ -104,12 +109,15 @@ AudioRendererHost::AudioRendererHost( int render_process_id, media::AudioManager* audio_manager, AudioMirroringManager* mirroring_manager, - MediaInternals* media_internals) + MediaInternals* media_internals, + MediaStreamManager* media_stream_manager) : render_process_id_(render_process_id), audio_manager_(audio_manager), mirroring_manager_(mirroring_manager), - media_internals_(media_internals) { + media_internals_(media_internals), + media_stream_manager_(media_stream_manager) { DCHECK(audio_manager_); + DCHECK(media_stream_manager_); } AudioRendererHost::~AudioRendererHost() { @@ -265,12 +273,14 @@ bool AudioRendererHost::OnMessageReceived(const IPC::Message& message, } void AudioRendererHost::OnCreateStream( - int stream_id, int render_view_id, const media::AudioParameters& params) { + int stream_id, int render_view_id, int session_id, + const media::AudioParameters& params) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); DVLOG(1) << "AudioRendererHost@" << this << "::OnCreateStream(stream_id=" << stream_id - << ", render_view_id=" << render_view_id << ")"; + << ", render_view_id=" << render_view_id + << ", session_id=" << session_id << ")"; DCHECK_GT(render_view_id, 0); // media::AudioParameters is validated in the deserializer. @@ -282,6 +292,22 @@ void AudioRendererHost::OnCreateStream( return; } + // When the |input_channels| is valid, clients are trying to create a unified + // IO stream which opens an input device mapping to the |session_id|. + std::string input_device_id; + if (input_channels > 0) { + const StreamDeviceInfo* info = media_stream_manager_-> + audio_input_device_manager()->GetOpenedDeviceInfoById(session_id); + if (!info) { + SendErrorMessage(stream_id); + DLOG(WARNING) << "No permission has been granted to input stream with " + << "session_id=" << session_id; + return; + } + + input_device_id = info->device.id; + } + // Calculate output and input memory size. int output_memory_size = AudioBus::CalculateMemorySize(params); int frames = params.frames_per_buffer(); @@ -308,7 +334,8 @@ void AudioRendererHost::OnCreateStream( } scoped_ptr<AudioEntry> entry(new AudioEntry( - this, stream_id, render_view_id, params, shared_memory.Pass(), + this, stream_id, render_view_id, params, input_device_id, + shared_memory.Pass(), reader.PassAs<media::AudioOutputController::SyncReader>())); if (mirroring_manager_) { mirroring_manager_->AddDiverter( diff --git a/content/browser/renderer_host/media/audio_renderer_host.h b/content/browser/renderer_host/media/audio_renderer_host.h index 803539c..b249ef4 100644 --- a/content/browser/renderer_host/media/audio_renderer_host.h +++ b/content/browser/renderer_host/media/audio_renderer_host.h @@ -61,6 +61,7 @@ namespace content { class AudioMirroringManager; class MediaInternals; +class MediaStreamManager; class ResourceContext; class CONTENT_EXPORT AudioRendererHost : public BrowserMessageFilter { @@ -69,7 +70,8 @@ class CONTENT_EXPORT AudioRendererHost : public BrowserMessageFilter { AudioRendererHost(int render_process_id, media::AudioManager* audio_manager, AudioMirroringManager* mirroring_manager, - MediaInternals* media_internals); + MediaInternals* media_internals, + MediaStreamManager* media_stream_manager); // BrowserMessageFilter implementation. virtual void OnChannelClosing() OVERRIDE; @@ -96,10 +98,14 @@ class CONTENT_EXPORT AudioRendererHost : public BrowserMessageFilter { // Creates an audio output stream with the specified format whose data is // produced by an entity in the render view referenced by |render_view_id|. + // |session_id| is used for unified IO to find out which input device to be + // opened for the stream. For clients that do not use unified IO, + // |session_id| will be ignored. // Upon success/failure, the peer is notified via the NotifyStreamCreated // message. void OnCreateStream(int stream_id, int render_view_id, + int session_id, const media::AudioParameters& params); // Play the audio stream referenced by |stream_id|. @@ -143,6 +149,9 @@ class CONTENT_EXPORT AudioRendererHost : public BrowserMessageFilter { AudioMirroringManager* const mirroring_manager_; MediaInternals* const media_internals_; + // Used to access to AudioInputDeviceManager. + MediaStreamManager* media_stream_manager_; + // A map of stream IDs to audio sources. AudioEntryMap audio_entries_; diff --git a/content/browser/renderer_host/media/audio_renderer_host_unittest.cc b/content/browser/renderer_host/media/audio_renderer_host_unittest.cc index bd4913b..7847981 100644 --- a/content/browser/renderer_host/media/audio_renderer_host_unittest.cc +++ b/content/browser/renderer_host/media/audio_renderer_host_unittest.cc @@ -9,12 +9,16 @@ #include "base/process_util.h" #include "base/sync_socket.h" #include "content/browser/browser_thread_impl.h" +#include "content/browser/renderer_host/media/audio_input_device_manager.h" #include "content/browser/renderer_host/media/audio_mirroring_manager.h" #include "content/browser/renderer_host/media/audio_renderer_host.h" +#include "content/browser/renderer_host/media/media_stream_manager.h" #include "content/browser/renderer_host/media/mock_media_observer.h" #include "content/common/media/audio_messages.h" +#include "content/common/media/media_stream_options.h" #include "ipc/ipc_message_utils.h" #include "media/audio/audio_manager.h" +#include "media/audio/audio_manager_base.h" #include "media/audio/fake_audio_output_stream.h" #include "net/url_request/url_request_context.h" #include "testing/gmock/include/gmock/gmock.h" @@ -56,11 +60,13 @@ class MockAudioRendererHost : public AudioRendererHost { explicit MockAudioRendererHost( media::AudioManager* audio_manager, AudioMirroringManager* mirroring_manager, - MediaInternals* media_internals) + MediaInternals* media_internals, + MediaStreamManager* media_stream_manager) : AudioRendererHost(kRenderProcessId, audio_manager, mirroring_manager, - media_internals), + media_internals, + media_stream_manager), shared_memory_length_(0) { } @@ -170,9 +176,12 @@ class AudioRendererHostTest : public testing::Test { ui_thread_.reset(new BrowserThreadImpl(BrowserThread::UI, message_loop_.get())); audio_manager_.reset(media::AudioManager::Create()); + media_stream_manager_.reset(new MediaStreamManager(audio_manager_.get())); + media_stream_manager_->UseFakeDevice(); observer_.reset(new MockMediaInternals()); host_ = new MockAudioRendererHost( - audio_manager_.get(), &mirroring_manager_, observer_.get()); + audio_manager_.get(), &mirroring_manager_, observer_.get(), + media_stream_manager_.get()); // Simulate IPC channel connected. host_->OnChannelConnected(base::GetCurrentProcId()); @@ -188,11 +197,14 @@ class AudioRendererHostTest : public testing::Test { // We need to continue running message_loop_ to complete all destructions. SyncWithAudioThread(); - audio_manager_.reset(); io_thread_.reset(); ui_thread_.reset(); + + // Delete the IO message loop. This will cause the MediaStreamManager to be + // notified so it will stop its device thread and device managers. + message_loop_.reset(); } void Create() { @@ -208,9 +220,47 @@ class AudioRendererHostTest : public testing::Test { // we receive the created message. host_->OnCreateStream(kStreamId, kRenderViewId, + 0, + media::AudioParameters( + media::AudioParameters::AUDIO_FAKE, + media::CHANNEL_LAYOUT_STEREO, + media::AudioParameters::kAudioCDSampleRate, 16, + media::AudioParameters::kAudioCDSampleRate / 10)); + message_loop_->Run(); + + // At some point in the future, a corresponding RemoveDiverter() call must + // be made. + EXPECT_CALL(mirroring_manager_, + RemoveDiverter(kRenderProcessId, kRenderViewId, NotNull())) + .RetiresOnSaturation(); + + // All created streams should ultimately be closed. + EXPECT_CALL(*observer_, + OnSetAudioStreamStatus(_, kStreamId, "closed")); + + // Expect the audio stream will be deleted at some later point. + EXPECT_CALL(*observer_, OnDeleteAudioStream(_, kStreamId)); + } + + void CreateUnifiedStream() { + EXPECT_CALL(*observer_, + OnSetAudioStreamStatus(_, kStreamId, "created")); + EXPECT_CALL(*host_, OnStreamCreated(kStreamId, _)) + .WillOnce(QuitMessageLoop(message_loop_.get())); + EXPECT_CALL(mirroring_manager_, + AddDiverter(kRenderProcessId, kRenderViewId, NotNull())) + .RetiresOnSaturation(); + // Send a create stream message to the audio output stream and wait until + // we receive the created message. + // Use AudioInputDeviceManager::kFakeOpenSessionId as the session id to + // pass the permission check. + host_->OnCreateStream(kStreamId, + kRenderViewId, + AudioInputDeviceManager::kFakeOpenSessionId, media::AudioParameters( media::AudioParameters::AUDIO_FAKE, media::CHANNEL_LAYOUT_STEREO, + 2, media::AudioParameters::kAudioCDSampleRate, 16, media::AudioParameters::kAudioCDSampleRate / 10)); message_loop_->Run(); @@ -315,6 +365,7 @@ class AudioRendererHostTest : public testing::Test { scoped_ptr<BrowserThreadImpl> io_thread_; scoped_ptr<BrowserThreadImpl> ui_thread_; scoped_ptr<media::AudioManager> audio_manager_; + scoped_ptr<MediaStreamManager> media_stream_manager_; DISALLOW_COPY_AND_ASSIGN(AudioRendererHostTest); }; @@ -379,6 +430,11 @@ TEST_F(AudioRendererHostTest, SimulateErrorAndClose) { Close(); } +TEST_F(AudioRendererHostTest, CreateUnifiedStreamAndClose) { + CreateUnifiedStream(); + Close(); +} + // TODO(hclam): Add tests for data conversation in low latency mode. } // namespace content diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index 4518841..260b613 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc @@ -596,7 +596,7 @@ void RenderProcessHostImpl::CreateMessageFilters() { media_stream_manager)); channel_->AddFilter(new AudioRendererHost( GetID(), audio_manager, BrowserMainLoop::GetAudioMirroringManager(), - media_internals)); + media_internals, media_stream_manager)); channel_->AddFilter(new VideoCaptureHost()); channel_->AddFilter(new AppCacheDispatcherHost( storage_partition_impl_->GetAppCacheService(), diff --git a/content/common/media/audio_messages.h b/content/common/media/audio_messages.h index dc844eb..d52712d 100644 --- a/content/common/media/audio_messages.h +++ b/content/common/media/audio_messages.h @@ -96,9 +96,10 @@ IPC_MESSAGE_CONTROL2(AudioInputMsg_NotifyStreamVolume, // Request that is sent to the browser for creating an audio output stream. // |render_view_id| is the routing ID for the render view producing the audio // data. -IPC_MESSAGE_CONTROL3(AudioHostMsg_CreateStream, +IPC_MESSAGE_CONTROL4(AudioHostMsg_CreateStream, int /* stream_id */, int /* render_view_id */, + int /* session_id */, media::AudioParameters /* params */) // Request that is sent to the browser for creating an audio input stream. diff --git a/content/renderer/media/audio_message_filter.cc b/content/renderer/media/audio_message_filter.cc index 1cb5352..4523f01 100644 --- a/content/renderer/media/audio_message_filter.cc +++ b/content/renderer/media/audio_message_filter.cc @@ -25,7 +25,8 @@ class AudioMessageFilter::AudioOutputIPCImpl // media::AudioOutputIPC implementation. virtual void CreateStream(media::AudioOutputIPCDelegate* delegate, - const media::AudioParameters& params) OVERRIDE; + const media::AudioParameters& params, + int session_id) OVERRIDE; virtual void PlayStream() OVERRIDE; virtual void PauseStream() OVERRIDE; virtual void CloseStream() OVERRIDE; @@ -75,13 +76,14 @@ scoped_ptr<media::AudioOutputIPC> AudioMessageFilter::CreateAudioOutputIPC( void AudioMessageFilter::AudioOutputIPCImpl::CreateStream( media::AudioOutputIPCDelegate* delegate, - const media::AudioParameters& params) { + const media::AudioParameters& params, + int session_id) { DCHECK(filter_->io_message_loop_->BelongsToCurrentThread()); DCHECK(delegate); DCHECK_EQ(stream_id_, kStreamIDNotSet); stream_id_ = filter_->delegates_.Add(delegate); filter_->Send(new AudioHostMsg_CreateStream( - stream_id_, render_view_id_, params)); + stream_id_, render_view_id_, session_id, params)); } void AudioMessageFilter::AudioOutputIPCImpl::PlayStream() { diff --git a/content/renderer/media/audio_message_filter_unittest.cc b/content/renderer/media/audio_message_filter_unittest.cc index 81db84e..fa8823f 100644 --- a/content/renderer/media/audio_message_filter_unittest.cc +++ b/content/renderer/media/audio_message_filter_unittest.cc @@ -79,7 +79,8 @@ TEST(AudioMessageFilterTest, Basic) { MockAudioDelegate delegate; const scoped_ptr<media::AudioOutputIPC> ipc = filter->CreateAudioOutputIPC(kRenderViewId); - ipc->CreateStream(&delegate, media::AudioParameters()); + static const int kSessionId = 0; + ipc->CreateStream(&delegate, media::AudioParameters(), kSessionId); static const int kStreamId = 1; EXPECT_EQ(&delegate, filter->delegates_.Lookup(kStreamId)); @@ -128,8 +129,9 @@ TEST(AudioMessageFilterTest, Delegates) { filter->CreateAudioOutputIPC(kRenderViewId); const scoped_ptr<media::AudioOutputIPC> ipc2 = filter->CreateAudioOutputIPC(kRenderViewId); - ipc1->CreateStream(&delegate1, media::AudioParameters()); - ipc2->CreateStream(&delegate2, media::AudioParameters()); + static const int kSessionId = 0; + ipc1->CreateStream(&delegate1, media::AudioParameters(), kSessionId); + ipc2->CreateStream(&delegate2, media::AudioParameters(), kSessionId); static const int kStreamId1 = 1; static const int kStreamId2 = 2; EXPECT_EQ(&delegate1, filter->delegates_.Lookup(kStreamId1)); diff --git a/content/renderer/media/media_stream_impl.cc b/content/renderer/media/media_stream_impl.cc index 20277b8..08d4edf 100644 --- a/content/renderer/media/media_stream_impl.cc +++ b/content/renderer/media/media_stream_impl.cc @@ -91,7 +91,8 @@ void CreateWebKitSourceVector( UTF8ToUTF16(devices[i].device.name)); webkit_sources[i].setExtraData( new content::MediaStreamSourceExtraData(devices[i], webkit_sources[i])); - webkit_sources[i].setDeviceId(UTF8ToUTF16(devices[i].device.id.c_str())); + webkit_sources[i].setDeviceId(UTF8ToUTF16( + base::IntToString(devices[i].session_id))); } } diff --git a/content/renderer/media/renderer_webaudiodevice_impl.cc b/content/renderer/media/renderer_webaudiodevice_impl.cc index 3b08159..cb2ba7d 100644 --- a/content/renderer/media/renderer_webaudiodevice_impl.cc +++ b/content/renderer/media/renderer_webaudiodevice_impl.cc @@ -22,9 +22,11 @@ namespace content { RendererWebAudioDeviceImpl::RendererWebAudioDeviceImpl( const media::AudioParameters& params, - WebAudioDevice::RenderCallback* callback) + WebAudioDevice::RenderCallback* callback, + int session_id) : params_(params), - client_callback_(callback) { + client_callback_(callback), + session_id_(session_id) { DCHECK(client_callback_); } @@ -51,7 +53,7 @@ void RendererWebAudioDeviceImpl::start() { web_view ? RenderViewImpl::FromWebView(web_view) : NULL; output_device_ = AudioDeviceFactory::NewOutputDevice( render_view ? render_view->routing_id() : MSG_ROUTING_NONE); - output_device_->Initialize(params_, this); + output_device_->InitializeUnifiedStream(params_, this, session_id_); output_device_->Start(); // Note: Default behavior is to auto-play on start. } diff --git a/content/renderer/media/renderer_webaudiodevice_impl.h b/content/renderer/media/renderer_webaudiodevice_impl.h index 23a46ab..5a8161f 100644 --- a/content/renderer/media/renderer_webaudiodevice_impl.h +++ b/content/renderer/media/renderer_webaudiodevice_impl.h @@ -23,7 +23,8 @@ class RendererWebAudioDeviceImpl public media::AudioRendererSink::RenderCallback { public: RendererWebAudioDeviceImpl(const media::AudioParameters& params, - WebKit::WebAudioDevice::RenderCallback* callback); + WebKit::WebAudioDevice::RenderCallback* callback, + int session_id); virtual ~RendererWebAudioDeviceImpl(); // WebKit::WebAudioDevice implementation. @@ -54,6 +55,9 @@ class RendererWebAudioDeviceImpl // When non-NULL, we are started. When NULL, we are stopped. scoped_refptr<media::AudioOutputDevice> output_device_; + // ID to allow browser to select the correct input device for unified IO. + int session_id_; + DISALLOW_COPY_AND_ASSIGN(RendererWebAudioDeviceImpl); }; diff --git a/content/renderer/media/webrtc_audio_device_impl.h b/content/renderer/media/webrtc_audio_device_impl.h index e740a59..960d0d0 100644 --- a/content/renderer/media/webrtc_audio_device_impl.h +++ b/content/renderer/media/webrtc_audio_device_impl.h @@ -24,13 +24,11 @@ // webrtc::AudioDeviceModule which makes it possible for a user (e.g. webrtc:: // VoiceEngine) to register this class as an external AudioDeviceModule (ADM). // Then WebRtcAudioDeviceImpl::SetSessionId() needs to be called to set the -// session id that tells which device to use. The user can either get the -// session id from the MediaStream or use a value of 1 (AudioInputDeviceManager -// ::kFakeOpenSessionId), the later will open the default device without going -// through the MediaStream. The user can then call WebRtcAudioDeviceImpl:: -// StartPlayout() and WebRtcAudioDeviceImpl::StartRecording() from the render -// process to initiate and start audio rendering and capturing in the browser -// process. IPC is utilized to set up the media streams. +// session id that tells which device to use. The user can then call +// WebRtcAudioDeviceImpl::StartPlayout() and +// WebRtcAudioDeviceImpl::StartRecording() from the render process to initiate +// and start audio rendering and capturing in the browser process. IPC is +// utilized to set up the media streams. // // Usage example: // @@ -39,7 +37,7 @@ // { // scoped_refptr<WebRtcAudioDeviceImpl> external_adm; // external_adm = new WebRtcAudioDeviceImpl(); -// external_adm->SetSessionId(1); +// external_adm->SetSessionId(session_id); // VoiceEngine* voe = VoiceEngine::Create(); // VoEBase* base = VoEBase::GetInterface(voe); // base->Init(external_adm); diff --git a/content/renderer/pepper/pepper_platform_audio_output_impl.cc b/content/renderer/pepper/pepper_platform_audio_output_impl.cc index e53dd6d..05600dd 100644 --- a/content/renderer/pepper/pepper_platform_audio_output_impl.cc +++ b/content/renderer/pepper/pepper_platform_audio_output_impl.cc @@ -138,8 +138,9 @@ void PepperPlatformAudioOutputImpl::InitializeOnIOThread( const media::AudioParameters& params) { DCHECK(ChildProcess::current()->io_message_loop_proxy()-> BelongsToCurrentThread()); + const int kSessionId = 0; if (ipc_) - ipc_->CreateStream(this, params); + ipc_->CreateStream(this, params, kSessionId); } void PepperPlatformAudioOutputImpl::StartPlaybackOnIOThread() { diff --git a/content/renderer/renderer_webkitplatformsupport_impl.cc b/content/renderer/renderer_webkitplatformsupport_impl.cc index 4efc1fa..f0b7910 100644 --- a/content/renderer/renderer_webkitplatformsupport_impl.cc +++ b/content/renderer/renderer_webkitplatformsupport_impl.cc @@ -10,6 +10,7 @@ #include "base/metrics/histogram.h" #include "base/platform_file.h" #include "base/shared_memory.h" +#include "base/string_number_conversions.h" #include "base/utf_string_conversions.h" #include "content/common/database_util.h" #include "content/common/file_utilities_messages.h" @@ -681,16 +682,6 @@ RendererWebKitPlatformSupportImpl::createAudioDevice( double sample_rate, WebAudioDevice::RenderCallback* callback, const WebKit::WebString& input_device_id) { - if (input_device_id != "default") { - // Only allow audio input if we know for sure that WebKit is giving us the - // "default" input device. - // TODO(crogers): add support for non-default audio input devices when - // using synchronized audio I/O in WebAudio. - if (input_channels > 0) - DLOG(WARNING) << "createAudioDevice(): request for audio input ignored"; - input_channels = 0; - } - // The |channels| does not exactly identify the channel layout of the // device. The switch statement below assigns a best guess to the channel // layout based on number of channels. @@ -726,12 +717,21 @@ RendererWebKitPlatformSupportImpl::createAudioDevice( layout = media::CHANNEL_LAYOUT_STEREO; } + int session_id = 0; + if (input_device_id.isNull() || + !base::StringToInt(UTF16ToUTF8(input_device_id), &session_id)) { + if (input_channels > 0) + DLOG(WARNING) << "createAudioDevice(): request for audio input ignored"; + + input_channels = 0; + } + media::AudioParameters params( media::AudioParameters::AUDIO_PCM_LOW_LATENCY, layout, input_channels, static_cast<int>(sample_rate), 16, buffer_size); - return new RendererWebAudioDeviceImpl(params, callback); + return new RendererWebAudioDeviceImpl(params, callback, session_id); } //------------------------------------------------------------------------------ diff --git a/content/test/webrtc_audio_device_test.cc b/content/test/webrtc_audio_device_test.cc index f6c5dd8..63fbf13 100644 --- a/content/test/webrtc_audio_device_test.cc +++ b/content/test/webrtc_audio_device_test.cc @@ -240,7 +240,7 @@ void WebRTCAudioDeviceTest::CreateChannel(const char* name) { static const int kRenderProcessId = 1; audio_render_host_ = new AudioRendererHost( kRenderProcessId, audio_manager_.get(), mirroring_manager_.get(), - media_internals_.get()); + media_internals_.get(), media_stream_manager_.get()); audio_render_host_->OnChannelConnected(base::GetCurrentProcId()); audio_input_renderer_host_ = new AudioInputRendererHost( diff --git a/media/audio/android/audio_manager_android.cc b/media/audio/android/audio_manager_android.cc index fa042b5..ce172b5 100644 --- a/media/audio/android/audio_manager_android.cc +++ b/media/audio/android/audio_manager_android.cc @@ -69,9 +69,9 @@ AudioParameters AudioManagerAndroid::GetInputStreamParameters( } AudioOutputStream* AudioManagerAndroid::MakeAudioOutputStream( - const AudioParameters& params) { + const AudioParameters& params, const std::string& input_device_id) { AudioOutputStream* stream = - AudioManagerBase::MakeAudioOutputStream(params); + AudioManagerBase::MakeAudioOutputStream(params, std::string()); if (stream && output_stream_count() == 1) RegisterHeadsetReceiver(); return stream; @@ -105,7 +105,7 @@ AudioOutputStream* AudioManagerAndroid::MakeLinearOutputStream( } AudioOutputStream* AudioManagerAndroid::MakeLowLatencyOutputStream( - const AudioParameters& params) { + const AudioParameters& params, const std::string& input_device_id) { DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); return new OpenSLESOutputStream(this, params); } diff --git a/media/audio/android/audio_manager_android.h b/media/audio/android/audio_manager_android.h index 422924f..fa1c373 100644 --- a/media/audio/android/audio_manager_android.h +++ b/media/audio/android/audio_manager_android.h @@ -24,7 +24,8 @@ class MEDIA_EXPORT AudioManagerAndroid : public AudioManagerBase { const std::string& device_id) OVERRIDE; virtual AudioOutputStream* MakeAudioOutputStream( - const AudioParameters& params) OVERRIDE; + const AudioParameters& params, + const std::string& input_device_id) OVERRIDE; virtual AudioInputStream* MakeAudioInputStream( const AudioParameters& params, const std::string& device_id) OVERRIDE; virtual void ReleaseOutputStream(AudioOutputStream* stream) OVERRIDE; @@ -34,7 +35,8 @@ class MEDIA_EXPORT AudioManagerAndroid : public AudioManagerBase { virtual AudioOutputStream* MakeLinearOutputStream( const AudioParameters& params) OVERRIDE; virtual AudioOutputStream* MakeLowLatencyOutputStream( - const AudioParameters& params) OVERRIDE; + 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( diff --git a/media/audio/audio_low_latency_input_output_unittest.cc b/media/audio/audio_low_latency_input_output_unittest.cc index 0dc434f..4dd22ab 100644 --- a/media/audio/audio_low_latency_input_output_unittest.cc +++ b/media/audio/audio_low_latency_input_output_unittest.cc @@ -309,7 +309,7 @@ class AudioOutputStreamTraits { static StreamType* CreateStream(AudioManager* audio_manager, const AudioParameters& params) { - return audio_manager->MakeAudioOutputStream(params); + return audio_manager->MakeAudioOutputStream(params, std::string()); } }; diff --git a/media/audio/audio_manager.h b/media/audio/audio_manager.h index a20af4a..b513ec9 100644 --- a/media/audio/audio_manager.h +++ b/media/audio/audio_manager.h @@ -82,14 +82,14 @@ class MEDIA_EXPORT AudioManager { // // Do not free the returned AudioOutputStream. It is owned by AudioManager. virtual AudioOutputStream* MakeAudioOutputStream( - const AudioParameters& params) = 0; + const AudioParameters& params, 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) = 0; + const AudioParameters& params, const std::string& input_device_id) = 0; // Factory to create audio recording streams. // |channels| can be 1 or 2. diff --git a/media/audio/audio_manager_base.cc b/media/audio/audio_manager_base.cc index 07c56b6..43dc31e2 100644 --- a/media/audio/audio_manager_base.cc +++ b/media/audio/audio_manager_base.cc @@ -32,6 +32,44 @@ static const int kMaxInputChannels = 2; const char AudioManagerBase::kDefaultDeviceName[] = "Default"; const char AudioManagerBase::kDefaultDeviceId[] = "default"; +struct AudioManagerBase::DispatcherParams { + DispatcherParams(const AudioParameters& input, + const AudioParameters& output, + const std::string& device_id) + : input_params(input), + output_params(output), + input_device_id(device_id) {} + ~DispatcherParams() {} + + const AudioParameters input_params; + const AudioParameters output_params; + const std::string input_device_id; + scoped_refptr<AudioOutputDispatcher> dispatcher; + + private: + DISALLOW_COPY_AND_ASSIGN(DispatcherParams); +}; + +class AudioManagerBase::CompareByParams { + public: + explicit CompareByParams(const DispatcherParams* dispatcher) + : dispatcher_(dispatcher) {} + bool operator()(DispatcherParams* dispatcher_in) const { + // We will reuse the existing dispatcher when: + // 1) Unified IO is not used, input_params and output_params of the + // existing dispatcher are the same as the requested dispatcher. + // 2) Unified IO is used, input_params, output_params and input_device_id + // 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_->input_params.input_channels() || + dispatcher_->input_device_id == dispatcher_in->input_device_id)); + } + + private: + const DispatcherParams* dispatcher_; +}; + AudioManagerBase::AudioManagerBase() : num_active_input_streams_(0), max_num_output_streams_(kDefaultMaxOutputStreams), @@ -77,7 +115,8 @@ scoped_refptr<base::MessageLoopProxy> AudioManagerBase::GetMessageLoop() { } AudioOutputStream* AudioManagerBase::MakeAudioOutputStream( - const AudioParameters& params) { + const AudioParameters& params, + 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: // DCHECK(message_loop_->BelongsToCurrentThread()); @@ -105,7 +144,7 @@ AudioOutputStream* AudioManagerBase::MakeAudioOutputStream( stream = MakeLinearOutputStream(params); break; case AudioParameters::AUDIO_PCM_LOW_LATENCY: - stream = MakeLowLatencyOutputStream(params); + stream = MakeLowLatencyOutputStream(params, input_device_id); break; case AudioParameters::AUDIO_FAKE: stream = FakeAudioOutputStream::MakeFakeStream(this, params); @@ -165,7 +204,7 @@ AudioInputStream* AudioManagerBase::MakeAudioInputStream( } AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy( - const AudioParameters& params) { + const AudioParameters& params, const std::string& input_device_id) { #if defined(OS_IOS) // IOS implements audio input only. NOTIMPLEMENTED(); @@ -199,26 +238,33 @@ AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy( } } - std::pair<AudioParameters, AudioParameters> dispatcher_key = - std::make_pair(params, output_params); - AudioOutputDispatchersMap::iterator it = - output_dispatchers_.find(dispatcher_key); - if (it != output_dispatchers_.end()) - return new AudioOutputProxy(it->second.get()); + DispatcherParams* dispatcher_params = + new DispatcherParams(params, output_params, input_device_id); + + AudioOutputDispatchers::iterator it = + std::find_if(output_dispatchers_.begin(), output_dispatchers_.end(), + CompareByParams(dispatcher_params)); + if (it != output_dispatchers_.end()) { + delete dispatcher_params; + return new AudioOutputProxy((*it)->dispatcher); + } const base::TimeDelta kCloseDelay = base::TimeDelta::FromSeconds(kStreamCloseDelaySeconds); if (output_params.format() != AudioParameters::AUDIO_FAKE) { scoped_refptr<AudioOutputDispatcher> dispatcher = - new AudioOutputResampler(this, params, output_params, kCloseDelay); - output_dispatchers_[dispatcher_key] = dispatcher; + new AudioOutputResampler(this, params, output_params, input_device_id, + kCloseDelay); + dispatcher_params->dispatcher = dispatcher; return new AudioOutputProxy(dispatcher.get()); } scoped_refptr<AudioOutputDispatcher> dispatcher = - new AudioOutputDispatcherImpl(this, output_params, kCloseDelay); - output_dispatchers_[dispatcher_key] = dispatcher; + new AudioOutputDispatcherImpl(this, output_params, input_device_id, + kCloseDelay); + dispatcher_params->dispatcher = dispatcher; + output_dispatchers_.push_back(dispatcher_params); return new AudioOutputProxy(dispatcher.get()); #endif // defined(OS_IOS) } @@ -292,9 +338,9 @@ void AudioManagerBase::ShutdownOnAudioThread() { // 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 // called from one place, so we'll leave it at that. - AudioOutputDispatchersMap::iterator it = output_dispatchers_.begin(); + AudioOutputDispatchers::iterator it = output_dispatchers_.begin(); for (; it != output_dispatchers_.end(); ++it) { - scoped_refptr<AudioOutputDispatcher>& dispatcher = (*it).second; + scoped_refptr<AudioOutputDispatcher>& dispatcher = (*it)->dispatcher; if (dispatcher.get()) { dispatcher->Shutdown(); // All AudioOutputProxies must have been freed before Shutdown is called. diff --git a/media/audio/audio_manager_base.h b/media/audio/audio_manager_base.h index 3d75b77..d266253 100644 --- a/media/audio/audio_manager_base.h +++ b/media/audio/audio_manager_base.h @@ -5,17 +5,19 @@ #ifndef MEDIA_AUDIO_AUDIO_MANAGER_BASE_H_ #define MEDIA_AUDIO_AUDIO_MANAGER_BASE_H_ -#include <map> #include <string> #include <utility> #include "base/atomic_ref_count.h" #include "base/compiler_specific.h" #include "base/memory/scoped_ptr.h" +#include "base/memory/scoped_vector.h" #include "base/observer_list.h" #include "base/synchronization/lock.h" #include "media/audio/audio_manager.h" +#include "media/audio/audio_output_dispatcher.h" + #if defined(OS_WIN) #include "base/win/scoped_com_initializer.h" #endif @@ -48,13 +50,15 @@ class MEDIA_EXPORT AudioManagerBase : public AudioManager { media::AudioDeviceNames* device_names) OVERRIDE; virtual AudioOutputStream* MakeAudioOutputStream( - const AudioParameters& params) OVERRIDE; + const AudioParameters& params, + const std::string& input_device_id) OVERRIDE; virtual AudioInputStream* MakeAudioInputStream( const AudioParameters& params, const std::string& device_id) OVERRIDE; virtual AudioOutputStream* MakeAudioOutputStreamProxy( - const AudioParameters& params) OVERRIDE; + const AudioParameters& params, + const std::string& input_device_id) OVERRIDE; virtual bool IsRecordingInProcess() OVERRIDE; @@ -71,8 +75,9 @@ class MEDIA_EXPORT AudioManagerBase : public AudioManager { const AudioParameters& params) = 0; // 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) = 0; + const AudioParameters& params, 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|. @@ -96,12 +101,6 @@ class MEDIA_EXPORT AudioManagerBase : public AudioManager { protected: AudioManagerBase(); - // TODO(dalecurtis): This must change to map both input and output parameters - // to a single dispatcher, otherwise on a device state change we'll just get - // the exact same invalid dispatcher. - typedef std::map<std::pair<AudioParameters, AudioParameters>, - scoped_refptr<AudioOutputDispatcher> > - AudioOutputDispatchersMap; // Shuts down the audio thread and releases all the audio output dispatchers // on the audio thread. All audio streams should be freed before Shutdown() @@ -124,15 +123,16 @@ class MEDIA_EXPORT AudioManagerBase : public AudioManager { virtual AudioParameters GetPreferredOutputStreamParameters( const AudioParameters& input_params) = 0; - // Map of cached AudioOutputDispatcher instances. Must only be touched - // from the audio thread (no locking). - AudioOutputDispatchersMap output_dispatchers_; - // Get number of input or output streams. int input_stream_count() { return num_input_streams_; } int output_stream_count() { return num_output_streams_; } private: + struct DispatcherParams; + typedef ScopedVector<DispatcherParams> AudioOutputDispatchers; + + class CompareByParams; + // Called by Shutdown(). void ShutdownOnAudioThread(); @@ -165,6 +165,10 @@ class MEDIA_EXPORT AudioManagerBase : public AudioManager { // and GetMessageLoop() starts returning NULL. scoped_refptr<base::MessageLoopProxy> message_loop_; + // Map of cached AudioOutputDispatcher instances. Must only be touched + // from the audio thread (no locking). + AudioOutputDispatchers output_dispatchers_; + DISALLOW_COPY_AND_ASSIGN(AudioManagerBase); }; diff --git a/media/audio/audio_output_controller.cc b/media/audio/audio_output_controller.cc index 9194bcf..8e33c7f 100644 --- a/media/audio/audio_output_controller.cc +++ b/media/audio/audio_output_controller.cc @@ -39,10 +39,12 @@ const int AudioOutputController::kPollPauseInMilliseconds = 3; AudioOutputController::AudioOutputController(AudioManager* audio_manager, EventHandler* handler, const AudioParameters& params, + const std::string& input_device_id, SyncReader* sync_reader) : audio_manager_(audio_manager), params_(params), handler_(handler), + input_device_id_(input_device_id), stream_(NULL), diverting_to_stream_(NULL), volume_(1.0), @@ -67,6 +69,7 @@ scoped_refptr<AudioOutputController> AudioOutputController::Create( AudioManager* audio_manager, EventHandler* event_handler, const AudioParameters& params, + const std::string& input_device_id, SyncReader* sync_reader) { DCHECK(audio_manager); DCHECK(sync_reader); @@ -75,7 +78,7 @@ scoped_refptr<AudioOutputController> AudioOutputController::Create( return NULL; scoped_refptr<AudioOutputController> controller(new AudioOutputController( - audio_manager, event_handler, params, sync_reader)); + audio_manager, event_handler, params, input_device_id, sync_reader)); controller->message_loop_->PostTask(FROM_HERE, base::Bind( &AudioOutputController::DoCreate, controller, false)); return controller; @@ -114,7 +117,7 @@ void AudioOutputController::DoCreate(bool is_for_device_change) { DCHECK_EQ(kEmpty, state_); stream_ = diverting_to_stream_ ? diverting_to_stream_ : - audio_manager_->MakeAudioOutputStreamProxy(params_); + audio_manager_->MakeAudioOutputStreamProxy(params_, 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 0a83bae..1e56633 100644 --- a/media/audio/audio_output_controller.h +++ b/media/audio/audio_output_controller.h @@ -112,7 +112,8 @@ class MEDIA_EXPORT AudioOutputController // outlive AudioOutputController. static scoped_refptr<AudioOutputController> Create( AudioManager* audio_manager, EventHandler* event_handler, - const AudioParameters& params, SyncReader* sync_reader); + const AudioParameters& params, const std::string& input_device_id, + SyncReader* sync_reader); // Methods to control playback of the stream. @@ -177,7 +178,9 @@ class MEDIA_EXPORT AudioOutputController static const int kPollPauseInMilliseconds; AudioOutputController(AudioManager* audio_manager, EventHandler* handler, - const AudioParameters& params, SyncReader* sync_reader); + const AudioParameters& params, + const std::string& input_device_id, + SyncReader* sync_reader); // The following methods are executed on the audio manager thread. void DoCreate(bool is_for_device_change); @@ -210,6 +213,9 @@ class MEDIA_EXPORT AudioOutputController const AudioParameters params_; EventHandler* const handler_; + // Used by the unified IO to open the correct input device. + std::string input_device_id_; + // Note: It's important to invalidate the weak pointers whenever stream_ is // changed. See comment for weak_this_. AudioOutputStream* stream_; diff --git a/media/audio/audio_output_controller_unittest.cc b/media/audio/audio_output_controller_unittest.cc index 20a56a2..c2630b0 100644 --- a/media/audio/audio_output_controller_unittest.cc +++ b/media/audio/audio_output_controller_unittest.cc @@ -122,7 +122,7 @@ class AudioOutputControllerTest : public testing::Test { } controller_ = AudioOutputController::Create( - audio_manager_.get(), &mock_event_handler_, params_, + audio_manager_.get(), &mock_event_handler_, params_, std::string(), &mock_sync_reader_); if (controller_.get()) controller_->SetVolume(kTestVolume); diff --git a/media/audio/audio_output_device.cc b/media/audio/audio_output_device.cc index 192823a..b0319df 100644 --- a/media/audio/audio_output_device.cc +++ b/media/audio/audio_output_device.cc @@ -48,6 +48,7 @@ AudioOutputDevice::AudioOutputDevice( ipc_(ipc.Pass()), state_(IDLE), play_on_start_(true), + session_id_(-1), stopping_hack_(false) { CHECK(ipc_); @@ -59,12 +60,19 @@ AudioOutputDevice::AudioOutputDevice( COMPILE_ASSERT(PAUSED < PLAYING, invalid_enum_value_assignment_3); } -void AudioOutputDevice::Initialize(const AudioParameters& params, - RenderCallback* callback) { - DCHECK(!callback_) << "Calling Initialize() twice?"; +void AudioOutputDevice::InitializeUnifiedStream(const AudioParameters& params, + RenderCallback* callback, + int session_id) { + DCHECK(!callback_) << "Calling InitializeUnifiedStream() twice?"; DCHECK(params.IsValid()); audio_parameters_ = params; callback_ = callback; + session_id_ = session_id; +} + +void AudioOutputDevice::Initialize(const AudioParameters& params, + RenderCallback* callback) { + InitializeUnifiedStream(params, callback, 0); } AudioOutputDevice::~AudioOutputDevice() { @@ -117,7 +125,7 @@ void AudioOutputDevice::CreateStreamOnIOThread(const AudioParameters& params) { DCHECK(message_loop()->BelongsToCurrentThread()); if (state_ == IDLE) { state_ = CREATING_STREAM; - ipc_->CreateStream(this, params); + ipc_->CreateStream(this, params, session_id_); } } diff --git a/media/audio/audio_output_device.h b/media/audio/audio_output_device.h index a16b9ed..2af4f48 100644 --- a/media/audio/audio_output_device.h +++ b/media/audio/audio_output_device.h @@ -81,6 +81,18 @@ class MEDIA_EXPORT AudioOutputDevice AudioOutputDevice(scoped_ptr<AudioOutputIPC> ipc, const scoped_refptr<base::MessageLoopProxy>& io_loop); + // Initialize function for clients wishing to have unified input and + // output, |params| may specify |input_channels| > 0, representing a + // number of input channels which will be at the same sample-rate + // and buffer-size as the output as specified in |params|. |session_id| is + // used for the browser to select the correct input device. + // In this case, the callback's RenderIO() method will be called instead + // of Render(), providing the synchronized input data at the same time as + // when new output data is to be rendered. + void InitializeUnifiedStream(const AudioParameters& params, + RenderCallback* callback, + int session_id); + // AudioRendererSink implementation. virtual void Initialize(const AudioParameters& params, RenderCallback* callback) OVERRIDE; @@ -144,6 +156,10 @@ class MEDIA_EXPORT AudioOutputDevice // State of Play() / Pause() calls before OnStreamCreated() is called. bool play_on_start_; + // The media session ID used to identify which input device to be started. + // Only used by Unified IO. + int session_id_; + // Our audio thread callback class. See source file for details. class AudioThreadCallback; diff --git a/media/audio/audio_output_device_unittest.cc b/media/audio/audio_output_device_unittest.cc index 4605e63..5616ff9 100644 --- a/media/audio/audio_output_device_unittest.cc +++ b/media/audio/audio_output_device_unittest.cc @@ -49,8 +49,9 @@ class MockAudioOutputIPC : public AudioOutputIPC { MockAudioOutputIPC() {} virtual ~MockAudioOutputIPC() {} - MOCK_METHOD2(CreateStream, void(AudioOutputIPCDelegate* delegate, - const AudioParameters& params)); + MOCK_METHOD3(CreateStream, void(AudioOutputIPCDelegate* delegate, + const AudioParameters& params, + int session_id)); MOCK_METHOD0(PlayStream, void()); MOCK_METHOD0(PauseStream, void()); MOCK_METHOD0(CloseStream, void()); @@ -169,7 +170,7 @@ AudioOutputDeviceTest::~AudioOutputDeviceTest() { void AudioOutputDeviceTest::StartAudioDevice() { audio_device_->Start(); - EXPECT_CALL(*audio_output_ipc_, CreateStream(audio_device_.get(), _)); + EXPECT_CALL(*audio_output_ipc_, CreateStream(audio_device_.get(), _, 0)); io_loop_.RunUntilIdle(); } diff --git a/media/audio/audio_output_dispatcher.cc b/media/audio/audio_output_dispatcher.cc index be9cb57..de30b1c 100644 --- a/media/audio/audio_output_dispatcher.cc +++ b/media/audio/audio_output_dispatcher.cc @@ -10,10 +10,12 @@ namespace media { AudioOutputDispatcher::AudioOutputDispatcher( AudioManager* audio_manager, - const AudioParameters& params) + const AudioParameters& params, + const std::string& input_device_id) : audio_manager_(audio_manager), message_loop_(base::MessageLoop::current()), - params_(params) { + params_(params), + 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! DCHECK(audio_manager->GetMessageLoop()->BelongsToCurrentThread()); diff --git a/media/audio/audio_output_dispatcher.h b/media/audio/audio_output_dispatcher.h index e07d181..98dc89b 100644 --- a/media/audio/audio_output_dispatcher.h +++ b/media/audio/audio_output_dispatcher.h @@ -37,7 +37,8 @@ class MEDIA_EXPORT AudioOutputDispatcher : public base::RefCountedThreadSafe<AudioOutputDispatcher> { public: AudioOutputDispatcher(AudioManager* audio_manager, - const AudioParameters& params); + const AudioParameters& params, + const std::string& input_device_id); // Called by AudioOutputProxy to open the stream. // Returns false, if it fails to open it. @@ -64,6 +65,9 @@ class MEDIA_EXPORT AudioOutputDispatcher // Called on the audio thread when the AudioManager is shutting down. virtual void Shutdown() = 0; + // Accessor to the input device id used by unified IO. + const std::string& input_device_id() const { return input_device_id_; } + protected: friend class base::RefCountedThreadSafe<AudioOutputDispatcher>; friend class AudioOutputProxyTest; @@ -75,6 +79,7 @@ class MEDIA_EXPORT AudioOutputDispatcher AudioManager* audio_manager_; base::MessageLoop* message_loop_; AudioParameters params_; + const std::string input_device_id_; private: DISALLOW_COPY_AND_ASSIGN(AudioOutputDispatcher); diff --git a/media/audio/audio_output_dispatcher_impl.cc b/media/audio/audio_output_dispatcher_impl.cc index 046bdd8..17f14c2 100644 --- a/media/audio/audio_output_dispatcher_impl.cc +++ b/media/audio/audio_output_dispatcher_impl.cc @@ -19,8 +19,9 @@ namespace media { AudioOutputDispatcherImpl::AudioOutputDispatcherImpl( AudioManager* audio_manager, const AudioParameters& params, + const std::string& input_device_id, const base::TimeDelta& close_delay) - : AudioOutputDispatcher(audio_manager, params), + : AudioOutputDispatcher(audio_manager, params, input_device_id), pause_delay_(base::TimeDelta::FromMicroseconds( 2 * params.frames_per_buffer() * base::Time::kMicrosecondsPerSecond / static_cast<float>(params.sample_rate()))), @@ -166,7 +167,8 @@ void AudioOutputDispatcherImpl::Shutdown() { bool AudioOutputDispatcherImpl::CreateAndOpenStream() { DCHECK_EQ(base::MessageLoop::current(), message_loop_); - AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream(params_); + AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream( + params_, 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 85a84f7..90ac5db 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& input_device_id, const base::TimeDelta& close_delay); // Opens a new physical stream if there are no pending streams in diff --git a/media/audio/audio_output_ipc.h b/media/audio/audio_output_ipc.h index 78cf2e7..84f8c6a 100644 --- a/media/audio/audio_output_ipc.h +++ b/media/audio/audio_output_ipc.h @@ -61,10 +61,13 @@ class MEDIA_EXPORT AudioOutputIPC { // Sends a request to create an AudioOutputController object in the peer // process and configures it to use the specified audio |params| including - // number of synchronized input channels. Once the stream has been created, + // number of synchronized input channels.|session_id| is used by the browser + // to select the correct input device if the input channel in |params| is + // valid, otherwise it will be ignored. Once the stream has been created, // the implementation will notify |delegate| by calling OnStreamCreated(). virtual void CreateStream(AudioOutputIPCDelegate* delegate, - const AudioParameters& params) = 0; + const AudioParameters& params, + int session_id) = 0; // Starts playing the stream. This should generate a call to // AudioOutputController::Play(). diff --git a/media/audio/audio_output_proxy_unittest.cc b/media/audio/audio_output_proxy_unittest.cc index d55f726..fc09f1e 100644 --- a/media/audio/audio_output_proxy_unittest.cc +++ b/media/audio/audio_output_proxy_unittest.cc @@ -95,10 +95,10 @@ class MockAudioManager : public AudioManagerBase { MOCK_METHOD0(HasAudioOutputDevices, bool()); MOCK_METHOD0(HasAudioInputDevices, bool()); MOCK_METHOD0(GetAudioInputDeviceModel, string16()); - MOCK_METHOD1(MakeAudioOutputStream, AudioOutputStream*( - const AudioParameters& params)); - MOCK_METHOD1(MakeAudioOutputStreamProxy, AudioOutputStream*( - const AudioParameters& params)); + 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_METHOD2(MakeAudioInputStream, AudioInputStream*( const AudioParameters& params, const std::string& device_id)); MOCK_METHOD0(ShowAudioInputSettings, void()); @@ -109,8 +109,8 @@ class MockAudioManager : public AudioManagerBase { MOCK_METHOD1(MakeLinearOutputStream, AudioOutputStream*( const AudioParameters& params)); - MOCK_METHOD1(MakeLowLatencyOutputStream, AudioOutputStream*( - const AudioParameters& params)); + MOCK_METHOD2(MakeLowLatencyOutputStream, AudioOutputStream*( + const AudioParameters& params, const std::string& input_device_id)); MOCK_METHOD2(MakeLinearInputStream, AudioInputStream*( const AudioParameters& params, const std::string& device_id)); MOCK_METHOD2(MakeLowLatencyInputStream, AudioInputStream*( @@ -161,6 +161,7 @@ class AudioOutputProxyTest : public testing::Test { CHANNEL_LAYOUT_STEREO, 8000, 16, 2048); dispatcher_impl_ = new AudioOutputDispatcherImpl(&manager(), params_, + std::string(), close_delay); // Necessary to know how long the dispatcher will wait before posting @@ -186,7 +187,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 +204,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 +230,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 +262,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 +284,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 +302,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 +329,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 +367,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 +407,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 +426,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 +468,7 @@ class AudioOutputResamplerTest : public AudioOutputProxyTest { AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, 16000, 16, 1024); resampler_ = new AudioOutputResampler( - &manager(), params_, resampler_params_, close_delay); + &manager(), params_, resampler_params_, std::string(), close_delay); } virtual void OnStart() OVERRIDE { @@ -568,7 +569,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 +589,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 +620,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))); @@ -629,7 +630,8 @@ TEST_F(AudioOutputResamplerTest, HighLatencyFallbackFailed) { testing::Property(&AudioParameters::format, AudioParameters::AUDIO_FAKE), testing::Property(&AudioParameters::sample_rate, params_.sample_rate()), testing::Property( - &AudioParameters::frames_per_buffer, params_.frames_per_buffer())))) + &AudioParameters::frames_per_buffer, params_.frames_per_buffer())), + _)) .Times(1) .WillOnce(Return(&okay_stream)); EXPECT_CALL(okay_stream, Open()) @@ -654,7 +656,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))); @@ -672,7 +674,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 6750efc..ea1848e 100644 --- a/media/audio/audio_output_resampler.cc +++ b/media/audio/audio_output_resampler.cc @@ -148,10 +148,12 @@ static AudioParameters SetupFallbackParams( AudioOutputResampler::AudioOutputResampler(AudioManager* audio_manager, const AudioParameters& input_params, const AudioParameters& output_params, + const std::string& input_device_id, const base::TimeDelta& close_delay) - : AudioOutputDispatcher(audio_manager, input_params), + : AudioOutputDispatcher(audio_manager, input_params, 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()); @@ -171,7 +173,7 @@ void AudioOutputResampler::Initialize() { DCHECK(!streams_opened_); DCHECK(callbacks_.empty()); dispatcher_ = new AudioOutputDispatcherImpl( - audio_manager_, output_params_, close_delay_); + audio_manager_, output_params_, 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 057cf34..e2633da 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& input_device_id, const base::TimeDelta& close_delay); // AudioOutputDispatcher interface. @@ -73,6 +74,9 @@ 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/audio_parameters.h b/media/audio/audio_parameters.h index dcc9eae..02a6f96 100644 --- a/media/audio/audio_parameters.h +++ b/media/audio/audio_parameters.h @@ -79,6 +79,16 @@ class MEDIA_EXPORT AudioParameters { // Set to CHANNEL_LAYOUT_DISCRETE with given number of channels. void SetDiscreteChannels(int channels); + // Comparison with other AudioParams. + bool operator==(const AudioParameters& other) const { + return format_ == other.format() && + channel_layout_ == other.channel_layout() && + channels_ == other.channels() && + input_channels_ == other.input_channels() && + bits_per_sample_ == other.bits_per_sample() && + frames_per_buffer_ == other.frames_per_buffer(); + } + private: Format format_; // Format of the stream. ChannelLayout channel_layout_; // Order of surround sound channels. diff --git a/media/audio/cras/audio_manager_cras.cc b/media/audio/cras/audio_manager_cras.cc index 52fb97e..e1a140e 100644 --- a/media/audio/cras/audio_manager_cras.cc +++ b/media/audio/cras/audio_manager_cras.cc @@ -74,8 +74,9 @@ AudioOutputStream* AudioManagerCras::MakeLinearOutputStream( } AudioOutputStream* AudioManagerCras::MakeLowLatencyOutputStream( - const AudioParameters& params) { + const AudioParameters& params, const std::string& input_device_id) { DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); + // TODO(dgreid): Open the correct input device for unified IO. return MakeOutputStream(params); } diff --git a/media/audio/cras/audio_manager_cras.h b/media/audio/cras/audio_manager_cras.h index 2c38c8e..4e69c8f 100644 --- a/media/audio/cras/audio_manager_cras.h +++ b/media/audio/cras/audio_manager_cras.h @@ -30,7 +30,8 @@ class MEDIA_EXPORT AudioManagerCras : public AudioManagerBase { virtual AudioOutputStream* MakeLinearOutputStream( const AudioParameters& params) OVERRIDE; virtual AudioOutputStream* MakeLowLatencyOutputStream( - const AudioParameters& params) OVERRIDE; + 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( diff --git a/media/audio/ios/audio_manager_ios.h b/media/audio/ios/audio_manager_ios.h index 1c4013a..1975150 100644 --- a/media/audio/ios/audio_manager_ios.h +++ b/media/audio/ios/audio_manager_ios.h @@ -21,7 +21,8 @@ class MEDIA_EXPORT AudioManagerIOS : public AudioManagerBase { virtual bool HasAudioOutputDevices() OVERRIDE; virtual bool HasAudioInputDevices() OVERRIDE; virtual AudioOutputStream* MakeAudioOutputStream( - const AudioParameters& params) OVERRIDE; + 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( @@ -31,7 +32,8 @@ class MEDIA_EXPORT AudioManagerIOS : public AudioManagerBase { virtual AudioOutputStream* MakeLinearOutputStream( const AudioParameters& params) OVERRIDE; virtual AudioOutputStream* MakeLowLatencyOutputStream( - const AudioParameters& params) OVERRIDE; + 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( diff --git a/media/audio/ios/audio_manager_ios.mm b/media/audio/ios/audio_manager_ios.mm index 0e0a194..4947930 100644 --- a/media/audio/ios/audio_manager_ios.mm +++ b/media/audio/ios/audio_manager_ios.mm @@ -62,7 +62,7 @@ AudioParameters AudioManagerIOS::GetInputStreamParameters( } AudioOutputStream* AudioManagerIOS::MakeAudioOutputStream( - const AudioParameters& params) { + const AudioParameters& params, const std::string& input_device_id) { NOTIMPLEMENTED(); // Only input is supported on iOS. return NULL; } @@ -82,24 +82,24 @@ AudioInputStream* AudioManagerIOS::MakeAudioInputStream( } AudioOutputStream* AudioManagerIOS::MakeLinearOutputStream( - const AudioParameters& params) { + const AudioParameters& params) { NOTIMPLEMENTED(); // Only input is supported on iOS. return NULL; } AudioOutputStream* AudioManagerIOS::MakeLowLatencyOutputStream( - const AudioParameters& params) { + 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) { + const AudioParameters& params, const std::string& device_id) { return MakeAudioInputStream(params, device_id); } AudioInputStream* AudioManagerIOS::MakeLowLatencyInputStream( - const AudioParameters& params, const std::string& device_id) { + const AudioParameters& params, const std::string& device_id) { NOTIMPLEMENTED(); // Only linear audio input is supported on iOS. return MakeAudioInputStream(params, device_id); } diff --git a/media/audio/linux/alsa_output_unittest.cc b/media/audio/linux/alsa_output_unittest.cc index 0dc19f5..02cbd42 100644 --- a/media/audio/linux/alsa_output_unittest.cc +++ b/media/audio/linux/alsa_output_unittest.cc @@ -83,8 +83,8 @@ class MockAudioManagerLinux : public AudioManagerLinux { MOCK_METHOD0(HasAudioInputDevices, bool()); MOCK_METHOD1(MakeLinearOutputStream, AudioOutputStream*( const AudioParameters& params)); - MOCK_METHOD1(MakeLowLatencyOutputStream, AudioOutputStream*( - const AudioParameters& params)); + MOCK_METHOD2(MakeLowLatencyOutputStream, AudioOutputStream*( + const AudioParameters& params, 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 c898f81..3115523 100644 --- a/media/audio/linux/audio_manager_linux.cc +++ b/media/audio/linux/audio_manager_linux.cc @@ -256,8 +256,10 @@ AudioOutputStream* AudioManagerLinux::MakeLinearOutputStream( } AudioOutputStream* AudioManagerLinux::MakeLowLatencyOutputStream( - const AudioParameters& params) { + const AudioParameters& params, + const std::string& input_device_id) { DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); + // TODO(xians): Use input_device_id for unified IO. return MakeOutputStream(params); } diff --git a/media/audio/linux/audio_manager_linux.h b/media/audio/linux/audio_manager_linux.h index 4c89773..28abaa1 100644 --- a/media/audio/linux/audio_manager_linux.h +++ b/media/audio/linux/audio_manager_linux.h @@ -34,7 +34,8 @@ class MEDIA_EXPORT AudioManagerLinux : public AudioManagerBase { virtual AudioOutputStream* MakeLinearOutputStream( const AudioParameters& params) OVERRIDE; virtual AudioOutputStream* MakeLowLatencyOutputStream( - const AudioParameters& params) OVERRIDE; + 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( diff --git a/media/audio/mac/audio_auhal_mac_unittest.cc b/media/audio/mac/audio_auhal_mac_unittest.cc index cab8c28..b4cf8c6 100644 --- a/media/audio/mac/audio_auhal_mac_unittest.cc +++ b/media/audio/mac/audio_auhal_mac_unittest.cc @@ -100,7 +100,8 @@ class AudioOutputStreamWrapper { sample_rate_, bits_per_sample_, samples_per_packet_); - AudioOutputStream* aos = audio_man_->MakeAudioOutputStream(params); + AudioOutputStream* aos = audio_man_->MakeAudioOutputStream(params, + std::string()); EXPECT_TRUE(aos); return aos; } diff --git a/media/audio/mac/audio_manager_mac.cc b/media/audio/mac/audio_manager_mac.cc index 3671317..33dcff0 100644 --- a/media/audio/mac/audio_manager_mac.cc +++ b/media/audio/mac/audio_manager_mac.cc @@ -421,11 +421,11 @@ AudioParameters AudioManagerMac::GetInputStreamParameters( AudioOutputStream* AudioManagerMac::MakeLinearOutputStream( const AudioParameters& params) { - return MakeLowLatencyOutputStream(params); + return MakeLowLatencyOutputStream(params, std::string()); } AudioOutputStream* AudioManagerMac::MakeLowLatencyOutputStream( - const AudioParameters& params) { + const AudioParameters& params, const std::string& input_device_id) { // Handle basic output with no input channels. if (params.input_channels() == 0) { AudioDeviceID device = kAudioObjectUnknown; @@ -462,7 +462,8 @@ AudioOutputStream* AudioManagerMac::MakeLowLatencyOutputStream( LOG(INFO) << "Using AGGREGATE audio device"; } - if (device != kAudioObjectUnknown) + if (device != kAudioObjectUnknown && + input_device_id == AudioManagerBase::kDefaultDeviceId) return new AUHALStream(this, params, device); // Fallback to AudioSynchronizedStream which will handle completely @@ -471,9 +472,13 @@ AudioOutputStream* AudioManagerMac::MakeLowLatencyOutputStream( // kAudioDeviceUnknown translates to "use default" here. // TODO(crogers): consider tracking UMA stats on AUHALStream // versus AudioSynchronizedStream. + AudioDeviceID audio_device_id = GetAudioDeviceIdByUId(true, input_device_id); + if (audio_device_id == kAudioObjectUnknown) + return NULL; + return new AudioSynchronizedStream(this, params, - kAudioDeviceUnknown, + audio_device_id, kAudioDeviceUnknown); } diff --git a/media/audio/mac/audio_manager_mac.h b/media/audio/mac/audio_manager_mac.h index af867d8..0691ec2 100644 --- a/media/audio/mac/audio_manager_mac.h +++ b/media/audio/mac/audio_manager_mac.h @@ -36,7 +36,8 @@ class MEDIA_EXPORT AudioManagerMac : public AudioManagerBase { virtual AudioOutputStream* MakeLinearOutputStream( const AudioParameters& params) OVERRIDE; virtual AudioOutputStream* MakeLowLatencyOutputStream( - const AudioParameters& params) OVERRIDE; + 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( diff --git a/media/audio/mock_audio_manager.cc b/media/audio/mock_audio_manager.cc index 1209e19..49bc8d1 100644 --- a/media/audio/mock_audio_manager.cc +++ b/media/audio/mock_audio_manager.cc @@ -37,13 +37,15 @@ void MockAudioManager::GetAudioInputDeviceNames( } media::AudioOutputStream* MockAudioManager::MakeAudioOutputStream( - const media::AudioParameters& params) { + const media::AudioParameters& params, + const std::string& input_device_id) { NOTREACHED(); return NULL; } media::AudioOutputStream* MockAudioManager::MakeAudioOutputStreamProxy( - const media::AudioParameters& params) { + const media::AudioParameters& params, + const std::string& input_device_id) { NOTREACHED(); return NULL; } diff --git a/media/audio/mock_audio_manager.h b/media/audio/mock_audio_manager.h index 3a0e907..8042eda 100644 --- a/media/audio/mock_audio_manager.h +++ b/media/audio/mock_audio_manager.h @@ -35,10 +35,12 @@ class MockAudioManager : public media::AudioManager { media::AudioDeviceNames* device_names) OVERRIDE; virtual media::AudioOutputStream* MakeAudioOutputStream( - const media::AudioParameters& params) OVERRIDE; + const media::AudioParameters& params, + const std::string& input_device_id) OVERRIDE; virtual media::AudioOutputStream* MakeAudioOutputStreamProxy( - const media::AudioParameters& params) OVERRIDE; + const media::AudioParameters& params, + const std::string& input_device_id) OVERRIDE; virtual media::AudioInputStream* MakeAudioInputStream( const media::AudioParameters& params, diff --git a/media/audio/openbsd/audio_manager_openbsd.cc b/media/audio/openbsd/audio_manager_openbsd.cc index 681f219..4005aeb 100644 --- a/media/audio/openbsd/audio_manager_openbsd.cc +++ b/media/audio/openbsd/audio_manager_openbsd.cc @@ -91,7 +91,8 @@ AudioOutputStream* AudioManagerOpenBSD::MakeLinearOutputStream( } AudioOutputStream* AudioManagerOpenBSD::MakeLowLatencyOutputStream( - const AudioParameters& params) { + const AudioParameters& params, + const std::string& input_device_id) { DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format); return MakeOutputStream(params); } diff --git a/media/audio/openbsd/audio_manager_openbsd.h b/media/audio/openbsd/audio_manager_openbsd.h index d981612..a1adcb6 100644 --- a/media/audio/openbsd/audio_manager_openbsd.h +++ b/media/audio/openbsd/audio_manager_openbsd.h @@ -26,7 +26,8 @@ class MEDIA_EXPORT AudioManagerOpenBSD : public AudioManagerBase { virtual AudioOutputStream* MakeLinearOutputStream( const AudioParameters& params) OVERRIDE; virtual AudioOutputStream* MakeLowLatencyOutputStream( - const AudioParameters& params) OVERRIDE; + 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( diff --git a/media/audio/pulse/audio_manager_pulse.cc b/media/audio/pulse/audio_manager_pulse.cc index fed919a..3dcdd89 100644 --- a/media/audio/pulse/audio_manager_pulse.cc +++ b/media/audio/pulse/audio_manager_pulse.cc @@ -112,13 +112,13 @@ AudioParameters AudioManagerPulse::GetInputStreamParameters( AudioOutputStream* AudioManagerPulse::MakeLinearOutputStream( const AudioParameters& params) { DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); - return MakeOutputStream(params); + return MakeOutputStream(params, std::string()); } AudioOutputStream* AudioManagerPulse::MakeLowLatencyOutputStream( - const AudioParameters& params) { + const AudioParameters& params, const std::string& input_device_id) { DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); - return MakeOutputStream(params); + return MakeOutputStream(params, input_device_id); } AudioInputStream* AudioManagerPulse::MakeLinearInputStream( @@ -162,9 +162,9 @@ AudioParameters AudioManagerPulse::GetPreferredOutputStreamParameters( } AudioOutputStream* AudioManagerPulse::MakeOutputStream( - const AudioParameters& params) { + const AudioParameters& params, const std::string& input_device_id) { if (params.input_channels()) { - return new PulseAudioUnifiedStream(params, this); + return new PulseAudioUnifiedStream(params, input_device_id, this); } return new PulseAudioOutputStream(params, this); diff --git a/media/audio/pulse/audio_manager_pulse.h b/media/audio/pulse/audio_manager_pulse.h index 9dacb9c..d5cb93e 100644 --- a/media/audio/pulse/audio_manager_pulse.h +++ b/media/audio/pulse/audio_manager_pulse.h @@ -34,7 +34,8 @@ class MEDIA_EXPORT AudioManagerPulse : public AudioManagerBase { virtual AudioOutputStream* MakeLinearOutputStream( const AudioParameters& params) OVERRIDE; virtual AudioOutputStream* MakeLowLatencyOutputStream( - const AudioParameters& params) OVERRIDE; + 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( @@ -60,7 +61,8 @@ class MEDIA_EXPORT AudioManagerPulse : public AudioManagerBase { void* user_data); // Called by MakeLinearOutputStream and MakeLowLatencyOutputStream. - AudioOutputStream* MakeOutputStream(const AudioParameters& params); + AudioOutputStream* MakeOutputStream(const AudioParameters& params, + const std::string& input_device_id); // Called by MakeLinearInputStream and MakeLowLatencyInputStream. AudioInputStream* MakeInputStream(const AudioParameters& params, diff --git a/media/audio/pulse/pulse_unified.cc b/media/audio/pulse/pulse_unified.cc index 87bb6ae..ee14341 100644 --- a/media/audio/pulse/pulse_unified.cc +++ b/media/audio/pulse/pulse_unified.cc @@ -41,9 +41,12 @@ void PulseAudioUnifiedStream::ReadCallback(pa_stream* handle, size_t length, static_cast<PulseAudioUnifiedStream*>(user_data)->ReadData(); } -PulseAudioUnifiedStream::PulseAudioUnifiedStream(const AudioParameters& params, - AudioManagerBase* manager) +PulseAudioUnifiedStream::PulseAudioUnifiedStream( + const AudioParameters& params, + const std::string& input_device_id, + AudioManagerBase* manager) : params_(params), + input_device_id_(input_device_id), manager_(manager), pa_context_(NULL), pa_mainloop_(NULL), @@ -77,9 +80,8 @@ bool PulseAudioUnifiedStream::Open() { params_, &StreamNotifyCallback, NULL, this)) return false; - // TODO(xians): Add support for non-default device. if (!pulse::CreateInputStream(pa_mainloop_, pa_context_, &input_stream_, - params_, AudioManagerBase::kDefaultDeviceId, + params_, input_device_id_, &StreamNotifyCallback, this)) return false; diff --git a/media/audio/pulse/pulse_unified.h b/media/audio/pulse/pulse_unified.h index d7476a8..a800d09 100644 --- a/media/audio/pulse/pulse_unified.h +++ b/media/audio/pulse/pulse_unified.h @@ -6,6 +6,7 @@ #define MEDIA_AUDIO_PULSE_PULSE_UNIFIED_H_ #include <pulse/pulseaudio.h> +#include <string> #include "base/memory/scoped_ptr.h" #include "media/audio/audio_io.h" @@ -20,6 +21,7 @@ class SeekableBuffer; class PulseAudioUnifiedStream : public AudioOutputStream { public: PulseAudioUnifiedStream(const AudioParameters& params, + const std::string& input_device_id, AudioManagerBase* manager); virtual ~PulseAudioUnifiedStream(); @@ -51,6 +53,9 @@ class PulseAudioUnifiedStream : public AudioOutputStream { // AudioParameters from the constructor. const AudioParameters params_; + // Device unique ID of the input device. + const std::string input_device_id_; + // Audio manager that created us. Used to report that we've closed. AudioManagerBase* manager_; 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 5f1f1a6..af60be6 100644 --- a/media/audio/win/audio_low_latency_output_win_unittest.cc +++ b/media/audio/win/audio_low_latency_output_win_unittest.cc @@ -232,7 +232,8 @@ class AudioOutputStreamWrapper { AudioOutputStream* CreateOutputStream() { AudioOutputStream* aos = audio_man_->MakeAudioOutputStream( AudioParameters(format_, channel_layout_, sample_rate_, - bits_per_sample_, samples_per_packet_)); + bits_per_sample_, samples_per_packet_), + std::string()); EXPECT_TRUE(aos); return aos; } diff --git a/media/audio/win/audio_manager_win.cc b/media/audio/win/audio_manager_win.cc index cfeecc7..b8b5d89 100644 --- a/media/audio/win/audio_manager_win.cc +++ b/media/audio/win/audio_manager_win.cc @@ -301,7 +301,7 @@ AudioOutputStream* AudioManagerWin::MakeLinearOutputStream( // - PCMWaveOutAudioOutputStream: Based on the waveOut API. // - WASAPIAudioOutputStream: Based on Core Audio (WASAPI) API. AudioOutputStream* AudioManagerWin::MakeLowLatencyOutputStream( - const AudioParameters& params) { + const AudioParameters& params, const std::string& input_device_id) { DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); if (params.channels() > kWinMaxChannels) return NULL; @@ -316,7 +316,7 @@ AudioOutputStream* AudioManagerWin::MakeLowLatencyOutputStream( // TODO(crogers): support more than stereo input. if (params.input_channels() > 0) { DVLOG(1) << "WASAPIUnifiedStream is created."; - return new WASAPIUnifiedStream(this, params); + return new WASAPIUnifiedStream(this, params, input_device_id); } return new WASAPIAudioOutputStream(this, params, eConsole); diff --git a/media/audio/win/audio_manager_win.h b/media/audio/win/audio_manager_win.h index 46d7aa4..65cc73b 100644 --- a/media/audio/win/audio_manager_win.h +++ b/media/audio/win/audio_manager_win.h @@ -34,7 +34,8 @@ class MEDIA_EXPORT AudioManagerWin : public AudioManagerBase { virtual AudioOutputStream* MakeLinearOutputStream( const AudioParameters& params) OVERRIDE; virtual AudioOutputStream* MakeLowLatencyOutputStream( - const AudioParameters& params) OVERRIDE; + 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( diff --git a/media/audio/win/audio_output_win_unittest.cc b/media/audio/win/audio_output_win_unittest.cc index ad20327..4e13d84 100644 --- a/media/audio/win/audio_output_win_unittest.cc +++ b/media/audio/win/audio_output_win_unittest.cc @@ -184,7 +184,8 @@ TEST(WinAudioTest, PCMWaveStreamGetAndClose) { AudioOutputStream* oas = audio_man->MakeAudioOutputStream( AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO, - 8000, 16, 256)); + 8000, 16, 256), + std::string()); ASSERT_TRUE(NULL != oas); oas->Close(); } @@ -199,22 +200,30 @@ TEST(WinAudioTest, SanityOnMakeParams) { AudioParameters::Format fmt = AudioParameters::AUDIO_PCM_LINEAR; EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream( - AudioParameters(fmt, CHANNEL_LAYOUT_UNSUPPORTED, 8000, 16, 256))); + AudioParameters(fmt, CHANNEL_LAYOUT_UNSUPPORTED, 8000, 16, 256), + std::string())); EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream( - AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 1024 * 1024, 16, 256))); + AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 1024 * 1024, 16, 256), + std::string())); EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream( - AudioParameters(fmt, CHANNEL_LAYOUT_STEREO, 8000, 80, 256))); + AudioParameters(fmt, CHANNEL_LAYOUT_STEREO, 8000, 80, 256), + std::string())); EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream( - AudioParameters(fmt, CHANNEL_LAYOUT_UNSUPPORTED, 8000, 16, 256))); + AudioParameters(fmt, CHANNEL_LAYOUT_UNSUPPORTED, 8000, 16, 256), + std::string())); EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream( - AudioParameters(fmt, CHANNEL_LAYOUT_STEREO, -8000, 16, 256))); + AudioParameters(fmt, CHANNEL_LAYOUT_STEREO, -8000, 16, 256), + std::string())); EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream( - AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16, -100))); + AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16, -100), + std::string())); EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream( - AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16, 0))); + AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16, 0), + std::string())); EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream( AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16, - media::limits::kMaxSamplesPerPacket + 1))); + media::limits::kMaxSamplesPerPacket + 1), + std::string())); } // Test that it can be opened and closed. @@ -227,7 +236,8 @@ TEST(WinAudioTest, PCMWaveStreamOpenAndClose) { AudioOutputStream* oas = audio_man->MakeAudioOutputStream( AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO, - 8000, 16, 256)); + 8000, 16, 256), + std::string()); ASSERT_TRUE(NULL != oas); EXPECT_TRUE(oas->Open()); oas->Close(); @@ -243,7 +253,8 @@ TEST(WinAudioTest, PCMWaveStreamOpenLimit) { AudioOutputStream* oas = audio_man->MakeAudioOutputStream( AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO, - 8000, 16, 1024 * 1024 * 1024)); + 8000, 16, 1024 * 1024 * 1024), + std::string()); EXPECT_TRUE(NULL == oas); if (oas) oas->Close(); @@ -261,7 +272,8 @@ TEST(WinAudioTest, PCMWaveSlowSource) { AudioOutputStream* oas = audio_man->MakeAudioOutputStream( AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, - 16000, 16, 256)); + 16000, 16, 256), + std::string()); ASSERT_TRUE(NULL != oas); TestSourceLaggy test_laggy(2, 90); EXPECT_TRUE(oas->Open()); @@ -289,7 +301,8 @@ TEST(WinAudioTest, PCMWaveStreamPlaySlowLoop) { uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 10; AudioOutputStream* oas = audio_man->MakeAudioOutputStream( AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, - AudioParameters::kAudioCDSampleRate, 16, samples_100_ms)); + AudioParameters::kAudioCDSampleRate, 16, samples_100_ms), + std::string()); ASSERT_TRUE(NULL != oas); SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate); @@ -319,7 +332,8 @@ TEST(WinAudioTest, PCMWaveStreamPlay200HzTone44Kss) { uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 10; AudioOutputStream* oas = audio_man->MakeAudioOutputStream( AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, - AudioParameters::kAudioCDSampleRate, 16, samples_100_ms)); + AudioParameters::kAudioCDSampleRate, 16, samples_100_ms), + std::string()); ASSERT_TRUE(NULL != oas); SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate); @@ -347,7 +361,8 @@ TEST(WinAudioTest, PCMWaveStreamPlay200HzTone22Kss) { AudioOutputStream* oas = audio_man->MakeAudioOutputStream( AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, AudioParameters::kAudioCDSampleRate / 2, 16, - samples_100_ms)); + samples_100_ms), + std::string()); ASSERT_TRUE(NULL != oas); SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate/2); @@ -386,7 +401,8 @@ TEST(WinAudioTest, PushSourceFile16KHz) { AudioOutputStream* oas = audio_man->MakeAudioOutputStream( AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, - kSampleRate, 16, kSamples100ms)); + kSampleRate, 16, kSamples100ms), + std::string()); ASSERT_TRUE(NULL != oas); EXPECT_TRUE(oas->Open()); @@ -422,7 +438,8 @@ TEST(WinAudioTest, PCMWaveStreamPlayTwice200HzTone44Kss) { uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 10; AudioOutputStream* oas = audio_man->MakeAudioOutputStream( AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, - AudioParameters::kAudioCDSampleRate, 16, samples_100_ms)); + AudioParameters::kAudioCDSampleRate, 16, samples_100_ms), + std::string()); ASSERT_TRUE(NULL != oas); SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate); @@ -468,7 +485,8 @@ TEST(WinAudioTest, PCMWaveStreamPlay200HzToneLowLatency) { AudioOutputStream* oas = audio_man->MakeAudioOutputStream( AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_MONO, sample_rate, - 16, n * samples_10_ms)); + 16, n * samples_10_ms), + std::string()); ASSERT_TRUE(NULL != oas); SineWaveAudioSource source(1, 200, sample_rate); @@ -501,7 +519,8 @@ TEST(WinAudioTest, PCMWaveStreamPendingBytes) { uint32 samples_100_ms = AudioParameters::kAudioCDSampleRate / 10; AudioOutputStream* oas = audio_man->MakeAudioOutputStream( AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, - AudioParameters::kAudioCDSampleRate, 16, samples_100_ms)); + AudioParameters::kAudioCDSampleRate, 16, samples_100_ms), + std::string()); ASSERT_TRUE(NULL != oas); NiceMock<MockAudioSource> source; @@ -660,7 +679,8 @@ TEST(WinAudioTest, SyncSocketBasic) { CHANNEL_LAYOUT_MONO, sample_rate, 16, kSamples20ms); - AudioOutputStream* oas = audio_man->MakeAudioOutputStream(params); + AudioOutputStream* oas = audio_man->MakeAudioOutputStream(params, + std::string()); ASSERT_TRUE(NULL != oas); ASSERT_TRUE(oas->Open()); diff --git a/media/audio/win/audio_unified_win.cc b/media/audio/win/audio_unified_win.cc index 6e00b28..c69d114 100644 --- a/media/audio/win/audio_unified_win.cc +++ b/media/audio/win/audio_unified_win.cc @@ -109,12 +109,14 @@ static double FrameCountToMilliseconds(int num_frames, namespace media { WASAPIUnifiedStream::WASAPIUnifiedStream(AudioManagerWin* manager, - const AudioParameters& params) + const AudioParameters& params, + const std::string& input_device_id) : creating_thread_id_(base::PlatformThread::CurrentId()), manager_(manager), params_(params), input_channels_(params.input_channels()), output_channels_(params.channels()), + input_device_id_(input_device_id), share_mode_(CoreAudioUtil::GetShareMode()), audio_io_thread_(NULL), opened_(false), @@ -328,7 +330,8 @@ bool WASAPIUnifiedStream::Open() { return false; // Capture side (always event driven but format depends on varispeed or not): - + // TODO(henrika): Open the correct input device with |input_device_id_|, + // http://crbug.com/147327. ScopedComPtr<IAudioClient> audio_input_client = CoreAudioUtil::CreateDefaultClient(eCapture, eConsole); if (!audio_input_client) diff --git a/media/audio/win/audio_unified_win.h b/media/audio/win/audio_unified_win.h index 3561ae4..76c5329 100644 --- a/media/audio/win/audio_unified_win.h +++ b/media/audio/win/audio_unified_win.h @@ -84,7 +84,8 @@ class MEDIA_EXPORT WASAPIUnifiedStream // The ctor takes all the usual parameters, plus |manager| which is the // the audio manager who is creating this object. WASAPIUnifiedStream(AudioManagerWin* manager, - const AudioParameters& params); + const AudioParameters& params, + const std::string& input_device_id); // The dtor is typically called by the AudioManager only and it is usually // triggered by calling AudioOutputStream::Close(). @@ -183,6 +184,9 @@ class MEDIA_EXPORT WASAPIUnifiedStream int input_channels_; int output_channels_; + // Unique ID of the input device to be opened. + const std::string input_device_id_; + // The sharing mode for the streams. // Valid values are AUDCLNT_SHAREMODE_SHARED and AUDCLNT_SHAREMODE_EXCLUSIVE // where AUDCLNT_SHAREMODE_SHARED is the default. diff --git a/media/audio/win/audio_unified_win_unittest.cc b/media/audio/win/audio_unified_win_unittest.cc index 4830ff0..6fad0b7 100644 --- a/media/audio/win/audio_unified_win_unittest.cc +++ b/media/audio/win/audio_unified_win_unittest.cc @@ -215,7 +215,8 @@ class AudioUnifiedStreamWrapper { private: AudioOutputStream* CreateOutputStream() { - AudioOutputStream* aos = audio_man_->MakeAudioOutputStream(params_); + AudioOutputStream* aos = audio_man_->MakeAudioOutputStream(params_, + std::string()); EXPECT_TRUE(aos); return aos; } diff --git a/media/base/audio_renderer_sink.h b/media/base/audio_renderer_sink.h index 0d3c6c7..b2f4ba0a 100644 --- a/media/base/audio_renderer_sink.h +++ b/media/base/audio_renderer_sink.h @@ -7,6 +7,7 @@ #include <vector> #include "base/basictypes.h" +#include "base/logging.h" #include "base/memory/ref_counted.h" #include "media/audio/audio_parameters.h" #include "media/base/audio_bus.h" @@ -41,13 +42,6 @@ class AudioRendererSink // Sets important information about the audio stream format. // It must be called before any of the other methods. - // For clients wishing to have synchronized input and output, - // |params| may specify |input_channels| > 0, representing a - // number of input channels which will be at the same sample-rate - // and buffer-size as the output as specified in |params|. - // In this case, the callback's RenderIO() method will be called instead - // of Render(), providing the synchronized input data at the same time as - // when new output data is to be rendered. virtual void Initialize(const AudioParameters& params, RenderCallback* callback) = 0; |