diff options
author | xians@chromium.org <xians@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-07 21:32:50 +0000 |
---|---|---|
committer | xians@chromium.org <xians@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-07 21:32:50 +0000 |
commit | e8ff1ad4a40d8f525a457b1231f31ff1068fc7a7 (patch) | |
tree | 11aef20f75aab3889614f2b05f70fe7ffae92709 /media | |
parent | 1d62cf79f609fba47ef680bf5acc9b453d4229ea (diff) | |
download | chromium_src-e8ff1ad4a40d8f525a457b1231f31ff1068fc7a7.zip chromium_src-e8ff1ad4a40d8f525a457b1231f31ff1068fc7a7.tar.gz chromium_src-e8ff1ad4a40d8f525a457b1231f31ff1068fc7a7.tar.bz2 |
Remove the unified IO code on the browser.
Unified IO is not used any more and it should be removed.
BUG=337096
TEST=bots, and nothing breaks.
Review URL: https://codereview.chromium.org/153623004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@249790 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
51 files changed, 124 insertions, 4491 deletions
diff --git a/media/audio/alsa/alsa_output_unittest.cc b/media/audio/alsa/alsa_output_unittest.cc index 07ce8ea..8b0aeae 100644 --- a/media/audio/alsa/alsa_output_unittest.cc +++ b/media/audio/alsa/alsa_output_unittest.cc @@ -75,10 +75,9 @@ class MockAudioManagerAlsa : public AudioManagerAlsa { MOCK_METHOD0(HasAudioInputDevices, bool()); MOCK_METHOD1(MakeLinearOutputStream, AudioOutputStream*( const AudioParameters& params)); - MOCK_METHOD3(MakeLowLatencyOutputStream, AudioOutputStream*( + MOCK_METHOD2(MakeLowLatencyOutputStream, AudioOutputStream*( const AudioParameters& params, - const std::string& device_id, - const std::string& input_device_id)); + const std::string& device_id)); MOCK_METHOD2(MakeLowLatencyInputStream, AudioInputStream*( const AudioParameters& params, const std::string& device_id)); diff --git a/media/audio/alsa/audio_manager_alsa.cc b/media/audio/alsa/audio_manager_alsa.cc index ac61a5f..7d6421f 100644 --- a/media/audio/alsa/audio_manager_alsa.cc +++ b/media/audio/alsa/audio_manager_alsa.cc @@ -283,11 +283,9 @@ AudioOutputStream* AudioManagerAlsa::MakeLinearOutputStream( AudioOutputStream* AudioManagerAlsa::MakeLowLatencyOutputStream( const AudioParameters& params, - const std::string& device_id, - const std::string& input_device_id) { + const std::string& device_id) { DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!"; DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); - // TODO(xians): Use input_device_id for unified IO. return MakeOutputStream(params); } diff --git a/media/audio/alsa/audio_manager_alsa.h b/media/audio/alsa/audio_manager_alsa.h index 155089f..d08c3ba 100644 --- a/media/audio/alsa/audio_manager_alsa.h +++ b/media/audio/alsa/audio_manager_alsa.h @@ -37,8 +37,7 @@ class MEDIA_EXPORT AudioManagerAlsa : public AudioManagerBase { const AudioParameters& params) OVERRIDE; virtual AudioOutputStream* MakeLowLatencyOutputStream( const AudioParameters& params, - const std::string& device_id, - const std::string& input_device_id) OVERRIDE; + const std::string& device_id) OVERRIDE; virtual AudioInputStream* MakeLinearInputStream( const AudioParameters& params, const std::string& device_id) OVERRIDE; virtual AudioInputStream* MakeLowLatencyInputStream( diff --git a/media/audio/android/audio_android_unittest.cc b/media/audio/android/audio_android_unittest.cc index 91bf5d8..a8d66a6 100644 --- a/media/audio/android/audio_android_unittest.cc +++ b/media/audio/android/audio_android_unittest.cc @@ -438,7 +438,7 @@ class AudioAndroidOutputTest : public testing::Test { const int num_callbacks = (kCallbackTestTimeMs / expected_time_between_callbacks_ms); AudioOutputStream* stream = audio_manager()->MakeAudioOutputStream( - params, std::string(), std::string()); + params, std::string()); EXPECT_TRUE(stream); int count = 0; @@ -621,7 +621,7 @@ TEST_P(AudioAndroidInputTest, CreateAndCloseInputStream) { TEST_F(AudioAndroidOutputTest, CreateAndCloseOutputStream) { AudioParameters params = GetDefaultOutputStreamParameters(); AudioOutputStream* aos = audio_manager()->MakeAudioOutputStream( - params, std::string(), std::string()); + params, std::string()); EXPECT_TRUE(aos); aos->Close(); } @@ -640,7 +640,7 @@ TEST_P(AudioAndroidInputTest, OpenAndCloseInputStream) { TEST_F(AudioAndroidOutputTest, OpenAndCloseOutputStream) { AudioParameters params = GetDefaultOutputStreamParameters(); AudioOutputStream* aos = audio_manager()->MakeAudioOutputStream( - params, std::string(), std::string()); + params, std::string()); EXPECT_TRUE(aos); EXPECT_TRUE(aos->Open()); aos->Close(); @@ -701,7 +701,7 @@ TEST_F(AudioAndroidOutputTest, DISABLED_RunOutputStreamWithFileAsSource) { AudioParameters params = GetDefaultOutputStreamParameters(); VLOG(1) << params; AudioOutputStream* aos = audio_manager()->MakeAudioOutputStream( - params, std::string(), std::string()); + params, std::string()); EXPECT_TRUE(aos); std::string file_name; @@ -770,7 +770,7 @@ TEST_P(AudioAndroidInputTest, DISABLED_RunDuplexInputStreamWithFileAsSink) { AudioParameters out_params = audio_manager()->GetDefaultOutputStreamParameters(); AudioOutputStream* aos = audio_manager()->MakeAudioOutputStream( - out_params, std::string(), std::string()); + out_params, std::string()); EXPECT_TRUE(aos); std::string file_name = base::StringPrintf("out_duplex_%d_%d_%d.pcm", @@ -829,7 +829,7 @@ TEST_P(AudioAndroidInputTest, io_params, AudioManagerBase::kDefaultDeviceId); EXPECT_TRUE(ais); AudioOutputStream* aos = audio_manager()->MakeAudioOutputStream( - io_params, std::string(), std::string()); + io_params, std::string()); EXPECT_TRUE(aos); FullDuplexAudioSinkSource full_duplex(io_params); diff --git a/media/audio/android/audio_manager_android.cc b/media/audio/android/audio_manager_android.cc index 33e9e08..a8d81c7 100644 --- a/media/audio/android/audio_manager_android.cc +++ b/media/audio/android/audio_manager_android.cc @@ -122,12 +122,10 @@ AudioParameters AudioManagerAndroid::GetInputStreamParameters( AudioOutputStream* AudioManagerAndroid::MakeAudioOutputStream( const AudioParameters& params, - const std::string& device_id, - const std::string& input_device_id) { + const std::string& device_id) { bool had_no_streams = HadNoAudioStreams(); AudioOutputStream* stream = - AudioManagerBase::MakeAudioOutputStream(params, std::string(), - std::string()); + AudioManagerBase::MakeAudioOutputStream(params, std::string()); // The audio manager for Android creates streams intended for real-time // VoIP sessions and therefore sets the audio mode to MODE_IN_COMMUNICATION. @@ -187,8 +185,7 @@ AudioOutputStream* AudioManagerAndroid::MakeLinearOutputStream( AudioOutputStream* AudioManagerAndroid::MakeLowLatencyOutputStream( const AudioParameters& params, - const std::string& device_id, - const std::string& input_device_id) { + const std::string& device_id) { DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!"; 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 670c094..ac67d08 100644 --- a/media/audio/android/audio_manager_android.h +++ b/media/audio/android/audio_manager_android.h @@ -33,8 +33,7 @@ class MEDIA_EXPORT AudioManagerAndroid : public AudioManagerBase { virtual AudioOutputStream* MakeAudioOutputStream( const AudioParameters& params, - const std::string& device_id, - const std::string& input_device_id) OVERRIDE; + const std::string& device_id) OVERRIDE; virtual AudioInputStream* MakeAudioInputStream( const AudioParameters& params, const std::string& device_id) OVERRIDE; @@ -46,8 +45,7 @@ class MEDIA_EXPORT AudioManagerAndroid : public AudioManagerBase { const AudioParameters& params) OVERRIDE; virtual AudioOutputStream* MakeLowLatencyOutputStream( const AudioParameters& params, - const std::string& device_id, - const std::string& input_device_id) OVERRIDE; + const std::string& device_id) OVERRIDE; virtual AudioInputStream* MakeLinearInputStream( const AudioParameters& params, const std::string& device_id) OVERRIDE; diff --git a/media/audio/audio_logging.h b/media/audio/audio_logging.h index 1d8366b..913b8ec 100644 --- a/media/audio/audio_logging.h +++ b/media/audio/audio_logging.h @@ -20,13 +20,11 @@ class AudioLog { virtual ~AudioLog() {} // Called when an audio component is created. |params| are the parameters of - // the created stream. |input_device_id| and |output_device_id| are the - // respective device ids for input and output. Either one or both may be - // specified. + // the created stream. |device_id| is the id of the audio device opened by + // the created stream. virtual void OnCreated(int component_id, const media::AudioParameters& params, - const std::string& input_device_id, - const std::string& output_device_id) = 0; + const std::string& device_id) = 0; // Called when an audio component is started, generally this is synonymous // with "playing." diff --git a/media/audio/audio_low_latency_input_output_unittest.cc b/media/audio/audio_low_latency_input_output_unittest.cc index 0fff86c..df94a3f 100644 --- a/media/audio/audio_low_latency_input_output_unittest.cc +++ b/media/audio/audio_low_latency_input_output_unittest.cc @@ -312,8 +312,7 @@ class AudioOutputStreamTraits { static StreamType* CreateStream(AudioManager* audio_manager, const AudioParameters& params) { - return audio_manager->MakeAudioOutputStream(params, std::string(), - std::string()); + return audio_manager->MakeAudioOutputStream(params, std::string()); } }; diff --git a/media/audio/audio_manager.h b/media/audio/audio_manager.h index 04e89a6..a15dab5 100644 --- a/media/audio/audio_manager.h +++ b/media/audio/audio_manager.h @@ -88,11 +88,6 @@ class MEDIA_EXPORT AudioManager { // To create a stream for the default output device, pass an empty string // for |device_id|, otherwise the specified audio device will be opened. // - // The |input_device_id| is used for low-latency unified streams - // (input+output) only and then only if the audio parameters specify a >0 - // input channel count. In other cases this id is ignored and should be - // empty. - // // Returns NULL if the combination of the parameters is not supported, or if // we have reached some other platform specific limit. // @@ -105,8 +100,7 @@ class MEDIA_EXPORT AudioManager { // Do not free the returned AudioOutputStream. It is owned by AudioManager. virtual AudioOutputStream* MakeAudioOutputStream( const AudioParameters& params, - const std::string& device_id, - const std::string& input_device_id) = 0; + const std::string& device_id) = 0; // Creates new audio output proxy. A proxy implements // AudioOutputStream interface, but unlike regular output stream @@ -114,8 +108,7 @@ class MEDIA_EXPORT AudioManager { // sound is actually playing. virtual AudioOutputStream* MakeAudioOutputStreamProxy( const AudioParameters& params, - const std::string& device_id, - const std::string& input_device_id) = 0; + const std::string& 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 f4cd60e..f9dcafe 100644 --- a/media/audio/audio_manager_base.cc +++ b/media/audio/audio_manager_base.cc @@ -37,17 +37,13 @@ const char AudioManagerBase::kLoopbackInputDeviceId[] = "loopback"; struct AudioManagerBase::DispatcherParams { DispatcherParams(const AudioParameters& input, const AudioParameters& output, - const std::string& output_device_id, - const std::string& input_device_id) + const std::string& output_device_id) : input_params(input), - output_params(output), - input_device_id(input_device_id), - output_device_id(output_device_id) {} + output_params(output) {} ~DispatcherParams() {} const AudioParameters input_params; const AudioParameters output_params; - const std::string input_device_id; const std::string output_device_id; scoped_refptr<AudioOutputDispatcher> dispatcher; @@ -63,13 +59,11 @@ class AudioManagerBase::CompareByParams { // 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. + // 2) Unified IO is used, input_params and output_params of the existing + // dispatcher are the same as the request dispatcher. return (dispatcher_->input_params == dispatcher_in->input_params && dispatcher_->output_params == dispatcher_in->output_params && - dispatcher_->output_device_id == dispatcher_in->output_device_id && - (!dispatcher_->input_params.input_channels() || - dispatcher_->input_device_id == dispatcher_in->input_device_id)); + dispatcher_->output_device_id == dispatcher_in->output_device_id); } private: @@ -139,8 +133,7 @@ AudioManagerBase::GetWorkerTaskRunner() { AudioOutputStream* AudioManagerBase::MakeAudioOutputStream( const AudioParameters& params, - const std::string& device_id, - const std::string& input_device_id) { + const std::string& 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(task_runner_->BelongsToCurrentThread()); @@ -170,7 +163,7 @@ AudioOutputStream* AudioManagerBase::MakeAudioOutputStream( stream = MakeLinearOutputStream(params); break; case AudioParameters::AUDIO_PCM_LOW_LATENCY: - stream = MakeLowLatencyOutputStream(params, device_id, input_device_id); + stream = MakeLowLatencyOutputStream(params, device_id); break; case AudioParameters::AUDIO_FAKE: stream = FakeAudioOutputStream::MakeFakeStream(this, params); @@ -232,8 +225,7 @@ AudioInputStream* AudioManagerBase::MakeAudioInputStream( AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy( const AudioParameters& params, - const std::string& device_id, - const std::string& input_device_id) { + const std::string& device_id) { DCHECK(task_runner_->BelongsToCurrentThread()); // If the caller supplied an empty device id to select the default device, @@ -273,8 +265,7 @@ AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy( } DispatcherParams* dispatcher_params = - new DispatcherParams(params, output_params, output_device_id, - input_device_id); + new DispatcherParams(params, output_params, output_device_id); AudioOutputDispatchers::iterator it = std::find_if(output_dispatchers_.begin(), output_dispatchers_.end(), @@ -289,12 +280,12 @@ AudioOutputStream* AudioManagerBase::MakeAudioOutputStreamProxy( scoped_refptr<AudioOutputDispatcher> dispatcher; if (output_params.format() != AudioParameters::AUDIO_FAKE) { dispatcher = new AudioOutputResampler(this, params, output_params, - output_device_id, input_device_id, + output_device_id, kCloseDelay); } else { dispatcher = new AudioOutputDispatcherImpl(this, output_params, output_device_id, - input_device_id, kCloseDelay); + kCloseDelay); } dispatcher_params->dispatcher = dispatcher; diff --git a/media/audio/audio_manager_base.h b/media/audio/audio_manager_base.h index e1ec49b..4c088fb 100644 --- a/media/audio/audio_manager_base.h +++ b/media/audio/audio_manager_base.h @@ -64,16 +64,14 @@ class MEDIA_EXPORT AudioManagerBase : public AudioManager { virtual AudioOutputStream* MakeAudioOutputStream( const AudioParameters& params, - const std::string& device_id, - const std::string& input_device_id) OVERRIDE; + const std::string& device_id) OVERRIDE; virtual AudioInputStream* MakeAudioInputStream( const AudioParameters& params, const std::string& device_id) OVERRIDE; virtual AudioOutputStream* MakeAudioOutputStreamProxy( const AudioParameters& params, - const std::string& device_id, - const std::string& input_device_id) OVERRIDE; + const std::string& device_id) OVERRIDE; // Called internally by the audio stream when it has been closed. virtual void ReleaseOutputStream(AudioOutputStream* stream); @@ -85,11 +83,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, - const std::string& device_id, - const std::string& input_device_id) = 0; + const std::string& device_id) = 0; // Creates the input stream for the |AUDIO_PCM_LINEAR| format. The legacy // name is also from |AUDIO_PCM_LINEAR|. diff --git a/media/audio/audio_output_controller.cc b/media/audio/audio_output_controller.cc index 0d9b0e8..405a02f 100644 --- a/media/audio/audio_output_controller.cc +++ b/media/audio/audio_output_controller.cc @@ -36,13 +36,11 @@ AudioOutputController::AudioOutputController( EventHandler* handler, const AudioParameters& params, const std::string& output_device_id, - const std::string& input_device_id, SyncReader* sync_reader) : audio_manager_(audio_manager), params_(params), handler_(handler), output_device_id_(output_device_id), - input_device_id_(input_device_id), stream_(NULL), diverting_to_stream_(NULL), volume_(1.0), @@ -72,7 +70,6 @@ scoped_refptr<AudioOutputController> AudioOutputController::Create( EventHandler* event_handler, const AudioParameters& params, const std::string& output_device_id, - const std::string& input_device_id, SyncReader* sync_reader) { DCHECK(audio_manager); DCHECK(sync_reader); @@ -81,8 +78,7 @@ scoped_refptr<AudioOutputController> AudioOutputController::Create( return NULL; scoped_refptr<AudioOutputController> controller(new AudioOutputController( - audio_manager, event_handler, params, output_device_id, input_device_id, - sync_reader)); + audio_manager, event_handler, params, output_device_id, sync_reader)); controller->message_loop_->PostTask(FROM_HERE, base::Bind( &AudioOutputController::DoCreate, controller, false)); return controller; @@ -141,8 +137,7 @@ void AudioOutputController::DoCreate(bool is_for_device_change) { stream_ = diverting_to_stream_ ? diverting_to_stream_ : - audio_manager_->MakeAudioOutputStreamProxy(params_, output_device_id_, - input_device_id_); + audio_manager_->MakeAudioOutputStreamProxy(params_, output_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 121b446..1a250f9 100644 --- a/media/audio/audio_output_controller.h +++ b/media/audio/audio_output_controller.h @@ -107,13 +107,11 @@ class MEDIA_EXPORT AudioOutputController // OnCreated() call from the same audio manager thread. |audio_manager| must // outlive AudioOutputController. // The |output_device_id| can be either empty (default device) or specify a - // specific hardware device for audio output. The |input_device_id| is - // used only for unified audio when opening up input and output at the same - // time (controlled by |params.input_channel_count()|). + // specific hardware device for audio output. static scoped_refptr<AudioOutputController> Create( AudioManager* audio_manager, EventHandler* event_handler, const AudioParameters& params, const std::string& output_device_id, - const std::string& input_device_id, SyncReader* sync_reader); + SyncReader* sync_reader); // Methods to control playback of the stream. @@ -193,7 +191,6 @@ class MEDIA_EXPORT AudioOutputController AudioOutputController(AudioManager* audio_manager, EventHandler* handler, const AudioParameters& params, const std::string& output_device_id, - const std::string& input_device_id, SyncReader* sync_reader); // The following methods are executed on the audio manager thread. @@ -234,9 +231,6 @@ class MEDIA_EXPORT AudioOutputController // default output device. std::string output_device_id_; - // Used by the unified IO to open the correct input device. - const std::string input_device_id_; - AudioOutputStream* stream_; // When non-NULL, audio is being diverted to this stream. diff --git a/media/audio/audio_output_controller_unittest.cc b/media/audio/audio_output_controller_unittest.cc index 288acd9..b4270e6 100644 --- a/media/audio/audio_output_controller_unittest.cc +++ b/media/audio/audio_output_controller_unittest.cc @@ -121,7 +121,7 @@ class AudioOutputControllerTest : public testing::Test { controller_ = AudioOutputController::Create( audio_manager_.get(), &mock_event_handler_, params_, std::string(), - std::string(), &mock_sync_reader_); + &mock_sync_reader_); if (controller_.get()) controller_->SetVolume(kTestVolume); diff --git a/media/audio/audio_output_dispatcher.cc b/media/audio/audio_output_dispatcher.cc index 1e78c9d..7f3dd10 100644 --- a/media/audio/audio_output_dispatcher.cc +++ b/media/audio/audio_output_dispatcher.cc @@ -11,13 +11,11 @@ namespace media { AudioOutputDispatcher::AudioOutputDispatcher( AudioManager* audio_manager, const AudioParameters& params, - const std::string& output_device_id, - const std::string& input_device_id) + const std::string& device_id) : audio_manager_(audio_manager), task_runner_(audio_manager->GetTaskRunner()), params_(params), - output_device_id_(output_device_id), - input_device_id_(input_device_id) { + device_id_(device_id) { // We expect to be instantiated on the audio thread. Otherwise the // |task_runner_| member will point to the wrong message loop! DCHECK(audio_manager->GetTaskRunner()->BelongsToCurrentThread()); diff --git a/media/audio/audio_output_dispatcher.h b/media/audio/audio_output_dispatcher.h index 69c5f16..d070b6b 100644 --- a/media/audio/audio_output_dispatcher.h +++ b/media/audio/audio_output_dispatcher.h @@ -38,8 +38,7 @@ class MEDIA_EXPORT AudioOutputDispatcher public: AudioOutputDispatcher(AudioManager* audio_manager, const AudioParameters& params, - const std::string& output_device_id, - const std::string& input_device_id); + const std::string& device_id); // Called by AudioOutputProxy to open the stream. // Returns false, if it fails to open it. @@ -73,8 +72,7 @@ class MEDIA_EXPORT AudioOutputDispatcher virtual void CloseStreamsForWedgeFix() = 0; virtual void RestartStreamsForWedgeFix() = 0; - // Accessor to the input device id used by unified IO. - const std::string& input_device_id() const { return input_device_id_; } + const std::string& device_id() const { return device_id_; } protected: friend class base::RefCountedThreadSafe<AudioOutputDispatcher>; @@ -85,8 +83,7 @@ class MEDIA_EXPORT AudioOutputDispatcher AudioManager* audio_manager_; const scoped_refptr<base::SingleThreadTaskRunner> task_runner_; const AudioParameters params_; - std::string output_device_id_; - const std::string input_device_id_; + std::string 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 d2e1d1c..5db170e 100644 --- a/media/audio/audio_output_dispatcher_impl.cc +++ b/media/audio/audio_output_dispatcher_impl.cc @@ -19,12 +19,10 @@ AudioOutputDispatcherImpl::AudioOutputDispatcherImpl( AudioManager* audio_manager, const AudioParameters& params, const std::string& output_device_id, - const std::string& input_device_id, const base::TimeDelta& close_delay) : AudioOutputDispatcher(audio_manager, params, - output_device_id, - input_device_id), + output_device_id), idle_proxies_(0), close_timer_(FROM_HERE, close_delay, @@ -131,7 +129,7 @@ void AudioOutputDispatcherImpl::Shutdown() { bool AudioOutputDispatcherImpl::CreateAndOpenStream() { DCHECK(task_runner_->BelongsToCurrentThread()); AudioOutputStream* stream = audio_manager_->MakeAudioOutputStream( - params_, output_device_id_, input_device_id_); + params_, device_id_); if (!stream) return false; @@ -143,7 +141,7 @@ bool AudioOutputDispatcherImpl::CreateAndOpenStream() { const int stream_id = audio_stream_id_++; audio_stream_ids_[stream] = stream_id; audio_log_->OnCreated( - stream_id, params_, input_device_id_, output_device_id_); + stream_id, params_, device_id_); idle_streams_.push_back(stream); return true; diff --git a/media/audio/audio_output_dispatcher_impl.h b/media/audio/audio_output_dispatcher_impl.h index 037e114..cb1ddb9 100644 --- a/media/audio/audio_output_dispatcher_impl.h +++ b/media/audio/audio_output_dispatcher_impl.h @@ -36,7 +36,6 @@ class MEDIA_EXPORT AudioOutputDispatcherImpl : public AudioOutputDispatcher { AudioOutputDispatcherImpl(AudioManager* audio_manager, const AudioParameters& params, const std::string& output_device_id, - 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_proxy_unittest.cc b/media/audio/audio_output_proxy_unittest.cc index 1c37dc5..534a6d9 100644 --- a/media/audio/audio_output_proxy_unittest.cc +++ b/media/audio/audio_output_proxy_unittest.cc @@ -93,14 +93,12 @@ class MockAudioManager : public AudioManagerBase { MOCK_METHOD0(HasAudioOutputDevices, bool()); MOCK_METHOD0(HasAudioInputDevices, bool()); MOCK_METHOD0(GetAudioInputDeviceModel, base::string16()); - MOCK_METHOD3(MakeAudioOutputStream, AudioOutputStream*( + MOCK_METHOD2(MakeAudioOutputStream, AudioOutputStream*( const AudioParameters& params, - const std::string& device_id, - const std::string& input_device_id)); - MOCK_METHOD3(MakeAudioOutputStreamProxy, AudioOutputStream*( + const std::string& device_id)); + MOCK_METHOD2(MakeAudioOutputStreamProxy, AudioOutputStream*( const AudioParameters& params, - const std::string& device_id, - const std::string& input_device_id)); + const std::string& device_id)); MOCK_METHOD2(MakeAudioInputStream, AudioInputStream*( const AudioParameters& params, const std::string& device_id)); MOCK_METHOD0(ShowAudioInputSettings, void()); @@ -112,9 +110,8 @@ class MockAudioManager : public AudioManagerBase { MOCK_METHOD1(MakeLinearOutputStream, AudioOutputStream*( const AudioParameters& params)); - MOCK_METHOD3(MakeLowLatencyOutputStream, AudioOutputStream*( - const AudioParameters& params, const std::string& device_id, - const std::string& input_device_id)); + MOCK_METHOD2(MakeLowLatencyOutputStream, AudioOutputStream*( + const AudioParameters& params, const std::string& device_id)); MOCK_METHOD2(MakeLinearInputStream, AudioInputStream*( const AudioParameters& params, const std::string& device_id)); MOCK_METHOD2(MakeLowLatencyInputStream, AudioInputStream*( @@ -168,7 +165,6 @@ class AudioOutputProxyTest : public testing::Test { dispatcher_impl_ = new AudioOutputDispatcherImpl(&manager(), params_, std::string(), - std::string(), close_delay); } @@ -199,7 +195,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)); @@ -213,7 +209,7 @@ class AudioOutputProxyTest : public testing::Test { void StartAndStop(AudioOutputDispatcher* dispatcher) { MockAudioOutputStream stream(&manager_, params_); - EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _)) + EXPECT_CALL(manager(), MakeAudioOutputStream(_, _)) .WillOnce(Return(&stream)); EXPECT_CALL(stream, Open()) .WillOnce(Return(true)); @@ -236,7 +232,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 +257,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)); @@ -280,7 +276,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)); @@ -297,7 +293,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)); @@ -314,7 +310,7 @@ class AudioOutputProxyTest : public testing::Test { void OneStream_TwoPlays(AudioOutputDispatcher* dispatcher) { MockAudioOutputStream stream(&manager_, params_); - EXPECT_CALL(manager(), MakeAudioOutputStream(_, _, _)) + EXPECT_CALL(manager(), MakeAudioOutputStream(_, _)) .WillOnce(Return(&stream)); EXPECT_CALL(stream, Open()) @@ -346,7 +342,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)); @@ -383,7 +379,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)); @@ -394,7 +390,7 @@ class AudioOutputProxyTest : public testing::Test { WaitForCloseTimer(&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))); @@ -434,8 +430,7 @@ class AudioOutputResamplerTest : public AudioOutputProxyTest { AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, 16000, 16, 1024); resampler_ = new AudioOutputResampler( - &manager(), params_, resampler_params_, std::string(), std::string(), - close_delay); + &manager(), params_, resampler_params_, std::string(), close_delay); } virtual void OnStart() OVERRIDE { @@ -535,7 +530,7 @@ TEST_F(AudioOutputResamplerTest, StartFailed) { StartFailed(resampler_); } // 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)); @@ -552,7 +547,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)); @@ -580,7 +575,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))); @@ -591,7 +586,7 @@ TEST_F(AudioOutputResamplerTest, HighLatencyFallbackFailed) { testing::Property(&AudioParameters::sample_rate, params_.sample_rate()), testing::Property( &AudioParameters::frames_per_buffer, params_.frames_per_buffer())), - _, _)) + _)) .Times(1) .WillOnce(Return(&okay_stream)); EXPECT_CALL(okay_stream, Open()) @@ -613,7 +608,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))); @@ -629,7 +624,7 @@ TEST_F(AudioOutputResamplerTest, LowLatencyOpenEventuallyFails) { MockAudioOutputStream stream2(&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)) .WillRepeatedly(Return(static_cast<AudioOutputStream*>(NULL))); @@ -685,7 +680,7 @@ TEST_F(AudioOutputResamplerTest, WedgeFix) { 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 e6fcc56..a5514c5 100644 --- a/media/audio/audio_output_resampler.cc +++ b/media/audio/audio_output_resampler.cc @@ -135,7 +135,7 @@ void AudioOutputResampler::SetupFallbackParams() { AudioParameters::AUDIO_PCM_LINEAR, params_.channel_layout(), params_.sample_rate(), params_.bits_per_sample(), frames_per_buffer); - output_device_id_ = ""; + device_id_ = ""; Initialize(); #endif } @@ -144,10 +144,8 @@ AudioOutputResampler::AudioOutputResampler(AudioManager* audio_manager, const AudioParameters& input_params, const AudioParameters& output_params, const std::string& output_device_id, - const std::string& input_device_id, const base::TimeDelta& close_delay) - : AudioOutputDispatcher(audio_manager, input_params, output_device_id, - input_device_id), + : AudioOutputDispatcher(audio_manager, input_params, output_device_id), close_delay_(close_delay), output_params_(output_params), streams_opened_(false) { @@ -169,8 +167,7 @@ void AudioOutputResampler::Initialize() { DCHECK(!streams_opened_); DCHECK(callbacks_.empty()); dispatcher_ = new AudioOutputDispatcherImpl( - audio_manager_, output_params_, output_device_id_, input_device_id_, - close_delay_); + audio_manager_, output_params_, device_id_, close_delay_); } bool AudioOutputResampler::OpenStream() { diff --git a/media/audio/audio_output_resampler.h b/media/audio/audio_output_resampler.h index a8fca23..80c9d77 100644 --- a/media/audio/audio_output_resampler.h +++ b/media/audio/audio_output_resampler.h @@ -41,7 +41,6 @@ class MEDIA_EXPORT AudioOutputResampler : public AudioOutputDispatcher { const AudioParameters& input_params, const AudioParameters& output_params, const std::string& output_device_id, - const std::string& input_device_id, const base::TimeDelta& close_delay); // AudioOutputDispatcher interface. diff --git a/media/audio/cras/cras_unified_unittest.cc b/media/audio/cras/cras_unified_unittest.cc index ee36b10..9d282bb 100644 --- a/media/audio/cras/cras_unified_unittest.cc +++ b/media/audio/cras/cras_unified_unittest.cc @@ -37,10 +37,9 @@ class MockAudioManagerCras : public AudioManagerCras { MOCK_METHOD0(HasAudioInputDevices, bool()); MOCK_METHOD1(MakeLinearOutputStream, AudioOutputStream*( const AudioParameters& params)); - MOCK_METHOD3(MakeLowLatencyOutputStream, + MOCK_METHOD2(MakeLowLatencyOutputStream, AudioOutputStream*(const AudioParameters& params, - const std::string& device_id, - const std::string& input_device_id)); + const std::string& device_id)); MOCK_METHOD2(MakeLinearOutputStream, AudioInputStream*( const AudioParameters& params, const std::string& device_id)); MOCK_METHOD2(MakeLowLatencyInputStream, AudioInputStream*( diff --git a/media/audio/fake_audio_log_factory.cc b/media/audio/fake_audio_log_factory.cc index 6f752e5..5e2d134 100644 --- a/media/audio/fake_audio_log_factory.cc +++ b/media/audio/fake_audio_log_factory.cc @@ -12,8 +12,7 @@ class FakeAudioLogImpl : public AudioLog { virtual ~FakeAudioLogImpl() {} virtual void OnCreated(int component_id, const media::AudioParameters& params, - const std::string& input_device_id, - const std::string& output_device_id) OVERRIDE {} + const std::string& device_id) OVERRIDE {} virtual void OnStarted(int component_id) OVERRIDE {} virtual void OnStopped(int component_id) OVERRIDE {} virtual void OnClosed(int component_id) OVERRIDE {} diff --git a/media/audio/fake_audio_manager.cc b/media/audio/fake_audio_manager.cc index bfe9a0a..e5d9bd4 100644 --- a/media/audio/fake_audio_manager.cc +++ b/media/audio/fake_audio_manager.cc @@ -33,8 +33,7 @@ AudioOutputStream* FakeAudioManager::MakeLinearOutputStream( AudioOutputStream* FakeAudioManager::MakeLowLatencyOutputStream( const AudioParameters& params, - const std::string& device_id, - const std::string& input_device_id) { + const std::string& device_id) { return FakeAudioOutputStream::MakeFakeStream(this, params); } diff --git a/media/audio/fake_audio_manager.h b/media/audio/fake_audio_manager.h index b5c4520..9fbf140 100644 --- a/media/audio/fake_audio_manager.h +++ b/media/audio/fake_audio_manager.h @@ -26,8 +26,7 @@ class MEDIA_EXPORT FakeAudioManager : public AudioManagerBase { const AudioParameters& params) OVERRIDE; virtual AudioOutputStream* MakeLowLatencyOutputStream( const AudioParameters& params, - const std::string& device_id, - const std::string& input_device_id) OVERRIDE; + const std::string& device_id) OVERRIDE; virtual AudioInputStream* MakeLinearInputStream(const AudioParameters& params, const std::string& device_id) OVERRIDE; diff --git a/media/audio/mac/aggregate_device_manager.cc b/media/audio/mac/aggregate_device_manager.cc deleted file mode 100644 index c7f3233..0000000 --- a/media/audio/mac/aggregate_device_manager.cc +++ /dev/null @@ -1,371 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "media/audio/mac/aggregate_device_manager.h" - -#include <CoreAudio/AudioHardware.h> -#include <string> - -#include "base/mac/mac_logging.h" -#include "base/mac/scoped_cftyperef.h" -#include "media/audio/audio_parameters.h" -#include "media/audio/mac/audio_manager_mac.h" - -using base::ScopedCFTypeRef; - -namespace media { - -AggregateDeviceManager::AggregateDeviceManager() - : plugin_id_(kAudioObjectUnknown), - input_device_(kAudioDeviceUnknown), - output_device_(kAudioDeviceUnknown), - aggregate_device_(kAudioObjectUnknown) { -} - -AggregateDeviceManager::~AggregateDeviceManager() { - DestroyAggregateDevice(); -} - -AudioDeviceID AggregateDeviceManager::GetDefaultAggregateDevice() { - AudioDeviceID current_input_device; - AudioDeviceID current_output_device; - AudioManagerMac::GetDefaultInputDevice(¤t_input_device); - AudioManagerMac::GetDefaultOutputDevice(¤t_output_device); - - if (AudioManagerMac::HardwareSampleRateForDevice(current_input_device) != - AudioManagerMac::HardwareSampleRateForDevice(current_output_device)) { - // TODO(crogers): with some extra work we can make aggregate devices work - // if the clock domain is the same but the sample-rate differ. - // For now we fallback to the synchronized path. - return kAudioDeviceUnknown; - } - - // Use a lazily created aggregate device if it's already available - // and still appropriate. - if (aggregate_device_ != kAudioObjectUnknown) { - // TODO(crogers): handle default device changes for synchronized I/O. - // For now, we check to make sure the default devices haven't changed - // since we lazily created the aggregate device. - if (current_input_device == input_device_ && - current_output_device == output_device_) - return aggregate_device_; - - // For now, once lazily created don't attempt to create another - // aggregate device. - return kAudioDeviceUnknown; - } - - input_device_ = current_input_device; - output_device_ = current_output_device; - - // Only create an aggregrate device if the clock domains match. - UInt32 input_clockdomain = GetClockDomain(input_device_); - UInt32 output_clockdomain = GetClockDomain(output_device_); - DVLOG(1) << "input_clockdomain: " << input_clockdomain; - DVLOG(1) << "output_clockdomain: " << output_clockdomain; - - if (input_clockdomain == 0 || input_clockdomain != output_clockdomain) - return kAudioDeviceUnknown; - - OSStatus result = CreateAggregateDevice( - input_device_, - output_device_, - &aggregate_device_); - if (result != noErr) - DestroyAggregateDevice(); - - return aggregate_device_; -} - -CFStringRef AggregateDeviceManager::GetDeviceUID(AudioDeviceID id) { - static const AudioObjectPropertyAddress kDeviceUIDAddress = { - kAudioDevicePropertyDeviceUID, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster - }; - - // As stated in the CoreAudio header (AudioHardwareBase.h), - // the caller is responsible for releasing the device_UID. - CFStringRef device_UID; - UInt32 size = sizeof(device_UID); - OSStatus result = AudioObjectGetPropertyData( - id, - &kDeviceUIDAddress, - 0, - 0, - &size, - &device_UID); - - return (result == noErr) ? device_UID : NULL; -} - -void AggregateDeviceManager::GetDeviceName( - AudioDeviceID id, char* name, UInt32 size) { - static const AudioObjectPropertyAddress kDeviceNameAddress = { - kAudioDevicePropertyDeviceName, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster - }; - - OSStatus result = AudioObjectGetPropertyData( - id, - &kDeviceNameAddress, - 0, - 0, - &size, - name); - - if (result != noErr && size > 0) - name[0] = 0; -} - -UInt32 AggregateDeviceManager::GetClockDomain(AudioDeviceID device_id) { - static const AudioObjectPropertyAddress kClockDomainAddress = { - kAudioDevicePropertyClockDomain, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster - }; - - UInt32 clockdomain = 0; - UInt32 size = sizeof(UInt32); - OSStatus result = AudioObjectGetPropertyData( - device_id, - &kClockDomainAddress, - 0, - 0, - &size, - &clockdomain); - - return (result == noErr) ? clockdomain : 0; -} - -OSStatus AggregateDeviceManager::GetPluginID(AudioObjectID* id) { - DCHECK(id); - - // Get the audio hardware plugin. - CFStringRef bundle_name = CFSTR("com.apple.audio.CoreAudio"); - - AudioValueTranslation plugin_translation; - plugin_translation.mInputData = &bundle_name; - plugin_translation.mInputDataSize = sizeof(bundle_name); - plugin_translation.mOutputData = id; - plugin_translation.mOutputDataSize = sizeof(*id); - - static const AudioObjectPropertyAddress kPlugInAddress = { - kAudioHardwarePropertyPlugInForBundleID, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster - }; - - UInt32 size = sizeof(plugin_translation); - OSStatus result = AudioObjectGetPropertyData( - kAudioObjectSystemObject, - &kPlugInAddress, - 0, - 0, - &size, - &plugin_translation); - - DVLOG(1) << "CoreAudio plugin ID: " << *id; - - return result; -} - -CFMutableDictionaryRef -AggregateDeviceManager::CreateAggregateDeviceDictionary( - AudioDeviceID input_id, - AudioDeviceID output_id) { - CFMutableDictionaryRef aggregate_device_dict = CFDictionaryCreateMutable( - NULL, - 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - if (!aggregate_device_dict) - return NULL; - - const CFStringRef kAggregateDeviceName = - CFSTR("ChromeAggregateAudioDevice"); - const CFStringRef kAggregateDeviceUID = - CFSTR("com.google.chrome.AggregateAudioDevice"); - - // Add name and UID of the device to the dictionary. - CFDictionaryAddValue( - aggregate_device_dict, - CFSTR(kAudioAggregateDeviceNameKey), - kAggregateDeviceName); - CFDictionaryAddValue( - aggregate_device_dict, - CFSTR(kAudioAggregateDeviceUIDKey), - kAggregateDeviceUID); - - // Add a "private aggregate key" to the dictionary. - // The 1 value means that the created aggregate device will - // only be accessible from the process that created it, and - // won't be visible to outside processes. - int value = 1; - ScopedCFTypeRef<CFNumberRef> aggregate_device_number(CFNumberCreate( - NULL, - kCFNumberIntType, - &value)); - CFDictionaryAddValue( - aggregate_device_dict, - CFSTR(kAudioAggregateDeviceIsPrivateKey), - aggregate_device_number); - - return aggregate_device_dict; -} - -CFMutableArrayRef -AggregateDeviceManager::CreateSubDeviceArray( - CFStringRef input_device_UID, CFStringRef output_device_UID) { - CFMutableArrayRef sub_devices_array = CFArrayCreateMutable( - NULL, - 0, - &kCFTypeArrayCallBacks); - - CFArrayAppendValue(sub_devices_array, input_device_UID); - CFArrayAppendValue(sub_devices_array, output_device_UID); - - return sub_devices_array; -} - -OSStatus AggregateDeviceManager::CreateAggregateDevice( - AudioDeviceID input_id, - AudioDeviceID output_id, - AudioDeviceID* aggregate_device) { - DCHECK(aggregate_device); - - const size_t kMaxDeviceNameLength = 256; - - scoped_ptr<char[]> input_device_name(new char[kMaxDeviceNameLength]); - GetDeviceName( - input_id, - input_device_name.get(), - sizeof(input_device_name)); - DVLOG(1) << "Input device: \n" << input_device_name; - - scoped_ptr<char[]> output_device_name(new char[kMaxDeviceNameLength]); - GetDeviceName( - output_id, - output_device_name.get(), - sizeof(output_device_name)); - DVLOG(1) << "Output device: \n" << output_device_name; - - OSStatus result = GetPluginID(&plugin_id_); - if (result != noErr) - return result; - - // Create a dictionary for the aggregate device. - ScopedCFTypeRef<CFMutableDictionaryRef> aggregate_device_dict( - CreateAggregateDeviceDictionary(input_id, output_id)); - if (!aggregate_device_dict) - return -1; - - // Create the aggregate device. - static const AudioObjectPropertyAddress kCreateAggregateDeviceAddress = { - kAudioPlugInCreateAggregateDevice, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster - }; - - UInt32 size = sizeof(*aggregate_device); - result = AudioObjectGetPropertyData( - plugin_id_, - &kCreateAggregateDeviceAddress, - sizeof(aggregate_device_dict), - &aggregate_device_dict, - &size, - aggregate_device); - if (result != noErr) { - DLOG(ERROR) << "Error creating aggregate audio device!"; - return result; - } - - // Set the sub-devices for the aggregate device. - // In this case we use two: the input and output devices. - - ScopedCFTypeRef<CFStringRef> input_device_UID(GetDeviceUID(input_id)); - ScopedCFTypeRef<CFStringRef> output_device_UID(GetDeviceUID(output_id)); - if (!input_device_UID || !output_device_UID) { - DLOG(ERROR) << "Error getting audio device UID strings."; - return -1; - } - - ScopedCFTypeRef<CFMutableArrayRef> sub_devices_array( - CreateSubDeviceArray(input_device_UID, output_device_UID)); - if (sub_devices_array == NULL) { - DLOG(ERROR) << "Error creating sub-devices array."; - return -1; - } - - static const AudioObjectPropertyAddress kSetSubDevicesAddress = { - kAudioAggregateDevicePropertyFullSubDeviceList, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster - }; - - size = sizeof(CFMutableArrayRef); - result = AudioObjectSetPropertyData( - *aggregate_device, - &kSetSubDevicesAddress, - 0, - NULL, - size, - &sub_devices_array); - if (result != noErr) { - DLOG(ERROR) << "Error setting aggregate audio device sub-devices!"; - return result; - } - - // Use the input device as the master device. - static const AudioObjectPropertyAddress kSetMasterDeviceAddress = { - kAudioAggregateDevicePropertyMasterSubDevice, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster - }; - - size = sizeof(CFStringRef); - result = AudioObjectSetPropertyData( - *aggregate_device, - &kSetMasterDeviceAddress, - 0, - NULL, - size, - &input_device_UID); - if (result != noErr) { - DLOG(ERROR) << "Error setting aggregate audio device master device!"; - return result; - } - - DVLOG(1) << "New aggregate device: " << *aggregate_device; - return noErr; -} - -void AggregateDeviceManager::DestroyAggregateDevice() { - if (aggregate_device_ == kAudioObjectUnknown) - return; - - static const AudioObjectPropertyAddress kDestroyAddress = { - kAudioPlugInDestroyAggregateDevice, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster - }; - - UInt32 size = sizeof(aggregate_device_); - OSStatus result = AudioObjectGetPropertyData( - plugin_id_, - &kDestroyAddress, - 0, - NULL, - &size, - &aggregate_device_); - if (result != noErr) { - DLOG(ERROR) << "Error destroying aggregate audio device!"; - return; - } - - aggregate_device_ = kAudioObjectUnknown; -} - -} // namespace media diff --git a/media/audio/mac/aggregate_device_manager.h b/media/audio/mac/aggregate_device_manager.h deleted file mode 100644 index 7b8b71f..0000000 --- a/media/audio/mac/aggregate_device_manager.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MEDIA_AUDIO_MAC_AGGREGATE_DEVICE_MANAGER_H_ -#define MEDIA_AUDIO_MAC_AGGREGATE_DEVICE_MANAGER_H_ - -#include <CoreAudio/CoreAudio.h> - -#include "base/basictypes.h" -#include "base/compiler_specific.h" -#include "media/base/media_export.h" - -namespace media { - -class MEDIA_EXPORT AggregateDeviceManager { - public: - AggregateDeviceManager(); - ~AggregateDeviceManager(); - - // Lazily creates an aggregate device based on the default - // input and output devices. - // It will either return a valid device or kAudioDeviceUnknown - // if the default devices are not suitable for aggregate devices. - AudioDeviceID GetDefaultAggregateDevice(); - - private: - // The caller is responsible for releasing the CFStringRef. - static CFStringRef GetDeviceUID(AudioDeviceID id); - - static void GetDeviceName(AudioDeviceID id, char* name, UInt32 size); - static UInt32 GetClockDomain(AudioDeviceID device_id); - static OSStatus GetPluginID(AudioObjectID* id); - - CFMutableDictionaryRef CreateAggregateDeviceDictionary( - AudioDeviceID input_id, - AudioDeviceID output_id); - - CFMutableArrayRef CreateSubDeviceArray(CFStringRef input_device_UID, - CFStringRef output_device_UID); - - OSStatus CreateAggregateDevice(AudioDeviceID input_id, - AudioDeviceID output_id, - AudioDeviceID* aggregate_device); - void DestroyAggregateDevice(); - - AudioObjectID plugin_id_; - AudioDeviceID input_device_; - AudioDeviceID output_device_; - - AudioDeviceID aggregate_device_; - - DISALLOW_COPY_AND_ASSIGN(AggregateDeviceManager); -}; - -} // namespace media - -#endif // MEDIA_AUDIO_MAC_AGGREGATE_DEVICE_MANAGER_H_ diff --git a/media/audio/mac/audio_auhal_mac_unittest.cc b/media/audio/mac/audio_auhal_mac_unittest.cc index 9babd80..fd0ffff 100644 --- a/media/audio/mac/audio_auhal_mac_unittest.cc +++ b/media/audio/mac/audio_auhal_mac_unittest.cc @@ -45,7 +45,7 @@ class AUHALStreamTest : public testing::Test { AudioOutputStream* Create() { return manager_->MakeAudioOutputStream( - manager_->GetDefaultOutputStreamParameters(), "", ""); + manager_->GetDefaultOutputStreamParameters(), ""); } bool CanRunAudioTests() { diff --git a/media/audio/mac/audio_manager_mac.cc b/media/audio/mac/audio_manager_mac.cc index c08efff..e86e7b48 100644 --- a/media/audio/mac/audio_manager_mac.cc +++ b/media/audio/mac/audio_manager_mac.cc @@ -20,8 +20,6 @@ #include "media/audio/mac/audio_input_mac.h" #include "media/audio/mac/audio_low_latency_input_mac.h" #include "media/audio/mac/audio_low_latency_output_mac.h" -#include "media/audio/mac/audio_synchronized_mac.h" -#include "media/audio/mac/audio_unified_mac.h" #include "media/base/bind_to_current_loop.h" #include "media/base/channel_layout.h" #include "media/base/limits.h" @@ -56,16 +54,6 @@ static bool HasAudioHardware(AudioObjectPropertySelector selector) { output_device_id != kAudioObjectUnknown; } -// Returns true if the default input device is the same as -// the default output device. -bool AudioManagerMac::HasUnifiedDefaultIO() { - AudioDeviceID input_id, output_id; - if (!GetDefaultInputDevice(&input_id) || !GetDefaultOutputDevice(&output_id)) - return false; - - return input_id == output_id; -} - // Retrieves information on audio devices, and prepends the default // device to the list if the list is non-empty. static void GetAudioDeviceInfo(bool is_input, @@ -566,72 +554,18 @@ std::string AudioManagerMac::GetAssociatedOutputDeviceID( AudioOutputStream* AudioManagerMac::MakeLinearOutputStream( const AudioParameters& params) { - return MakeLowLatencyOutputStream(params, std::string(), std::string()); + return MakeLowLatencyOutputStream(params, std::string()); } AudioOutputStream* AudioManagerMac::MakeLowLatencyOutputStream( const AudioParameters& params, - const std::string& device_id, - const std::string& input_device_id) { - // Handle basic output with no input channels. - if (params.input_channels() == 0) { - AudioDeviceID device = GetAudioDeviceIdByUId(false, device_id); - if (device == kAudioObjectUnknown) { - DLOG(ERROR) << "Failed to open output device: " << device_id; - return NULL; - } - return new AUHALStream(this, params, device); - } - - DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!"; - - // TODO(xians): support more than stereo input. - if (params.input_channels() != 2) { - // WebAudio is currently hard-coded to 2 channels so we should not - // see this case. - NOTREACHED() << "Only stereo input is currently supported!"; + const std::string& device_id) { + AudioDeviceID device = GetAudioDeviceIdByUId(false, device_id); + if (device == kAudioObjectUnknown) { + DLOG(ERROR) << "Failed to open output device: " << device_id; return NULL; } - - AudioDeviceID device = kAudioObjectUnknown; - if (HasUnifiedDefaultIO()) { - // For I/O, the simplest case is when the default input and output - // devices are the same. - GetDefaultOutputDevice(&device); - VLOG(0) << "UNIFIED: default input and output devices are identical"; - } else { - // Some audio hardware is presented as separate input and output devices - // even though they are really the same physical hardware and - // share the same "clock domain" at the lowest levels of the driver. - // A common of example of this is the "built-in" audio hardware: - // "Built-in Line Input" - // "Built-in Output" - // We would like to use an "aggregate" device for these situations, since - // CoreAudio will make the most efficient use of the shared "clock domain" - // so we get the lowest latency and use fewer threads. - device = aggregate_device_manager_.GetDefaultAggregateDevice(); - if (device != kAudioObjectUnknown) - VLOG(0) << "Using AGGREGATE audio device"; - } - - if (device != kAudioObjectUnknown && - input_device_id == AudioManagerBase::kDefaultDeviceId) - return new AUHALStream(this, params, device); - - // Fallback to AudioSynchronizedStream which will handle completely - // different and arbitrary combinations of input and output devices - // even running at different sample-rates. - // kAudioDeviceUnknown translates to "use default" here. - // TODO(xians): 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, - audio_device_id, - kAudioDeviceUnknown); + return new AUHALStream(this, params, device); } std::string AudioManagerMac::GetDefaultOutputDeviceID() { diff --git a/media/audio/mac/audio_manager_mac.h b/media/audio/mac/audio_manager_mac.h index 641f9d3..0d4e05f 100644 --- a/media/audio/mac/audio_manager_mac.h +++ b/media/audio/mac/audio_manager_mac.h @@ -11,7 +11,6 @@ #include "base/basictypes.h" #include "base/compiler_specific.h" #include "media/audio/audio_manager_base.h" -#include "media/audio/mac/aggregate_device_manager.h" #include "media/audio/mac/audio_device_listener_mac.h" namespace media { @@ -40,8 +39,7 @@ class MEDIA_EXPORT AudioManagerMac : public AudioManagerBase { const AudioParameters& params) OVERRIDE; virtual AudioOutputStream* MakeLowLatencyOutputStream( const AudioParameters& params, - const std::string& device_id, - const std::string& input_device_id) OVERRIDE; + const std::string& device_id) OVERRIDE; virtual AudioInputStream* MakeLinearInputStream( const AudioParameters& params, const std::string& device_id) OVERRIDE; virtual AudioInputStream* MakeLowLatencyInputStream( @@ -80,8 +78,6 @@ class MEDIA_EXPORT AudioManagerMac : public AudioManagerBase { const AudioParameters& input_params) OVERRIDE; private: - bool HasUnifiedDefaultIO(); - // Helper methods for constructing AudioDeviceListenerMac on the audio thread. void CreateDeviceListener(); void DestroyDeviceListener(); @@ -99,8 +95,6 @@ class MEDIA_EXPORT AudioManagerMac : public AudioManagerBase { int current_sample_rate_; AudioDeviceID current_output_device_; - AggregateDeviceManager aggregate_device_manager_; - // Helper class which monitors power events to determine if output streams // should defer Start() calls. Required to workaround an OSX bug. See // http://crbug.com/160920 for more details. diff --git a/media/audio/mac/audio_synchronized_mac.cc b/media/audio/mac/audio_synchronized_mac.cc deleted file mode 100644 index a9bc88e..0000000 --- a/media/audio/mac/audio_synchronized_mac.cc +++ /dev/null @@ -1,976 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "media/audio/mac/audio_synchronized_mac.h" - -#include <CoreServices/CoreServices.h> -#include <algorithm> - -#include "base/basictypes.h" -#include "base/debug/trace_event.h" -#include "base/logging.h" -#include "base/mac/mac_logging.h" -#include "media/audio/mac/audio_manager_mac.h" -#include "media/base/channel_mixer.h" - -namespace media { - -static const int kHardwareBufferSize = 128; -static const int kFifoSize = 16384; - -// TODO(crogers): handle the non-stereo case. -static const int kChannels = 2; - -// This value was determined empirically for minimum latency while still -// guarding against FIFO under-runs. -static const int kBaseTargetFifoFrames = 256 + 64; - -// If the input and output sample-rate don't match, then we need to maintain -// an additional safety margin due to the callback timing jitter and the -// varispeed buffering. This value was empirically tuned. -static const int kAdditionalTargetFifoFrames = 128; - -static void ZeroBufferList(AudioBufferList* buffer_list) { - for (size_t i = 0; i < buffer_list->mNumberBuffers; ++i) - memset(buffer_list->mBuffers[i].mData, - 0, - buffer_list->mBuffers[i].mDataByteSize); -} - -static void WrapBufferList(AudioBufferList* buffer_list, - AudioBus* bus, - int frames) { - DCHECK(buffer_list); - DCHECK(bus); - int channels = bus->channels(); - int buffer_list_channels = buffer_list->mNumberBuffers; - - // Copy pointers from AudioBufferList. - int source_idx = 0; - for (int i = 0; i < channels; ++i) { - bus->SetChannelData( - i, static_cast<float*>(buffer_list->mBuffers[source_idx].mData)); - - // It's ok to pass in a |buffer_list| with fewer channels, in which - // case we just duplicate the last channel. - if (source_idx < buffer_list_channels - 1) - ++source_idx; - } - - // Finally set the actual length. - bus->set_frames(frames); -} - -AudioSynchronizedStream::AudioSynchronizedStream( - AudioManagerMac* manager, - const AudioParameters& params, - AudioDeviceID input_id, - AudioDeviceID output_id) - : manager_(manager), - params_(params), - input_sample_rate_(0), - output_sample_rate_(0), - input_id_(input_id), - output_id_(output_id), - input_buffer_list_(NULL), - fifo_(kChannels, kFifoSize), - target_fifo_frames_(kBaseTargetFifoFrames), - average_delta_(0.0), - fifo_rate_compensation_(1.0), - input_unit_(0), - varispeed_unit_(0), - output_unit_(0), - first_input_time_(-1), - is_running_(false), - hardware_buffer_size_(kHardwareBufferSize), - channels_(kChannels) { - VLOG(1) << "AudioSynchronizedStream::AudioSynchronizedStream()"; -} - -AudioSynchronizedStream::~AudioSynchronizedStream() { - DCHECK(!input_unit_); - DCHECK(!output_unit_); - DCHECK(!varispeed_unit_); -} - -bool AudioSynchronizedStream::Open() { - if (params_.channels() != kChannels) { - LOG(ERROR) << "Only stereo output is currently supported."; - return false; - } - - // Create the input, output, and varispeed AudioUnits. - OSStatus result = CreateAudioUnits(); - if (result != noErr) { - LOG(ERROR) << "Cannot create AudioUnits."; - return false; - } - - result = SetupInput(input_id_); - if (result != noErr) { - LOG(ERROR) << "Error configuring input AudioUnit."; - return false; - } - - result = SetupOutput(output_id_); - if (result != noErr) { - LOG(ERROR) << "Error configuring output AudioUnit."; - return false; - } - - result = SetupCallbacks(); - if (result != noErr) { - LOG(ERROR) << "Error setting up callbacks on AudioUnits."; - return false; - } - - result = SetupStreamFormats(); - if (result != noErr) { - LOG(ERROR) << "Error configuring stream formats on AudioUnits."; - return false; - } - - AllocateInputData(); - - // Final initialization of the AudioUnits. - result = AudioUnitInitialize(input_unit_); - if (result != noErr) { - LOG(ERROR) << "Error initializing input AudioUnit."; - return false; - } - - result = AudioUnitInitialize(output_unit_); - if (result != noErr) { - LOG(ERROR) << "Error initializing output AudioUnit."; - return false; - } - - result = AudioUnitInitialize(varispeed_unit_); - if (result != noErr) { - LOG(ERROR) << "Error initializing varispeed AudioUnit."; - return false; - } - - if (input_sample_rate_ != output_sample_rate_) { - // Add extra safety margin. - target_fifo_frames_ += kAdditionalTargetFifoFrames; - } - - // Buffer initial silence corresponding to target I/O buffering. - fifo_.Clear(); - scoped_ptr<AudioBus> silence = - AudioBus::Create(channels_, target_fifo_frames_); - silence->Zero(); - fifo_.Push(silence.get()); - - return true; -} - -void AudioSynchronizedStream::Close() { - DCHECK(!is_running_); - - if (input_buffer_list_) { - free(input_buffer_list_); - input_buffer_list_ = 0; - input_bus_.reset(NULL); - wrapper_bus_.reset(NULL); - } - - if (input_unit_) { - AudioUnitUninitialize(input_unit_); - CloseComponent(input_unit_); - } - - if (output_unit_) { - AudioUnitUninitialize(output_unit_); - CloseComponent(output_unit_); - } - - if (varispeed_unit_) { - AudioUnitUninitialize(varispeed_unit_); - CloseComponent(varispeed_unit_); - } - - input_unit_ = NULL; - output_unit_ = NULL; - varispeed_unit_ = NULL; - - // Inform the audio manager that we have been closed. This can cause our - // destruction. - manager_->ReleaseOutputStream(this); -} - -void AudioSynchronizedStream::Start(AudioSourceCallback* callback) { - DCHECK(callback); - DCHECK(input_unit_); - DCHECK(output_unit_); - DCHECK(varispeed_unit_); - - if (is_running_ || !input_unit_ || !output_unit_ || !varispeed_unit_) - return; - - source_ = callback; - - // Reset state variables each time we Start(). - fifo_rate_compensation_ = 1.0; - average_delta_ = 0.0; - - OSStatus result = noErr; - - if (!is_running_) { - first_input_time_ = -1; - - result = AudioOutputUnitStart(input_unit_); - OSSTATUS_DCHECK(result == noErr, result); - - if (result == noErr) { - result = AudioOutputUnitStart(output_unit_); - OSSTATUS_DCHECK(result == noErr, result); - } - } - - is_running_ = true; -} - -void AudioSynchronizedStream::Stop() { - OSStatus result = noErr; - if (is_running_) { - result = AudioOutputUnitStop(input_unit_); - OSSTATUS_DCHECK(result == noErr, result); - - if (result == noErr) { - result = AudioOutputUnitStop(output_unit_); - OSSTATUS_DCHECK(result == noErr, result); - } - } - - if (result == noErr) - is_running_ = false; -} - -bool AudioSynchronizedStream::IsRunning() { - return is_running_; -} - -// TODO(crogers): implement - or remove from AudioOutputStream. -void AudioSynchronizedStream::SetVolume(double volume) {} -void AudioSynchronizedStream::GetVolume(double* volume) {} - -OSStatus AudioSynchronizedStream::SetOutputDeviceAsCurrent( - AudioDeviceID output_id) { - OSStatus result = noErr; - - // Get the default output device if device is unknown. - if (output_id == kAudioDeviceUnknown) { - AudioObjectPropertyAddress pa; - pa.mSelector = kAudioHardwarePropertyDefaultOutputDevice; - pa.mScope = kAudioObjectPropertyScopeGlobal; - pa.mElement = kAudioObjectPropertyElementMaster; - UInt32 size = sizeof(output_id); - - result = AudioObjectGetPropertyData( - kAudioObjectSystemObject, - &pa, - 0, - 0, - &size, - &output_id); - - OSSTATUS_DCHECK(result == noErr, result); - if (result != noErr) - return result; - } - - // Set the render frame size. - UInt32 frame_size = hardware_buffer_size_; - AudioObjectPropertyAddress pa; - pa.mSelector = kAudioDevicePropertyBufferFrameSize; - pa.mScope = kAudioDevicePropertyScopeInput; - pa.mElement = kAudioObjectPropertyElementMaster; - result = AudioObjectSetPropertyData( - output_id, - &pa, - 0, - 0, - sizeof(frame_size), - &frame_size); - - OSSTATUS_DCHECK(result == noErr, result); - if (result != noErr) - return result; - - output_info_.Initialize(output_id, false); - - // Set the Current Device to the Default Output Unit. - result = AudioUnitSetProperty( - output_unit_, - kAudioOutputUnitProperty_CurrentDevice, - kAudioUnitScope_Global, - 0, - &output_info_.id_, - sizeof(output_info_.id_)); - - OSSTATUS_DCHECK(result == noErr, result); - return result; -} - -OSStatus AudioSynchronizedStream::SetInputDeviceAsCurrent( - AudioDeviceID input_id) { - OSStatus result = noErr; - - // Get the default input device if device is unknown. - if (input_id == kAudioDeviceUnknown) { - AudioObjectPropertyAddress pa; - pa.mSelector = kAudioHardwarePropertyDefaultInputDevice; - pa.mScope = kAudioObjectPropertyScopeGlobal; - pa.mElement = kAudioObjectPropertyElementMaster; - UInt32 size = sizeof(input_id); - - result = AudioObjectGetPropertyData( - kAudioObjectSystemObject, - &pa, - 0, - 0, - &size, - &input_id); - - OSSTATUS_DCHECK(result == noErr, result); - if (result != noErr) - return result; - } - - // Set the render frame size. - UInt32 frame_size = hardware_buffer_size_; - AudioObjectPropertyAddress pa; - pa.mSelector = kAudioDevicePropertyBufferFrameSize; - pa.mScope = kAudioDevicePropertyScopeInput; - pa.mElement = kAudioObjectPropertyElementMaster; - result = AudioObjectSetPropertyData( - input_id, - &pa, - 0, - 0, - sizeof(frame_size), - &frame_size); - - OSSTATUS_DCHECK(result == noErr, result); - if (result != noErr) - return result; - - input_info_.Initialize(input_id, true); - - // Set the Current Device to the AUHAL. - // This should be done only after I/O has been enabled on the AUHAL. - result = AudioUnitSetProperty( - input_unit_, - kAudioOutputUnitProperty_CurrentDevice, - kAudioUnitScope_Global, - 0, - &input_info_.id_, - sizeof(input_info_.id_)); - - OSSTATUS_DCHECK(result == noErr, result); - return result; -} - -OSStatus AudioSynchronizedStream::CreateAudioUnits() { - // Q: Why do we need a varispeed unit? - // A: If the input device and the output device are running at - // different sample rates and/or on different clocks, we will need - // to compensate to avoid a pitch change and - // to avoid buffer under and over runs. - ComponentDescription varispeed_desc; - varispeed_desc.componentType = kAudioUnitType_FormatConverter; - varispeed_desc.componentSubType = kAudioUnitSubType_Varispeed; - varispeed_desc.componentManufacturer = kAudioUnitManufacturer_Apple; - varispeed_desc.componentFlags = 0; - varispeed_desc.componentFlagsMask = 0; - - Component varispeed_comp = FindNextComponent(NULL, &varispeed_desc); - if (varispeed_comp == NULL) - return -1; - - OSStatus result = OpenAComponent(varispeed_comp, &varispeed_unit_); - OSSTATUS_DCHECK(result == noErr, result); - if (result != noErr) - return result; - - // Open input AudioUnit. - ComponentDescription input_desc; - input_desc.componentType = kAudioUnitType_Output; - input_desc.componentSubType = kAudioUnitSubType_HALOutput; - input_desc.componentManufacturer = kAudioUnitManufacturer_Apple; - input_desc.componentFlags = 0; - input_desc.componentFlagsMask = 0; - - Component input_comp = FindNextComponent(NULL, &input_desc); - if (input_comp == NULL) - return -1; - - result = OpenAComponent(input_comp, &input_unit_); - OSSTATUS_DCHECK(result == noErr, result); - if (result != noErr) - return result; - - // Open output AudioUnit. - ComponentDescription output_desc; - output_desc.componentType = kAudioUnitType_Output; - output_desc.componentSubType = kAudioUnitSubType_DefaultOutput; - output_desc.componentManufacturer = kAudioUnitManufacturer_Apple; - output_desc.componentFlags = 0; - output_desc.componentFlagsMask = 0; - - Component output_comp = FindNextComponent(NULL, &output_desc); - if (output_comp == NULL) - return -1; - - result = OpenAComponent(output_comp, &output_unit_); - OSSTATUS_DCHECK(result == noErr, result); - if (result != noErr) - return result; - - return noErr; -} - -OSStatus AudioSynchronizedStream::SetupInput(AudioDeviceID input_id) { - // The AUHAL used for input needs to be initialized - // before anything is done to it. - OSStatus result = AudioUnitInitialize(input_unit_); - OSSTATUS_DCHECK(result == noErr, result); - if (result != noErr) - return result; - - // We must enable the Audio Unit (AUHAL) for input and disable output - // BEFORE setting the AUHAL's current device. - result = EnableIO(); - OSSTATUS_DCHECK(result == noErr, result); - if (result != noErr) - return result; - - result = SetInputDeviceAsCurrent(input_id); - OSSTATUS_DCHECK(result == noErr, result); - - return result; -} - -OSStatus AudioSynchronizedStream::EnableIO() { - // Enable input on the AUHAL. - UInt32 enable_io = 1; - OSStatus result = AudioUnitSetProperty( - input_unit_, - kAudioOutputUnitProperty_EnableIO, - kAudioUnitScope_Input, - 1, // input element - &enable_io, - sizeof(enable_io)); - - OSSTATUS_DCHECK(result == noErr, result); - if (result != noErr) - return result; - - // Disable Output on the AUHAL. - enable_io = 0; - result = AudioUnitSetProperty( - input_unit_, - kAudioOutputUnitProperty_EnableIO, - kAudioUnitScope_Output, - 0, // output element - &enable_io, - sizeof(enable_io)); - - OSSTATUS_DCHECK(result == noErr, result); - return result; -} - -OSStatus AudioSynchronizedStream::SetupOutput(AudioDeviceID output_id) { - OSStatus result = noErr; - - result = SetOutputDeviceAsCurrent(output_id); - OSSTATUS_DCHECK(result == noErr, result); - if (result != noErr) - return result; - - // Tell the output unit not to reset timestamps. - // Otherwise sample rate changes will cause sync loss. - UInt32 start_at_zero = 0; - result = AudioUnitSetProperty( - output_unit_, - kAudioOutputUnitProperty_StartTimestampsAtZero, - kAudioUnitScope_Global, - 0, - &start_at_zero, - sizeof(start_at_zero)); - - OSSTATUS_DCHECK(result == noErr, result); - - return result; -} - -OSStatus AudioSynchronizedStream::SetupCallbacks() { - // Set the input callback. - AURenderCallbackStruct callback; - callback.inputProc = InputProc; - callback.inputProcRefCon = this; - OSStatus result = AudioUnitSetProperty( - input_unit_, - kAudioOutputUnitProperty_SetInputCallback, - kAudioUnitScope_Global, - 0, - &callback, - sizeof(callback)); - - OSSTATUS_DCHECK(result == noErr, result); - if (result != noErr) - return result; - - // Set the output callback. - callback.inputProc = OutputProc; - callback.inputProcRefCon = this; - result = AudioUnitSetProperty( - output_unit_, - kAudioUnitProperty_SetRenderCallback, - kAudioUnitScope_Input, - 0, - &callback, - sizeof(callback)); - - OSSTATUS_DCHECK(result == noErr, result); - if (result != noErr) - return result; - - // Set the varispeed callback. - callback.inputProc = VarispeedProc; - callback.inputProcRefCon = this; - result = AudioUnitSetProperty( - varispeed_unit_, - kAudioUnitProperty_SetRenderCallback, - kAudioUnitScope_Input, - 0, - &callback, - sizeof(callback)); - - OSSTATUS_DCHECK(result == noErr, result); - - return result; -} - -OSStatus AudioSynchronizedStream::SetupStreamFormats() { - AudioStreamBasicDescription asbd, asbd_dev1_in, asbd_dev2_out; - - // Get the Stream Format (Output client side). - UInt32 property_size = sizeof(asbd_dev1_in); - OSStatus result = AudioUnitGetProperty( - input_unit_, - kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Input, - 1, - &asbd_dev1_in, - &property_size); - - OSSTATUS_DCHECK(result == noErr, result); - if (result != noErr) - return result; - - // Get the Stream Format (client side). - property_size = sizeof(asbd); - result = AudioUnitGetProperty( - input_unit_, - kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Output, - 1, - &asbd, - &property_size); - - OSSTATUS_DCHECK(result == noErr, result); - if (result != noErr) - return result; - - // Get the Stream Format (Output client side). - property_size = sizeof(asbd_dev2_out); - result = AudioUnitGetProperty( - output_unit_, - kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Output, - 0, - &asbd_dev2_out, - &property_size); - - OSSTATUS_DCHECK(result == noErr, result); - if (result != noErr) - return result; - - // Set the format of all the AUs to the input/output devices channel count. - // For a simple case, you want to set this to - // the lower of count of the channels in the input device vs output device. - asbd.mChannelsPerFrame = std::min(asbd_dev1_in.mChannelsPerFrame, - asbd_dev2_out.mChannelsPerFrame); - - // We must get the sample rate of the input device and set it to the - // stream format of AUHAL. - Float64 rate = 0; - property_size = sizeof(rate); - - AudioObjectPropertyAddress pa; - pa.mSelector = kAudioDevicePropertyNominalSampleRate; - pa.mScope = kAudioObjectPropertyScopeWildcard; - pa.mElement = kAudioObjectPropertyElementMaster; - result = AudioObjectGetPropertyData( - input_info_.id_, - &pa, - 0, - 0, - &property_size, - &rate); - - OSSTATUS_DCHECK(result == noErr, result); - if (result != noErr) - return result; - - input_sample_rate_ = rate; - - asbd.mSampleRate = rate; - property_size = sizeof(asbd); - - // Set the new formats to the AUs... - result = AudioUnitSetProperty( - input_unit_, - kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Output, - 1, - &asbd, - property_size); - - OSSTATUS_DCHECK(result == noErr, result); - if (result != noErr) - return result; - - result = AudioUnitSetProperty( - varispeed_unit_, - kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Input, - 0, - &asbd, - property_size); - - OSSTATUS_DCHECK(result == noErr, result); - if (result != noErr) - return result; - - // Set the correct sample rate for the output device, - // but keep the channel count the same. - property_size = sizeof(rate); - - pa.mSelector = kAudioDevicePropertyNominalSampleRate; - pa.mScope = kAudioObjectPropertyScopeWildcard; - pa.mElement = kAudioObjectPropertyElementMaster; - result = AudioObjectGetPropertyData( - output_info_.id_, - &pa, - 0, - 0, - &property_size, - &rate); - - OSSTATUS_DCHECK(result == noErr, result); - if (result != noErr) - return result; - - output_sample_rate_ = rate; - - // The requested sample-rate must match the hardware sample-rate. - if (output_sample_rate_ != params_.sample_rate()) { - LOG(ERROR) << "Requested sample-rate: " << params_.sample_rate() - << " must match the hardware sample-rate: " << output_sample_rate_; - return kAudioDeviceUnsupportedFormatError; - } - - asbd.mSampleRate = rate; - property_size = sizeof(asbd); - - // Set the new audio stream formats for the rest of the AUs... - result = AudioUnitSetProperty( - varispeed_unit_, - kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Output, - 0, - &asbd, - property_size); - - OSSTATUS_DCHECK(result == noErr, result); - if (result != noErr) - return result; - - result = AudioUnitSetProperty( - output_unit_, - kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Input, - 0, - &asbd, - property_size); - - OSSTATUS_DCHECK(result == noErr, result); - return result; -} - -void AudioSynchronizedStream::AllocateInputData() { - // Get the native number of input channels that the hardware supports. - int hardware_channels = 0; - bool got_hardware_channels = AudioManagerMac::GetDeviceChannels( - input_id_, kAudioDevicePropertyScopeInput, &hardware_channels); - if (!got_hardware_channels || hardware_channels > 2) { - // Only mono and stereo are supported on the input side. When it fails to - // get the native channel number or the native channel number is bigger - // than 2, we open the device in stereo mode. - hardware_channels = 2; - } - - // Allocate storage for the AudioBufferList used for the - // input data from the input AudioUnit. - // We allocate enough space for with one AudioBuffer per channel. - size_t malloc_size = offsetof(AudioBufferList, mBuffers[0]) + - (sizeof(AudioBuffer) * hardware_channels); - - input_buffer_list_ = static_cast<AudioBufferList*>(malloc(malloc_size)); - input_buffer_list_->mNumberBuffers = hardware_channels; - - input_bus_ = AudioBus::Create(hardware_channels, hardware_buffer_size_); - wrapper_bus_ = AudioBus::CreateWrapper(channels_); - if (hardware_channels != params_.input_channels()) { - ChannelLayout hardware_channel_layout = - GuessChannelLayout(hardware_channels); - ChannelLayout requested_channel_layout = - GuessChannelLayout(params_.input_channels()); - channel_mixer_.reset(new ChannelMixer(hardware_channel_layout, - requested_channel_layout)); - mixer_bus_ = AudioBus::Create(params_.input_channels(), - hardware_buffer_size_); - } - - // Allocate buffers for AudioBufferList. - UInt32 buffer_size_bytes = input_bus_->frames() * sizeof(Float32); - for (size_t i = 0; i < input_buffer_list_->mNumberBuffers; ++i) { - input_buffer_list_->mBuffers[i].mNumberChannels = 1; - input_buffer_list_->mBuffers[i].mDataByteSize = buffer_size_bytes; - input_buffer_list_->mBuffers[i].mData = input_bus_->channel(i); - } -} - -OSStatus AudioSynchronizedStream::HandleInputCallback( - AudioUnitRenderActionFlags* io_action_flags, - const AudioTimeStamp* time_stamp, - UInt32 bus_number, - UInt32 number_of_frames, - AudioBufferList* io_data) { - TRACE_EVENT0("audio", "AudioSynchronizedStream::HandleInputCallback"); - - if (first_input_time_ < 0.0) - first_input_time_ = time_stamp->mSampleTime; - - // Get the new audio input data. - OSStatus result = AudioUnitRender( - input_unit_, - io_action_flags, - time_stamp, - bus_number, - number_of_frames, - input_buffer_list_); - - // TODO(xians): Add back the DCHECK after synchronize IO supports all - // combination of input and output params. See http://issue/246521. - if (result != noErr) - return result; - - // Buffer input into FIFO. - int available_frames = fifo_.max_frames() - fifo_.frames(); - if (input_bus_->frames() <= available_frames) { - if (channel_mixer_) { - channel_mixer_->Transform(input_bus_.get(), mixer_bus_.get()); - fifo_.Push(mixer_bus_.get()); - } else { - fifo_.Push(input_bus_.get()); - } - } - - return result; -} - -OSStatus AudioSynchronizedStream::HandleVarispeedCallback( - AudioUnitRenderActionFlags* io_action_flags, - const AudioTimeStamp* time_stamp, - UInt32 bus_number, - UInt32 number_of_frames, - AudioBufferList* io_data) { - // Create a wrapper bus on the AudioBufferList. - WrapBufferList(io_data, wrapper_bus_.get(), number_of_frames); - - if (fifo_.frames() < static_cast<int>(number_of_frames)) { - // We don't DCHECK here, since this is a possible run-time condition - // if the machine is bogged down. - wrapper_bus_->Zero(); - return noErr; - } - - // Read from the FIFO to feed the varispeed. - fifo_.Consume(wrapper_bus_.get(), 0, number_of_frames); - - return noErr; -} - -OSStatus AudioSynchronizedStream::HandleOutputCallback( - AudioUnitRenderActionFlags* io_action_flags, - const AudioTimeStamp* time_stamp, - UInt32 bus_number, - UInt32 number_of_frames, - AudioBufferList* io_data) { - // Input callback hasn't run yet or we've suddenly changed sample-rates - // -> silence. - if (first_input_time_ < 0.0 || - static_cast<int>(number_of_frames) != params_.frames_per_buffer()) { - ZeroBufferList(io_data); - return noErr; - } - - // Use the varispeed playback rate to offset small discrepancies - // in hardware clocks, and also any differences in sample-rate - // between input and output devices. - - // Calculate a varispeed rate scalar factor to compensate for drift between - // input and output. We use the actual number of frames still in the FIFO - // compared with the ideal value of |target_fifo_frames_|. - int delta = fifo_.frames() - target_fifo_frames_; - - // Average |delta| because it can jitter back/forth quite frequently - // by +/- the hardware buffer-size *if* the input and output callbacks are - // happening at almost exactly the same time. Also, if the input and output - // sample-rates are different then |delta| will jitter quite a bit due to - // the rate conversion happening in the varispeed, plus the jittering of - // the callbacks. The average value is what's important here. - average_delta_ += (delta - average_delta_) * 0.1; - - // Compute a rate compensation which always attracts us back to the - // |target_fifo_frames_| over a period of kCorrectionTimeSeconds. - const double kCorrectionTimeSeconds = 0.1; - double correction_time_frames = kCorrectionTimeSeconds * output_sample_rate_; - fifo_rate_compensation_ = - (correction_time_frames + average_delta_) / correction_time_frames; - - // Adjust for FIFO drift. - OSStatus result = AudioUnitSetParameter( - varispeed_unit_, - kVarispeedParam_PlaybackRate, - kAudioUnitScope_Global, - 0, - fifo_rate_compensation_, - 0); - - OSSTATUS_DCHECK(result == noErr, result); - if (result != noErr) - return result; - - // Render to the output using the varispeed. - result = AudioUnitRender( - varispeed_unit_, - io_action_flags, - time_stamp, - 0, - number_of_frames, - io_data); - - OSSTATUS_DCHECK(result == noErr, result); - if (result != noErr) - return result; - - // Create a wrapper bus on the AudioBufferList. - WrapBufferList(io_data, wrapper_bus_.get(), number_of_frames); - - // Process in-place! - source_->OnMoreIOData(wrapper_bus_.get(), - wrapper_bus_.get(), - AudioBuffersState(0, 0)); - - return noErr; -} - -OSStatus AudioSynchronizedStream::InputProc( - void* user_data, - AudioUnitRenderActionFlags* io_action_flags, - const AudioTimeStamp* time_stamp, - UInt32 bus_number, - UInt32 number_of_frames, - AudioBufferList* io_data) { - AudioSynchronizedStream* stream = - static_cast<AudioSynchronizedStream*>(user_data); - DCHECK(stream); - - return stream->HandleInputCallback( - io_action_flags, - time_stamp, - bus_number, - number_of_frames, - io_data); -} - -OSStatus AudioSynchronizedStream::VarispeedProc( - void* user_data, - AudioUnitRenderActionFlags* io_action_flags, - const AudioTimeStamp* time_stamp, - UInt32 bus_number, - UInt32 number_of_frames, - AudioBufferList* io_data) { - AudioSynchronizedStream* stream = - static_cast<AudioSynchronizedStream*>(user_data); - DCHECK(stream); - - return stream->HandleVarispeedCallback( - io_action_flags, - time_stamp, - bus_number, - number_of_frames, - io_data); -} - -OSStatus AudioSynchronizedStream::OutputProc( - void* user_data, - AudioUnitRenderActionFlags* io_action_flags, - const AudioTimeStamp* time_stamp, - UInt32 bus_number, - UInt32 number_of_frames, - AudioBufferList* io_data) { - AudioSynchronizedStream* stream = - static_cast<AudioSynchronizedStream*>(user_data); - DCHECK(stream); - - return stream->HandleOutputCallback( - io_action_flags, - time_stamp, - bus_number, - number_of_frames, - io_data); -} - -void AudioSynchronizedStream::AudioDeviceInfo::Initialize( - AudioDeviceID id, bool is_input) { - id_ = id; - is_input_ = is_input; - if (id_ == kAudioDeviceUnknown) - return; - - UInt32 property_size = sizeof(buffer_size_frames_); - - AudioObjectPropertyAddress pa; - pa.mSelector = kAudioDevicePropertyBufferFrameSize; - pa.mScope = kAudioObjectPropertyScopeWildcard; - pa.mElement = kAudioObjectPropertyElementMaster; - OSStatus result = AudioObjectGetPropertyData( - id_, - &pa, - 0, - 0, - &property_size, - &buffer_size_frames_); - - OSSTATUS_DCHECK(result == noErr, result); -} - -} // namespace media diff --git a/media/audio/mac/audio_synchronized_mac.h b/media/audio/mac/audio_synchronized_mac.h deleted file mode 100644 index a6db48e..0000000 --- a/media/audio/mac/audio_synchronized_mac.h +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MEDIA_AUDIO_MAC_AUDIO_SYNCHRONIZED_MAC_H_ -#define MEDIA_AUDIO_MAC_AUDIO_SYNCHRONIZED_MAC_H_ - -#include <AudioToolbox/AudioToolbox.h> -#include <AudioUnit/AudioUnit.h> -#include <CoreAudio/CoreAudio.h> - -#include "base/compiler_specific.h" -#include "base/synchronization/lock.h" -#include "media/audio/audio_io.h" -#include "media/audio/audio_parameters.h" -#include "media/base/audio_bus.h" -#include "media/base/audio_fifo.h" - -namespace media { - -class AudioManagerMac; -class ChannelMixer; - -// AudioSynchronizedStream allows arbitrary combinations of input and output -// devices running off different clocks and using different drivers, with -// potentially differing sample-rates. It implements AudioOutputStream -// and shuttles its synchronized I/O data using AudioSourceCallback. -// -// It is required to first acquire the native sample rate of the selected -// output device and then use the same rate when creating this object. -// -// ............................................................................ -// Theory of Operation: -// . -// INPUT THREAD . OUTPUT THREAD -// +-----------------+ +------+ . -// | Input AudioUnit | --> | | . -// +-----------------+ | | . -// | FIFO | . -// | | +-----------+ -// | | -----> | Varispeed | -// | | +-----------+ -// +------+ . | -// . | +-----------+ -// . OnMoreIOData() --> | Output AU | -// . +-----------+ -// -// The input AudioUnit's InputProc is called on one thread which feeds the -// FIFO. The output AudioUnit's OutputProc is called on a second thread -// which pulls on the varispeed to get the current input data. The varispeed -// handles mismatches between input and output sample-rate and also clock drift -// between the input and output drivers. The varispeed consumes its data from -// the FIFO and adjusts its rate dynamically according to the amount -// of data buffered in the FIFO. If the FIFO starts getting too much data -// buffered then the varispeed will speed up slightly to compensate -// and similarly if the FIFO doesn't have enough data buffered then the -// varispeed will slow down slightly. -// -// Finally, once the input data is available then OnMoreIOData() is called -// which is given this input, and renders the output which is finally sent -// to the Output AudioUnit. -class AudioSynchronizedStream : public AudioOutputStream { - public: - // The ctor takes all the usual parameters, plus |manager| which is the - // the audio manager who is creating this object. - AudioSynchronizedStream(AudioManagerMac* manager, - const AudioParameters& params, - AudioDeviceID input_id, - AudioDeviceID output_id); - - virtual ~AudioSynchronizedStream(); - - // Implementation of AudioOutputStream. - virtual bool Open() OVERRIDE; - virtual void Close() OVERRIDE; - virtual void Start(AudioSourceCallback* callback) OVERRIDE; - virtual void Stop() OVERRIDE; - - virtual void SetVolume(double volume) OVERRIDE; - virtual void GetVolume(double* volume) OVERRIDE; - - OSStatus SetInputDeviceAsCurrent(AudioDeviceID input_id); - OSStatus SetOutputDeviceAsCurrent(AudioDeviceID output_id); - AudioDeviceID GetInputDeviceID() { return input_info_.id_; } - AudioDeviceID GetOutputDeviceID() { return output_info_.id_; } - - bool IsRunning(); - - private: - // Initialization. - OSStatus CreateAudioUnits(); - OSStatus SetupInput(AudioDeviceID input_id); - OSStatus EnableIO(); - OSStatus SetupOutput(AudioDeviceID output_id); - OSStatus SetupCallbacks(); - OSStatus SetupStreamFormats(); - void AllocateInputData(); - - // Handlers for the AudioUnit callbacks. - OSStatus HandleInputCallback(AudioUnitRenderActionFlags* io_action_flags, - const AudioTimeStamp* time_stamp, - UInt32 bus_number, - UInt32 number_of_frames, - AudioBufferList* io_data); - - OSStatus HandleVarispeedCallback(AudioUnitRenderActionFlags* io_action_flags, - const AudioTimeStamp* time_stamp, - UInt32 bus_number, - UInt32 number_of_frames, - AudioBufferList* io_data); - - OSStatus HandleOutputCallback(AudioUnitRenderActionFlags* io_action_flags, - const AudioTimeStamp* time_stamp, - UInt32 bus_number, - UInt32 number_of_frames, - AudioBufferList* io_data); - - // AudioUnit callbacks. - static OSStatus InputProc(void* user_data, - AudioUnitRenderActionFlags* io_action_flags, - const AudioTimeStamp* time_stamp, - UInt32 bus_number, - UInt32 number_of_frames, - AudioBufferList* io_data); - - static OSStatus VarispeedProc(void* user_data, - AudioUnitRenderActionFlags* io_action_flags, - const AudioTimeStamp* time_stamp, - UInt32 bus_number, - UInt32 number_of_frames, - AudioBufferList* io_data); - - static OSStatus OutputProc(void* user_data, - AudioUnitRenderActionFlags* io_action_flags, - const AudioTimeStamp* time_stamp, - UInt32 bus_number, - UInt32 number_of_frames, - AudioBufferList* io_data); - - // Our creator. - AudioManagerMac* manager_; - - // Client parameters. - AudioParameters params_; - - double input_sample_rate_; - double output_sample_rate_; - - // Pointer to the object that will provide the audio samples. - AudioSourceCallback* source_; - - // Values used in Open(). - AudioDeviceID input_id_; - AudioDeviceID output_id_; - - // The input AudioUnit renders its data here. - AudioBufferList* input_buffer_list_; - - // Holds the actual data for |input_buffer_list_|. - scoped_ptr<AudioBus> input_bus_; - - // Used to overlay AudioBufferLists. - scoped_ptr<AudioBus> wrapper_bus_; - - class AudioDeviceInfo { - public: - AudioDeviceInfo() - : id_(kAudioDeviceUnknown), - is_input_(false), - buffer_size_frames_(0) {} - void Initialize(AudioDeviceID inID, bool isInput); - bool IsInitialized() const { return id_ != kAudioDeviceUnknown; } - - AudioDeviceID id_; - bool is_input_; - UInt32 buffer_size_frames_; - }; - - AudioDeviceInfo input_info_; - AudioDeviceInfo output_info_; - - // Used for input to output buffering. - AudioFifo fifo_; - - // The optimal number of frames we'd like to keep in the FIFO at all times. - int target_fifo_frames_; - - // A running average of the measured delta between actual number of frames - // in the FIFO versus |target_fifo_frames_|. - double average_delta_; - - // A varispeed rate scalar which is calculated based on FIFO drift. - double fifo_rate_compensation_; - - // AudioUnits. - AudioUnit input_unit_; - AudioUnit varispeed_unit_; - AudioUnit output_unit_; - - double first_input_time_; - - bool is_running_; - int hardware_buffer_size_; - int channels_; - - // Channel mixer used to transform mono to stereo data. It is only created - // if the input_hardware_channels is mono. - scoped_ptr<ChannelMixer> channel_mixer_; - scoped_ptr<AudioBus> mixer_bus_; - - DISALLOW_COPY_AND_ASSIGN(AudioSynchronizedStream); -}; - -} // namespace media - -#endif // MEDIA_AUDIO_MAC_AUDIO_SYNCHRONIZED_MAC_H_ diff --git a/media/audio/mac/audio_unified_mac.cc b/media/audio/mac/audio_unified_mac.cc deleted file mode 100644 index d1dc007..0000000 --- a/media/audio/mac/audio_unified_mac.cc +++ /dev/null @@ -1,397 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "media/audio/mac/audio_unified_mac.h" - -#include <CoreServices/CoreServices.h> - -#include "base/basictypes.h" -#include "base/logging.h" -#include "base/mac/mac_logging.h" -#include "media/audio/mac/audio_manager_mac.h" - -namespace media { - -// TODO(crogers): support more than hard-coded stereo input. -// Ideally we would like to receive this value as a constructor argument. -static const int kDefaultInputChannels = 2; - -AudioHardwareUnifiedStream::AudioHardwareUnifiedStream( - AudioManagerMac* manager, const AudioParameters& params) - : manager_(manager), - source_(NULL), - client_input_channels_(kDefaultInputChannels), - volume_(1.0f), - input_channels_(0), - output_channels_(0), - input_channels_per_frame_(0), - output_channels_per_frame_(0), - io_proc_id_(0), - device_(kAudioObjectUnknown), - is_playing_(false) { - DCHECK(manager_); - - // A frame is one sample across all channels. In interleaved audio the per - // frame fields identify the set of n |channels|. In uncompressed audio, a - // packet is always one frame. - format_.mSampleRate = params.sample_rate(); - format_.mFormatID = kAudioFormatLinearPCM; - format_.mFormatFlags = kLinearPCMFormatFlagIsPacked | - kLinearPCMFormatFlagIsSignedInteger; - format_.mBitsPerChannel = params.bits_per_sample(); - format_.mChannelsPerFrame = params.channels(); - format_.mFramesPerPacket = 1; - format_.mBytesPerPacket = (format_.mBitsPerChannel * params.channels()) / 8; - format_.mBytesPerFrame = format_.mBytesPerPacket; - format_.mReserved = 0; - - // Calculate the number of sample frames per callback. - number_of_frames_ = params.GetBytesPerBuffer() / format_.mBytesPerPacket; - - input_bus_ = AudioBus::Create(client_input_channels_, - params.frames_per_buffer()); - output_bus_ = AudioBus::Create(params); -} - -AudioHardwareUnifiedStream::~AudioHardwareUnifiedStream() { - DCHECK_EQ(device_, kAudioObjectUnknown); -} - -bool AudioHardwareUnifiedStream::Open() { - // Obtain the current output device selected by the user. - AudioObjectPropertyAddress pa; - pa.mSelector = kAudioHardwarePropertyDefaultOutputDevice; - pa.mScope = kAudioObjectPropertyScopeGlobal; - pa.mElement = kAudioObjectPropertyElementMaster; - - UInt32 size = sizeof(device_); - - OSStatus result = AudioObjectGetPropertyData( - kAudioObjectSystemObject, - &pa, - 0, - 0, - &size, - &device_); - - if ((result != kAudioHardwareNoError) || (device_ == kAudioDeviceUnknown)) { - LOG(ERROR) << "Cannot open unified AudioDevice."; - return false; - } - - // The requested sample-rate must match the hardware sample-rate. - Float64 sample_rate = 0.0; - size = sizeof(sample_rate); - - pa.mSelector = kAudioDevicePropertyNominalSampleRate; - pa.mScope = kAudioObjectPropertyScopeWildcard; - pa.mElement = kAudioObjectPropertyElementMaster; - - result = AudioObjectGetPropertyData( - device_, - &pa, - 0, - 0, - &size, - &sample_rate); - - if (result != noErr || sample_rate != format_.mSampleRate) { - LOG(ERROR) << "Requested sample-rate: " << format_.mSampleRate - << " must match the hardware sample-rate: " << sample_rate; - return false; - } - - // Configure buffer frame size. - UInt32 frame_size = number_of_frames_; - - pa.mSelector = kAudioDevicePropertyBufferFrameSize; - pa.mScope = kAudioDevicePropertyScopeInput; - pa.mElement = kAudioObjectPropertyElementMaster; - result = AudioObjectSetPropertyData( - device_, - &pa, - 0, - 0, - sizeof(frame_size), - &frame_size); - - if (result != noErr) { - LOG(ERROR) << "Unable to set input buffer frame size: " << frame_size; - return false; - } - - pa.mScope = kAudioDevicePropertyScopeOutput; - result = AudioObjectSetPropertyData( - device_, - &pa, - 0, - 0, - sizeof(frame_size), - &frame_size); - - if (result != noErr) { - LOG(ERROR) << "Unable to set output buffer frame size: " << frame_size; - return false; - } - - DVLOG(1) << "Sample rate: " << sample_rate; - DVLOG(1) << "Frame size: " << frame_size; - - // Determine the number of input and output channels. - // We handle both the interleaved and non-interleaved cases. - - // Get input stream configuration. - pa.mSelector = kAudioDevicePropertyStreamConfiguration; - pa.mScope = kAudioDevicePropertyScopeInput; - pa.mElement = kAudioObjectPropertyElementMaster; - - result = AudioObjectGetPropertyDataSize(device_, &pa, 0, 0, &size); - OSSTATUS_DCHECK(result == noErr, result); - - if (result == noErr && size > 0) { - // Allocate storage. - scoped_ptr<uint8[]> input_list_storage(new uint8[size]); - AudioBufferList& input_list = - *reinterpret_cast<AudioBufferList*>(input_list_storage.get()); - - result = AudioObjectGetPropertyData( - device_, - &pa, - 0, - 0, - &size, - &input_list); - OSSTATUS_DCHECK(result == noErr, result); - - if (result == noErr) { - // Determine number of input channels. - input_channels_per_frame_ = input_list.mNumberBuffers > 0 ? - input_list.mBuffers[0].mNumberChannels : 0; - if (input_channels_per_frame_ == 1 && input_list.mNumberBuffers > 1) { - // Non-interleaved. - input_channels_ = input_list.mNumberBuffers; - } else { - // Interleaved. - input_channels_ = input_channels_per_frame_; - } - } - } - - DVLOG(1) << "Input channels: " << input_channels_; - DVLOG(1) << "Input channels per frame: " << input_channels_per_frame_; - - // The hardware must have at least the requested input channels. - if (result != noErr || client_input_channels_ > input_channels_) { - LOG(ERROR) << "AudioDevice does not support requested input channels."; - return false; - } - - // Get output stream configuration. - pa.mSelector = kAudioDevicePropertyStreamConfiguration; - pa.mScope = kAudioDevicePropertyScopeOutput; - pa.mElement = kAudioObjectPropertyElementMaster; - - result = AudioObjectGetPropertyDataSize(device_, &pa, 0, 0, &size); - OSSTATUS_DCHECK(result == noErr, result); - - if (result == noErr && size > 0) { - // Allocate storage. - scoped_ptr<uint8[]> output_list_storage(new uint8[size]); - AudioBufferList& output_list = - *reinterpret_cast<AudioBufferList*>(output_list_storage.get()); - - result = AudioObjectGetPropertyData( - device_, - &pa, - 0, - 0, - &size, - &output_list); - OSSTATUS_DCHECK(result == noErr, result); - - if (result == noErr) { - // Determine number of output channels. - output_channels_per_frame_ = output_list.mBuffers[0].mNumberChannels; - if (output_channels_per_frame_ == 1 && output_list.mNumberBuffers > 1) { - // Non-interleaved. - output_channels_ = output_list.mNumberBuffers; - } else { - // Interleaved. - output_channels_ = output_channels_per_frame_; - } - } - } - - DVLOG(1) << "Output channels: " << output_channels_; - DVLOG(1) << "Output channels per frame: " << output_channels_per_frame_; - - // The hardware must have at least the requested output channels. - if (result != noErr || - output_channels_ < static_cast<int>(format_.mChannelsPerFrame)) { - LOG(ERROR) << "AudioDevice does not support requested output channels."; - return false; - } - - // Setup the I/O proc. - result = AudioDeviceCreateIOProcID(device_, RenderProc, this, &io_proc_id_); - if (result != noErr) { - LOG(ERROR) << "Error creating IOProc."; - return false; - } - - return true; -} - -void AudioHardwareUnifiedStream::Close() { - DCHECK(!is_playing_); - - OSStatus result = AudioDeviceDestroyIOProcID(device_, io_proc_id_); - OSSTATUS_DCHECK(result == noErr, result); - - io_proc_id_ = 0; - device_ = kAudioObjectUnknown; - - // Inform the audio manager that we have been closed. This can cause our - // destruction. - manager_->ReleaseOutputStream(this); -} - -void AudioHardwareUnifiedStream::Start(AudioSourceCallback* callback) { - DCHECK(callback); - DCHECK_NE(device_, kAudioObjectUnknown); - DCHECK(!is_playing_); - if (device_ == kAudioObjectUnknown || is_playing_) - return; - - source_ = callback; - - OSStatus result = AudioDeviceStart(device_, io_proc_id_); - OSSTATUS_DCHECK(result == noErr, result); - - if (result == noErr) - is_playing_ = true; -} - -void AudioHardwareUnifiedStream::Stop() { - if (!is_playing_) - return; - - if (device_ != kAudioObjectUnknown) { - OSStatus result = AudioDeviceStop(device_, io_proc_id_); - OSSTATUS_DCHECK(result == noErr, result); - } - - is_playing_ = false; - source_ = NULL; -} - -void AudioHardwareUnifiedStream::SetVolume(double volume) { - volume_ = static_cast<float>(volume); - // TODO(crogers): set volume property -} - -void AudioHardwareUnifiedStream::GetVolume(double* volume) { - *volume = volume_; -} - -// Pulls on our provider with optional input, asking it to render output. -// Note to future hackers of this function: Do not add locks here because this -// is running on a real-time thread (for low-latency). -OSStatus AudioHardwareUnifiedStream::Render( - AudioDeviceID device, - const AudioTimeStamp* now, - const AudioBufferList* input_data, - const AudioTimeStamp* input_time, - AudioBufferList* output_data, - const AudioTimeStamp* output_time) { - // Convert the input data accounting for possible interleaving. - // TODO(crogers): it's better to simply memcpy() if source is already planar. - if (input_channels_ >= client_input_channels_) { - for (int channel_index = 0; channel_index < client_input_channels_; - ++channel_index) { - float* source; - - int source_channel_index = channel_index; - - if (input_channels_per_frame_ > 1) { - // Interleaved. - source = static_cast<float*>(input_data->mBuffers[0].mData) + - source_channel_index; - } else { - // Non-interleaved. - source = static_cast<float*>( - input_data->mBuffers[source_channel_index].mData); - } - - float* p = input_bus_->channel(channel_index); - for (int i = 0; i < number_of_frames_; ++i) { - p[i] = *source; - source += input_channels_per_frame_; - } - } - } else if (input_channels_) { - input_bus_->Zero(); - } - - // Give the client optional input data and have it render the output data. - source_->OnMoreIOData(input_bus_.get(), - output_bus_.get(), - AudioBuffersState(0, 0)); - - // TODO(crogers): handle final Core Audio 5.1 layout for 5.1 audio. - - // Handle interleaving as necessary. - // TODO(crogers): it's better to simply memcpy() if dest is already planar. - - for (int channel_index = 0; - channel_index < static_cast<int>(format_.mChannelsPerFrame); - ++channel_index) { - float* dest; - - int dest_channel_index = channel_index; - - if (output_channels_per_frame_ > 1) { - // Interleaved. - dest = static_cast<float*>(output_data->mBuffers[0].mData) + - dest_channel_index; - } else { - // Non-interleaved. - dest = static_cast<float*>( - output_data->mBuffers[dest_channel_index].mData); - } - - float* p = output_bus_->channel(channel_index); - for (int i = 0; i < number_of_frames_; ++i) { - *dest = p[i]; - dest += output_channels_per_frame_; - } - } - - return noErr; -} - -OSStatus AudioHardwareUnifiedStream::RenderProc( - AudioDeviceID device, - const AudioTimeStamp* now, - const AudioBufferList* input_data, - const AudioTimeStamp* input_time, - AudioBufferList* output_data, - const AudioTimeStamp* output_time, - void* user_data) { - AudioHardwareUnifiedStream* audio_output = - static_cast<AudioHardwareUnifiedStream*>(user_data); - DCHECK(audio_output); - if (!audio_output) - return -1; - - return audio_output->Render( - device, - now, - input_data, - input_time, - output_data, - output_time); -} - -} // namespace media diff --git a/media/audio/mac/audio_unified_mac.h b/media/audio/mac/audio_unified_mac.h deleted file mode 100644 index ff090e3..0000000 --- a/media/audio/mac/audio_unified_mac.h +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MEDIA_AUDIO_MAC_AUDIO_UNIFIED_MAC_H_ -#define MEDIA_AUDIO_MAC_AUDIO_UNIFIED_MAC_H_ - -#include <CoreAudio/CoreAudio.h> - -#include "base/memory/scoped_ptr.h" -#include "media/audio/audio_io.h" -#include "media/audio/audio_parameters.h" - -namespace media { - -class AudioManagerMac; - -// Implementation of AudioOutputStream for Mac OS X using the -// CoreAudio AudioHardware API suitable for low-latency unified audio I/O -// when using devices which support *both* input and output -// in the same driver. This is the case with professional -// USB and Firewire devices. -// -// Please note that it's required to first get the native sample-rate of the -// default output device and use that sample-rate when creating this object. -class AudioHardwareUnifiedStream : public AudioOutputStream { - public: - // The ctor takes all the usual parameters, plus |manager| which is the - // the audio manager who is creating this object. - AudioHardwareUnifiedStream(AudioManagerMac* manager, - const AudioParameters& params); - // The dtor is typically called by the AudioManager only and it is usually - // triggered by calling AudioOutputStream::Close(). - virtual ~AudioHardwareUnifiedStream(); - - // Implementation of AudioOutputStream. - virtual bool Open() OVERRIDE; - virtual void Close() OVERRIDE; - virtual void Start(AudioSourceCallback* callback) OVERRIDE; - virtual void Stop() OVERRIDE; - virtual void SetVolume(double volume) OVERRIDE; - virtual void GetVolume(double* volume) OVERRIDE; - - int input_channels() const { return input_channels_; } - int output_channels() const { return output_channels_; } - - private: - OSStatus Render(AudioDeviceID device, - const AudioTimeStamp* now, - const AudioBufferList* input_data, - const AudioTimeStamp* input_time, - AudioBufferList* output_data, - const AudioTimeStamp* output_time); - - static OSStatus RenderProc(AudioDeviceID device, - const AudioTimeStamp* now, - const AudioBufferList* input_data, - const AudioTimeStamp* input_time, - AudioBufferList* output_data, - const AudioTimeStamp* output_time, - void* user_data); - - // Our creator, the audio manager needs to be notified when we close. - AudioManagerMac* manager_; - - // Pointer to the object that will provide the audio samples. - AudioSourceCallback* source_; - - // Structure that holds the stream format details such as bitrate. - AudioStreamBasicDescription format_; - - // Hardware buffer size. - int number_of_frames_; - - // Number of audio channels provided to the client via OnMoreIOData(). - int client_input_channels_; - - // Volume level from 0 to 1. - float volume_; - - // Number of input and output channels queried from the hardware. - int input_channels_; - int output_channels_; - int input_channels_per_frame_; - int output_channels_per_frame_; - - AudioDeviceIOProcID io_proc_id_; - AudioDeviceID device_; - bool is_playing_; - - // Intermediate buffers used with call to OnMoreIOData(). - scoped_ptr<AudioBus> input_bus_; - scoped_ptr<AudioBus> output_bus_; - - DISALLOW_COPY_AND_ASSIGN(AudioHardwareUnifiedStream); -}; - -} // namespace media - -#endif // MEDIA_AUDIO_MAC_AUDIO_UNIFIED_MAC_H_ diff --git a/media/audio/mock_audio_manager.cc b/media/audio/mock_audio_manager.cc index 5984790..318bf09 100644 --- a/media/audio/mock_audio_manager.cc +++ b/media/audio/mock_audio_manager.cc @@ -47,16 +47,14 @@ void MockAudioManager::GetAudioOutputDeviceNames( media::AudioOutputStream* MockAudioManager::MakeAudioOutputStream( const media::AudioParameters& params, - const std::string& device_id, - const std::string& input_device_id) { + const std::string& device_id) { NOTREACHED(); return NULL; } media::AudioOutputStream* MockAudioManager::MakeAudioOutputStreamProxy( const media::AudioParameters& params, - const std::string& device_id, - const std::string& input_device_id) { + const std::string& device_id) { NOTREACHED(); return NULL; } diff --git a/media/audio/mock_audio_manager.h b/media/audio/mock_audio_manager.h index 0cd79e7..8ca4009 100644 --- a/media/audio/mock_audio_manager.h +++ b/media/audio/mock_audio_manager.h @@ -40,13 +40,11 @@ class MockAudioManager : public media::AudioManager { virtual media::AudioOutputStream* MakeAudioOutputStream( const media::AudioParameters& params, - const std::string& device_id, - const std::string& input_device_id) OVERRIDE; + const std::string& device_id) OVERRIDE; virtual media::AudioOutputStream* MakeAudioOutputStreamProxy( const media::AudioParameters& params, - const std::string& device_id, - const std::string& input_device_id) OVERRIDE; + const std::string& 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 b378b02..141689a 100644 --- a/media/audio/openbsd/audio_manager_openbsd.cc +++ b/media/audio/openbsd/audio_manager_openbsd.cc @@ -92,8 +92,7 @@ AudioOutputStream* AudioManagerOpenBSD::MakeLinearOutputStream( AudioOutputStream* AudioManagerOpenBSD::MakeLowLatencyOutputStream( const AudioParameters& params, - const std::string& device_id, - const std::string& input_device_id) { + const std::string& device_id) { DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!"; 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 113f591..53b7dfb 100644 --- a/media/audio/openbsd/audio_manager_openbsd.h +++ b/media/audio/openbsd/audio_manager_openbsd.h @@ -27,8 +27,7 @@ class MEDIA_EXPORT AudioManagerOpenBSD : public AudioManagerBase { const AudioParameters& params) OVERRIDE; virtual AudioOutputStream* MakeLowLatencyOutputStream( const AudioParameters& params, - const std::string& device_id, - const std::string& input_device_id) OVERRIDE; + const std::string& 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 da106c2..ea328ad 100644 --- a/media/audio/pulse/audio_manager_pulse.cc +++ b/media/audio/pulse/audio_manager_pulse.cc @@ -16,7 +16,6 @@ #include "media/audio/audio_parameters.h" #include "media/audio/pulse/pulse_input.h" #include "media/audio/pulse/pulse_output.h" -#include "media/audio/pulse/pulse_unified.h" #include "media/audio/pulse/pulse_util.h" #include "media/base/channel_layout.h" @@ -133,16 +132,15 @@ AudioParameters AudioManagerPulse::GetInputStreamParameters( AudioOutputStream* AudioManagerPulse::MakeLinearOutputStream( const AudioParameters& params) { DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); - return MakeOutputStream(params, std::string()); + return MakeOutputStream(params); } AudioOutputStream* AudioManagerPulse::MakeLowLatencyOutputStream( const AudioParameters& params, - const std::string& device_id, - const std::string& input_device_id) { + const std::string& device_id) { DLOG_IF(ERROR, !device_id.empty()) << "Not implemented!"; DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); - return MakeOutputStream(params, input_device_id); + return MakeOutputStream(params); } AudioInputStream* AudioManagerPulse::MakeLinearInputStream( @@ -189,11 +187,7 @@ AudioParameters AudioManagerPulse::GetPreferredOutputStreamParameters( } AudioOutputStream* AudioManagerPulse::MakeOutputStream( - const AudioParameters& params, const std::string& input_device_id) { - if (params.input_channels()) { - return new PulseAudioUnifiedStream(params, input_device_id, this); - } - + const AudioParameters& params) { return new PulseAudioOutputStream(params, this); } diff --git a/media/audio/pulse/audio_manager_pulse.h b/media/audio/pulse/audio_manager_pulse.h index 45fb8cb..b3b0031 100644 --- a/media/audio/pulse/audio_manager_pulse.h +++ b/media/audio/pulse/audio_manager_pulse.h @@ -37,8 +37,7 @@ class MEDIA_EXPORT AudioManagerPulse : public AudioManagerBase { const AudioParameters& params) OVERRIDE; virtual AudioOutputStream* MakeLowLatencyOutputStream( const AudioParameters& params, - const std::string& device_id, - const std::string& input_device_id) OVERRIDE; + const std::string& device_id) OVERRIDE; virtual AudioInputStream* MakeLinearInputStream( const AudioParameters& params, const std::string& device_id) OVERRIDE; virtual AudioInputStream* MakeLowLatencyInputStream( @@ -70,8 +69,7 @@ class MEDIA_EXPORT AudioManagerPulse : public AudioManagerBase { void* user_data); // Called by MakeLinearOutputStream and MakeLowLatencyOutputStream. - AudioOutputStream* MakeOutputStream(const AudioParameters& params, - const std::string& input_device_id); + AudioOutputStream* MakeOutputStream(const AudioParameters& params); // 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 deleted file mode 100644 index cd17b01..0000000 --- a/media/audio/pulse/pulse_unified.cc +++ /dev/null @@ -1,292 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "media/audio/pulse/pulse_unified.h" - -#include "base/single_thread_task_runner.h" -#include "base/time/time.h" -#include "media/audio/audio_manager_base.h" -#include "media/audio/audio_parameters.h" -#include "media/audio/pulse/pulse_util.h" -#include "media/base/seekable_buffer.h" - -namespace media { - -using pulse::AutoPulseLock; -using pulse::WaitForOperationCompletion; - -static const int kFifoSizeInPackets = 10; - -// static, pa_stream_notify_cb -void PulseAudioUnifiedStream::StreamNotifyCallback(pa_stream* s, - void* user_data) { - PulseAudioUnifiedStream* stream = - static_cast<PulseAudioUnifiedStream*>(user_data); - - // Forward unexpected failures to the AudioSourceCallback if available. All - // these variables are only modified under pa_threaded_mainloop_lock() so this - // should be thread safe. - if (s && stream->source_callback_ && - pa_stream_get_state(s) == PA_STREAM_FAILED) { - stream->source_callback_->OnError(stream); - } - - pa_threaded_mainloop_signal(stream->pa_mainloop_, 0); -} - -// static, used by pa_stream_set_read_callback. -void PulseAudioUnifiedStream::ReadCallback(pa_stream* handle, size_t length, - void* user_data) { - static_cast<PulseAudioUnifiedStream*>(user_data)->ReadData(); -} - -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), - input_stream_(NULL), - output_stream_(NULL), - volume_(1.0f), - source_callback_(NULL) { - DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread()); - CHECK(params_.IsValid()); - input_bus_ = AudioBus::Create(params_); - output_bus_ = AudioBus::Create(params_); -} - -PulseAudioUnifiedStream::~PulseAudioUnifiedStream() { - // All internal structures should already have been freed in Close(), which - // calls AudioManagerBase::ReleaseOutputStream() which deletes this object. - DCHECK(!input_stream_); - DCHECK(!output_stream_); - DCHECK(!pa_context_); - DCHECK(!pa_mainloop_); -} - -bool PulseAudioUnifiedStream::Open() { - DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread()); - // Prepare the recording buffers for the callbacks. - fifo_.reset(new media::SeekableBuffer( - 0, kFifoSizeInPackets * params_.GetBytesPerBuffer())); - input_data_buffer_.reset(new uint8[params_.GetBytesPerBuffer()]); - - if (!pulse::CreateOutputStream(&pa_mainloop_, &pa_context_, &output_stream_, - params_, &StreamNotifyCallback, NULL, this)) - return false; - - if (!pulse::CreateInputStream(pa_mainloop_, pa_context_, &input_stream_, - params_, input_device_id_, - &StreamNotifyCallback, this)) - return false; - - DCHECK(pa_mainloop_); - DCHECK(pa_context_); - DCHECK(input_stream_); - DCHECK(output_stream_); - return true; -} - -void PulseAudioUnifiedStream::Reset() { - if (!pa_mainloop_) { - DCHECK(!input_stream_); - DCHECK(!output_stream_); - DCHECK(!pa_context_); - return; - } - - { - AutoPulseLock auto_lock(pa_mainloop_); - - // Close the input stream. - if (input_stream_) { - // Disable all the callbacks before disconnecting. - pa_stream_set_state_callback(input_stream_, NULL, NULL); - pa_stream_flush(input_stream_, NULL, NULL); - pa_stream_disconnect(input_stream_); - - // Release PulseAudio structures. - pa_stream_unref(input_stream_); - input_stream_ = NULL; - } - - // Close the ouput stream. - if (output_stream_) { - // Release PulseAudio output stream structures. - pa_stream_set_state_callback(output_stream_, NULL, NULL); - pa_stream_disconnect(output_stream_); - pa_stream_unref(output_stream_); - output_stream_ = NULL; - } - - if (pa_context_) { - pa_context_disconnect(pa_context_); - pa_context_set_state_callback(pa_context_, NULL, NULL); - pa_context_unref(pa_context_); - pa_context_ = NULL; - } - } - - pa_threaded_mainloop_stop(pa_mainloop_); - pa_threaded_mainloop_free(pa_mainloop_); - pa_mainloop_ = NULL; -} - -void PulseAudioUnifiedStream::Close() { - DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread()); - Reset(); - - // Signal to the manager that we're closed and can be removed. - // This should be the last call in the function as it deletes "this". - manager_->ReleaseOutputStream(this); -} - -void PulseAudioUnifiedStream::WriteData(size_t requested_bytes) { - CHECK_EQ(requested_bytes, static_cast<size_t>(params_.GetBytesPerBuffer())); - - void* buffer = NULL; - int frames_filled = 0; - if (source_callback_) { - CHECK_GE(pa_stream_begin_write( - output_stream_, &buffer, &requested_bytes), 0); - uint32 hardware_delay = pulse::GetHardwareLatencyInBytes( - output_stream_, params_.sample_rate(), - params_.GetBytesPerFrame()); - fifo_->Read(input_data_buffer_.get(), requested_bytes); - input_bus_->FromInterleaved( - input_data_buffer_.get(), params_.frames_per_buffer(), 2); - - frames_filled = source_callback_->OnMoreIOData( - input_bus_.get(), - output_bus_.get(), - AudioBuffersState(0, hardware_delay)); - } - - // Zero the unfilled data so it plays back as silence. - if (frames_filled < output_bus_->frames()) { - output_bus_->ZeroFramesPartial( - frames_filled, output_bus_->frames() - frames_filled); - } - - // Note: If this ever changes to output raw float the data must be clipped - // and sanitized since it may come from an untrusted source such as NaCl. - output_bus_->Scale(volume_); - output_bus_->ToInterleaved( - output_bus_->frames(), params_.bits_per_sample() / 8, buffer); - - if (pa_stream_write(output_stream_, buffer, requested_bytes, NULL, 0LL, - PA_SEEK_RELATIVE) < 0) { - if (source_callback_) { - source_callback_->OnError(this); - } - } -} - -void PulseAudioUnifiedStream::ReadData() { - do { - size_t length = 0; - const void* data = NULL; - pa_stream_peek(input_stream_, &data, &length); - if (!data || length == 0) - break; - - fifo_->Append(reinterpret_cast<const uint8*>(data), length); - - // Deliver the recording data to the renderer and drive the playout. - int packet_size = params_.GetBytesPerBuffer(); - while (fifo_->forward_bytes() >= packet_size) { - WriteData(packet_size); - } - - // Checks if we still have data. - pa_stream_drop(input_stream_); - } while (pa_stream_readable_size(input_stream_) > 0); - - pa_threaded_mainloop_signal(pa_mainloop_, 0); -} - -void PulseAudioUnifiedStream::Start(AudioSourceCallback* callback) { - DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread()); - CHECK(callback); - CHECK(input_stream_); - CHECK(output_stream_); - AutoPulseLock auto_lock(pa_mainloop_); - - // Ensure the context and stream are ready. - if (pa_context_get_state(pa_context_) != PA_CONTEXT_READY && - pa_stream_get_state(output_stream_) != PA_STREAM_READY && - pa_stream_get_state(input_stream_) != PA_STREAM_READY) { - callback->OnError(this); - return; - } - - source_callback_ = callback; - - fifo_->Clear(); - - // Uncork (resume) the input stream. - pa_stream_set_read_callback(input_stream_, &ReadCallback, this); - pa_stream_readable_size(input_stream_); - pa_operation* operation = pa_stream_cork(input_stream_, 0, NULL, NULL); - WaitForOperationCompletion(pa_mainloop_, operation); - - // Uncork (resume) the output stream. - // We use the recording stream to drive the playback, so we do not need to - // register the write callback using pa_stream_set_write_callback(). - operation = pa_stream_cork(output_stream_, 0, - &pulse::StreamSuccessCallback, pa_mainloop_); - WaitForOperationCompletion(pa_mainloop_, operation); -} - -void PulseAudioUnifiedStream::Stop() { - DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread()); - - // Cork (pause) the stream. Waiting for the main loop lock will ensure - // outstanding callbacks have completed. - AutoPulseLock auto_lock(pa_mainloop_); - - // Set |source_callback_| to NULL so all FulfillWriteRequest() calls which may - // occur while waiting on the flush and cork exit immediately. - source_callback_ = NULL; - - // Set the read callback to NULL before flushing the stream, otherwise it - // will cause deadlock on the operation. - pa_stream_set_read_callback(input_stream_, NULL, NULL); - pa_operation* operation = pa_stream_flush( - input_stream_, &pulse::StreamSuccessCallback, pa_mainloop_); - WaitForOperationCompletion(pa_mainloop_, operation); - - operation = pa_stream_cork(input_stream_, 1, &pulse::StreamSuccessCallback, - pa_mainloop_); - WaitForOperationCompletion(pa_mainloop_, operation); - - // Flush the stream prior to cork, doing so after will cause hangs. Write - // callbacks are suspended while inside pa_threaded_mainloop_lock() so this - // is all thread safe. - operation = pa_stream_flush( - output_stream_, &pulse::StreamSuccessCallback, pa_mainloop_); - WaitForOperationCompletion(pa_mainloop_, operation); - - operation = pa_stream_cork(output_stream_, 1, &pulse::StreamSuccessCallback, - pa_mainloop_); - WaitForOperationCompletion(pa_mainloop_, operation); -} - -void PulseAudioUnifiedStream::SetVolume(double volume) { - DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread()); - - volume_ = static_cast<float>(volume); -} - -void PulseAudioUnifiedStream::GetVolume(double* volume) { - DCHECK(manager_->GetTaskRunner()->BelongsToCurrentThread()); - - *volume = volume_; -} - -} // namespace media diff --git a/media/audio/pulse/pulse_unified.h b/media/audio/pulse/pulse_unified.h deleted file mode 100644 index a800d09..0000000 --- a/media/audio/pulse/pulse_unified.h +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MEDIA_AUDIO_PULSE_PULSE_UNIFIED_H_ -#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" -#include "media/audio/audio_parameters.h" -#include "media/base/audio_fifo.h" - -namespace media { - -class AudioManagerBase; -class SeekableBuffer; - -class PulseAudioUnifiedStream : public AudioOutputStream { - public: - PulseAudioUnifiedStream(const AudioParameters& params, - const std::string& input_device_id, - AudioManagerBase* manager); - - virtual ~PulseAudioUnifiedStream(); - - // Implementation of PulseAudioUnifiedStream. - virtual bool Open() OVERRIDE; - virtual void Close() OVERRIDE; - virtual void Start(AudioSourceCallback* callback) OVERRIDE; - virtual void Stop() OVERRIDE; - virtual void SetVolume(double volume) OVERRIDE; - virtual void GetVolume(double* volume) OVERRIDE; - - private: - // Called by PulseAudio when |pa_stream_| change state. If an unexpected - // failure state change happens and |source_callback_| is set - // this method will forward the error via OnError(). - static void StreamNotifyCallback(pa_stream* s, void* user_data); - - // Called by PulseAudio recording stream when it has data. - static void ReadCallback(pa_stream* s, size_t length, void* user_data); - - // Helpers for ReadCallback() to read and write data. - void WriteData(size_t requested_bytes); - void ReadData(); - - // Close() helper function to free internal structs. - void Reset(); - - // 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_; - - // PulseAudio API structs. - pa_context* pa_context_; - pa_threaded_mainloop* pa_mainloop_; - pa_stream* input_stream_; - pa_stream* output_stream_; - - // Float representation of volume from 0.0 to 1.0. - float volume_; - - // Callback to audio data source. Must only be modified while holding a lock - // on |pa_mainloop_| via pa_threaded_mainloop_lock(). - AudioSourceCallback* source_callback_; - - scoped_ptr<AudioBus> input_bus_; - scoped_ptr<AudioBus> output_bus_; - - // Used for input to output buffering. - scoped_ptr<media::SeekableBuffer> fifo_; - - // Temporary storage for recorded data. It gets a packet of data from - // |fifo_| and deliver the data to OnMoreIOData() callback. - scoped_ptr<uint8[]> input_data_buffer_; - - DISALLOW_COPY_AND_ASSIGN(PulseAudioUnifiedStream); -}; - -} // namespace media - -#endif // MEDIA_AUDIO_PULSE_PULSE_UNIFIED_H_ diff --git a/media/audio/sounds/audio_stream_handler.cc b/media/audio/sounds/audio_stream_handler.cc index f286356..9452f04 100644 --- a/media/audio/sounds/audio_stream_handler.cc +++ b/media/audio/sounds/audio_stream_handler.cc @@ -59,7 +59,7 @@ class AudioStreamHandler::AudioStreamContainer p.bits_per_sample(), kDefaultFrameCount); stream_ = AudioManager::Get()->MakeAudioOutputStreamProxy( - params, std::string(), std::string()); + params, std::string()); if (!stream_ || !stream_->Open()) { LOG(ERROR) << "Failed to open an output stream."; return; 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 66d3891..c2b4d97 100644 --- a/media/audio/win/audio_low_latency_output_win_unittest.cc +++ b/media/audio/win/audio_low_latency_output_win_unittest.cc @@ -224,7 +224,7 @@ class AudioOutputStreamWrapper { AudioOutputStream* aos = audio_man_->MakeAudioOutputStream( AudioParameters(format_, channel_layout_, sample_rate_, bits_per_sample_, samples_per_packet_), - std::string(), std::string()); + std::string()); EXPECT_TRUE(aos); return aos; } diff --git a/media/audio/win/audio_manager_win.cc b/media/audio/win/audio_manager_win.cc index ec963a7..a8678cd 100644 --- a/media/audio/win/audio_manager_win.cc +++ b/media/audio/win/audio_manager_win.cc @@ -26,7 +26,6 @@ #include "media/audio/win/audio_low_latency_input_win.h" #include "media/audio/win/audio_low_latency_output_win.h" #include "media/audio/win/audio_manager_win.h" -#include "media/audio/win/audio_unified_win.h" #include "media/audio/win/core_audio_util_win.h" #include "media/audio/win/device_enumeration_win.h" #include "media/audio/win/wavein_input_win.h" @@ -353,8 +352,7 @@ AudioOutputStream* AudioManagerWin::MakeLinearOutputStream( // - WASAPIAudioOutputStream: Based on Core Audio (WASAPI) API. AudioOutputStream* AudioManagerWin::MakeLowLatencyOutputStream( const AudioParameters& params, - const std::string& device_id, - const std::string& input_device_id) { + const std::string& device_id) { DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); if (params.channels() > kWinMaxChannels) return NULL; @@ -369,15 +367,6 @@ AudioOutputStream* AudioManagerWin::MakeLowLatencyOutputStream( this, params, NumberOfWaveOutBuffers(), WAVE_MAPPER); } - // TODO(rtoy): support more than stereo input. - if (params.input_channels() > 0) { - DVLOG(1) << "WASAPIUnifiedStream is created."; - DLOG_IF(ERROR, !device_id.empty() && - device_id != AudioManagerBase::kDefaultDeviceId) - << "Opening by device id not supported by WASAPIUnifiedStream"; - return new WASAPIUnifiedStream(this, params, input_device_id); - } - // Pass an empty string to indicate that we want the default device // since we consistently only check for an empty string in // WASAPIAudioOutputStream. diff --git a/media/audio/win/audio_manager_win.h b/media/audio/win/audio_manager_win.h index c2ac8d7..3a05ee6 100644 --- a/media/audio/win/audio_manager_win.h +++ b/media/audio/win/audio_manager_win.h @@ -39,8 +39,7 @@ class MEDIA_EXPORT AudioManagerWin : public AudioManagerBase { const AudioParameters& params) OVERRIDE; virtual AudioOutputStream* MakeLowLatencyOutputStream( const AudioParameters& params, - const std::string& device_id, - const std::string& input_device_id) OVERRIDE; + const std::string& 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 dcb5ca3..72edad6 100644 --- a/media/audio/win/audio_output_win_unittest.cc +++ b/media/audio/win/audio_output_win_unittest.cc @@ -175,7 +175,7 @@ TEST(WinAudioTest, PCMWaveStreamGetAndClose) { AudioOutputStream* oas = audio_man->MakeAudioOutputStream( AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO, 8000, 16, 256), - std::string(), std::string()); + std::string()); ASSERT_TRUE(NULL != oas); oas->Close(); } @@ -191,29 +191,29 @@ TEST(WinAudioTest, SanityOnMakeParams) { AudioParameters::Format fmt = AudioParameters::AUDIO_PCM_LINEAR; EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream( AudioParameters(fmt, CHANNEL_LAYOUT_UNSUPPORTED, 8000, 16, 256), - std::string(), std::string())); + std::string())); EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream( AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 1024 * 1024, 16, 256), - std::string(), std::string())); + std::string())); EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream( AudioParameters(fmt, CHANNEL_LAYOUT_STEREO, 8000, 80, 256), - std::string(), std::string())); + std::string())); EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream( AudioParameters(fmt, CHANNEL_LAYOUT_UNSUPPORTED, 8000, 16, 256), - std::string(), std::string())); + std::string())); EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream( AudioParameters(fmt, CHANNEL_LAYOUT_STEREO, -8000, 16, 256), - std::string(), std::string())); + std::string())); EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream( AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16, -100), - std::string(), std::string())); + std::string())); EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream( AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16, 0), - std::string(), std::string())); + std::string())); EXPECT_TRUE(NULL == audio_man->MakeAudioOutputStream( AudioParameters(fmt, CHANNEL_LAYOUT_MONO, 8000, 16, media::limits::kMaxSamplesPerPacket + 1), - std::string(), std::string())); + std::string())); } // Test that it can be opened and closed. @@ -227,7 +227,7 @@ TEST(WinAudioTest, PCMWaveStreamOpenAndClose) { AudioOutputStream* oas = audio_man->MakeAudioOutputStream( AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO, 8000, 16, 256), - std::string(), std::string()); + std::string()); ASSERT_TRUE(NULL != oas); EXPECT_TRUE(oas->Open()); oas->Close(); @@ -244,7 +244,7 @@ TEST(WinAudioTest, PCMWaveStreamOpenLimit) { AudioOutputStream* oas = audio_man->MakeAudioOutputStream( AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO, 8000, 16, 1024 * 1024 * 1024), - std::string(), std::string()); + std::string()); EXPECT_TRUE(NULL == oas); if (oas) oas->Close(); @@ -263,7 +263,7 @@ TEST(WinAudioTest, PCMWaveSlowSource) { AudioOutputStream* oas = audio_man->MakeAudioOutputStream( AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, 16000, 16, 256), - std::string(), std::string()); + std::string()); ASSERT_TRUE(NULL != oas); TestSourceLaggy test_laggy(2, 90); EXPECT_TRUE(oas->Open()); @@ -292,7 +292,7 @@ TEST(WinAudioTest, PCMWaveStreamPlaySlowLoop) { AudioOutputStream* oas = audio_man->MakeAudioOutputStream( AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, AudioParameters::kAudioCDSampleRate, 16, samples_100_ms), - std::string(), std::string()); + std::string()); ASSERT_TRUE(NULL != oas); SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate); @@ -323,7 +323,7 @@ TEST(WinAudioTest, PCMWaveStreamPlay200HzTone44Kss) { AudioOutputStream* oas = audio_man->MakeAudioOutputStream( AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, AudioParameters::kAudioCDSampleRate, 16, samples_100_ms), - std::string(), std::string()); + std::string()); ASSERT_TRUE(NULL != oas); SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate); @@ -352,7 +352,7 @@ TEST(WinAudioTest, PCMWaveStreamPlay200HzTone22Kss) { AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, AudioParameters::kAudioCDSampleRate / 2, 16, samples_100_ms), - std::string(), std::string()); + std::string()); ASSERT_TRUE(NULL != oas); SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate/2); @@ -392,7 +392,7 @@ TEST(WinAudioTest, PushSourceFile16KHz) { AudioOutputStream* oas = audio_man->MakeAudioOutputStream( AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, kSampleRate, 16, kSamples100ms), - std::string(), std::string()); + std::string()); ASSERT_TRUE(NULL != oas); EXPECT_TRUE(oas->Open()); @@ -429,7 +429,7 @@ TEST(WinAudioTest, PCMWaveStreamPlayTwice200HzTone44Kss) { AudioOutputStream* oas = audio_man->MakeAudioOutputStream( AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, AudioParameters::kAudioCDSampleRate, 16, samples_100_ms), - std::string(), std::string()); + std::string()); ASSERT_TRUE(NULL != oas); SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate); @@ -476,7 +476,7 @@ TEST(WinAudioTest, PCMWaveStreamPlay200HzToneLowLatency) { AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_MONO, sample_rate, 16, n * samples_10_ms), - std::string(), std::string()); + std::string()); ASSERT_TRUE(NULL != oas); SineWaveAudioSource source(1, 200, sample_rate); @@ -510,7 +510,7 @@ TEST(WinAudioTest, PCMWaveStreamPendingBytes) { AudioOutputStream* oas = audio_man->MakeAudioOutputStream( AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, AudioParameters::kAudioCDSampleRate, 16, samples_100_ms), - std::string(), std::string()); + std::string()); ASSERT_TRUE(NULL != oas); NiceMock<MockAudioSourceCallback> source; @@ -664,7 +664,7 @@ TEST(WinAudioTest, SyncSocketBasic) { AudioOutputStream* oas = audio_man->MakeAudioOutputStream(params, - std::string(), std::string()); + std::string()); ASSERT_TRUE(NULL != oas); ASSERT_TRUE(oas->Open()); diff --git a/media/audio/win/audio_unified_win.cc b/media/audio/win/audio_unified_win.cc deleted file mode 100644 index 901c8b8..0000000 --- a/media/audio/win/audio_unified_win.cc +++ /dev/null @@ -1,984 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "media/audio/win/audio_unified_win.h" - -#include <Functiondiscoverykeys_devpkey.h> - -#include "base/debug/trace_event.h" -#ifndef NDEBUG -#include "base/file_util.h" -#include "base/path_service.h" -#endif -#include "base/time/time.h" -#include "base/win/scoped_com_initializer.h" -#include "media/audio/win/audio_manager_win.h" -#include "media/audio/win/avrt_wrapper_win.h" -#include "media/audio/win/core_audio_util_win.h" - -using base::win::ScopedComPtr; -using base::win::ScopedCOMInitializer; -using base::win::ScopedCoMem; - -// Smoothing factor in exponential smoothing filter where 0 < alpha < 1. -// Larger values of alpha reduce the level of smoothing. -// See http://en.wikipedia.org/wiki/Exponential_smoothing for details. -static const double kAlpha = 0.1; - -// Compute a rate compensation which always attracts us back to a specified -// target level over a period of |kCorrectionTimeSeconds|. -static const double kCorrectionTimeSeconds = 0.1; - -#ifndef NDEBUG -// Max number of columns in the output text file |kUnifiedAudioDebugFileName|. -// See LogElementNames enumerator for details on what each column represents. -static const size_t kMaxNumSampleTypes = 4; - -static const size_t kMaxNumParams = 2; - -// Max number of rows in the output file |kUnifiedAudioDebugFileName|. -// Each row corresponds to one set of sample values for (approximately) the -// same time instant (stored in the first column). -static const size_t kMaxFileSamples = 10000; - -// Name of output debug file used for off-line analysis of measurements which -// can be utilized for performance tuning of this class. -static const char kUnifiedAudioDebugFileName[] = "unified_win_debug.txt"; - -// Name of output debug file used for off-line analysis of measurements. -// This file will contain a list of audio parameters. -static const char kUnifiedAudioParamsFileName[] = "unified_win_params.txt"; -#endif - -// Use the acquired IAudioClock interface to derive a time stamp of the audio -// sample which is currently playing through the speakers. -static double SpeakerStreamPosInMilliseconds(IAudioClock* clock) { - UINT64 device_frequency = 0, position = 0; - if (FAILED(clock->GetFrequency(&device_frequency)) || - FAILED(clock->GetPosition(&position, NULL))) { - return 0.0; - } - return base::Time::kMillisecondsPerSecond * - (static_cast<double>(position) / device_frequency); -} - -// Get a time stamp in milliseconds given number of audio frames in |num_frames| -// using the current sample rate |fs| as scale factor. -// Example: |num_frames| = 960 and |fs| = 48000 => 20 [ms]. -static double CurrentStreamPosInMilliseconds(UINT64 num_frames, DWORD fs) { - return base::Time::kMillisecondsPerSecond * - (static_cast<double>(num_frames) / fs); -} - -// Convert a timestamp in milliseconds to byte units given the audio format -// in |format|. -// Example: |ts_milliseconds| equals 10, sample rate is 48000 and frame size -// is 4 bytes per audio frame => 480 * 4 = 1920 [bytes]. -static int MillisecondsToBytes(double ts_milliseconds, - const WAVEFORMATPCMEX& format) { - double seconds = ts_milliseconds / base::Time::kMillisecondsPerSecond; - return static_cast<int>(seconds * format.Format.nSamplesPerSec * - format.Format.nBlockAlign + 0.5); -} - -// Convert frame count to milliseconds given the audio format in |format|. -static double FrameCountToMilliseconds(int num_frames, - const WAVEFORMATPCMEX& format) { - return (base::Time::kMillisecondsPerSecond * num_frames) / - static_cast<double>(format.Format.nSamplesPerSec); -} - -namespace media { - -WASAPIUnifiedStream::WASAPIUnifiedStream(AudioManagerWin* manager, - 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()), - opened_(false), - volume_(1.0), - output_buffer_size_frames_(0), - input_buffer_size_frames_(0), - endpoint_render_buffer_size_frames_(0), - endpoint_capture_buffer_size_frames_(0), - num_written_frames_(0), - total_delay_ms_(0.0), - total_delay_bytes_(0), - source_(NULL), - input_callback_received_(false), - io_sample_rate_ratio_(1), - target_fifo_frames_(0), - average_delta_(0), - fifo_rate_compensation_(1), - update_output_delay_(false), - capture_delay_ms_(0) { - TRACE_EVENT0("audio", "WASAPIUnifiedStream::WASAPIUnifiedStream"); - VLOG(1) << "WASAPIUnifiedStream::WASAPIUnifiedStream()"; - DCHECK(manager_); - - VLOG(1) << "Input channels : " << input_channels_; - VLOG(1) << "Output channels: " << output_channels_; - VLOG(1) << "Sample rate : " << params_.sample_rate(); - VLOG(1) << "Buffer size : " << params.frames_per_buffer(); - -#ifndef NDEBUG - input_time_stamps_.reset(new int64[kMaxFileSamples]); - num_frames_in_fifo_.reset(new int[kMaxFileSamples]); - resampler_margin_.reset(new int[kMaxFileSamples]); - fifo_rate_comps_.reset(new double[kMaxFileSamples]); - num_elements_.reset(new int[kMaxNumSampleTypes]); - std::fill(num_elements_.get(), num_elements_.get() + kMaxNumSampleTypes, 0); - input_params_.reset(new int[kMaxNumParams]); - output_params_.reset(new int[kMaxNumParams]); -#endif - - DVLOG_IF(1, share_mode_ == AUDCLNT_SHAREMODE_EXCLUSIVE) - << "Core Audio (WASAPI) EXCLUSIVE MODE is enabled."; - - // Load the Avrt DLL if not already loaded. Required to support MMCSS. - bool avrt_init = avrt::Initialize(); - DCHECK(avrt_init) << "Failed to load the avrt.dll"; - - // All events are auto-reset events and non-signaled initially. - - // Create the event which the audio engine will signal each time a buffer - // has been recorded. - capture_event_.Set(CreateEvent(NULL, FALSE, FALSE, NULL)); - - // Create the event which will be set in Stop() when straeming shall stop. - stop_streaming_event_.Set(CreateEvent(NULL, FALSE, FALSE, NULL)); -} - -WASAPIUnifiedStream::~WASAPIUnifiedStream() { - VLOG(1) << "WASAPIUnifiedStream::~WASAPIUnifiedStream()"; -#ifndef NDEBUG - base::FilePath data_file_name; - PathService::Get(base::DIR_EXE, &data_file_name); - data_file_name = data_file_name.AppendASCII(kUnifiedAudioDebugFileName); - data_file_ = base::OpenFile(data_file_name, "wt"); - DVLOG(1) << ">> Output file " << data_file_name.value() << " is created."; - - size_t n = 0; - size_t elements_to_write = *std::min_element( - num_elements_.get(), num_elements_.get() + kMaxNumSampleTypes); - while (n < elements_to_write) { - fprintf(data_file_, "%I64d %d %d %10.9f\n", - input_time_stamps_[n], - num_frames_in_fifo_[n], - resampler_margin_[n], - fifo_rate_comps_[n]); - ++n; - } - base::CloseFile(data_file_); - - base::FilePath param_file_name; - PathService::Get(base::DIR_EXE, ¶m_file_name); - param_file_name = param_file_name.AppendASCII(kUnifiedAudioParamsFileName); - param_file_ = base::OpenFile(param_file_name, "wt"); - DVLOG(1) << ">> Output file " << param_file_name.value() << " is created."; - fprintf(param_file_, "%d %d\n", input_params_[0], input_params_[1]); - fprintf(param_file_, "%d %d\n", output_params_[0], output_params_[1]); - base::CloseFile(param_file_); -#endif -} - -bool WASAPIUnifiedStream::Open() { - TRACE_EVENT0("audio", "WASAPIUnifiedStream::Open"); - DVLOG(1) << "WASAPIUnifiedStream::Open()"; - DCHECK_EQ(GetCurrentThreadId(), creating_thread_id_); - if (opened_) - return true; - - AudioParameters hw_output_params; - HRESULT hr = CoreAudioUtil::GetPreferredAudioParameters( - eRender, eConsole, &hw_output_params); - if (FAILED(hr)) { - LOG(ERROR) << "Failed to get preferred output audio parameters."; - return false; - } - - AudioParameters hw_input_params; - if (input_device_id_ == AudioManagerBase::kDefaultDeviceId) { - // Query native parameters for the default capture device. - hr = CoreAudioUtil::GetPreferredAudioParameters( - eCapture, eConsole, &hw_input_params); - } else { - // Query native parameters for the capture device given by - // |input_device_id_|. - hr = CoreAudioUtil::GetPreferredAudioParameters( - input_device_id_, &hw_input_params); - } - if (FAILED(hr)) { - LOG(ERROR) << "Failed to get preferred input audio parameters."; - return false; - } - - // It is currently only possible to open up the output audio device using - // the native number of channels. - if (output_channels_ != hw_output_params.channels()) { - LOG(ERROR) << "Audio device does not support requested output channels."; - return false; - } - - // It is currently only possible to open up the input audio device using - // the native number of channels. If the client asks for a higher channel - // count, we will do channel upmixing in this class. The most typical - // example is that the client provides stereo but the hardware can only be - // opened in mono mode. We will do mono to stereo conversion in this case. - if (input_channels_ < hw_input_params.channels()) { - LOG(ERROR) << "Audio device does not support requested input channels."; - return false; - } else if (input_channels_ > hw_input_params.channels()) { - ChannelLayout input_layout = - GuessChannelLayout(hw_input_params.channels()); - ChannelLayout output_layout = GuessChannelLayout(input_channels_); - channel_mixer_.reset(new ChannelMixer(input_layout, output_layout)); - DVLOG(1) << "Remixing input channel layout from " << input_layout - << " to " << output_layout << "; from " - << hw_input_params.channels() << " channels to " - << input_channels_; - } - - if (hw_output_params.sample_rate() != params_.sample_rate()) { - LOG(ERROR) << "Requested sample-rate: " << params_.sample_rate() - << " must match the hardware sample-rate: " - << hw_output_params.sample_rate(); - return false; - } - - if (hw_output_params.frames_per_buffer() != params_.frames_per_buffer()) { - LOG(ERROR) << "Requested buffer size: " << params_.frames_per_buffer() - << " must match the hardware buffer size: " - << hw_output_params.frames_per_buffer(); - return false; - } - - // Set up WAVEFORMATPCMEX structures for input and output given the specified - // audio parameters. - SetIOFormats(hw_input_params, params_); - - // Create the input and output busses. - input_bus_ = AudioBus::Create( - hw_input_params.channels(), input_buffer_size_frames_); - output_bus_ = AudioBus::Create(params_); - - // One extra bus is needed for the input channel mixing case. - if (channel_mixer_) { - DCHECK_LT(hw_input_params.channels(), input_channels_); - // The size of the |channel_bus_| must be the same as the size of the - // output bus to ensure that the channel manager can deal with both - // resampled and non-resampled data as input. - channel_bus_ = AudioBus::Create( - input_channels_, params_.frames_per_buffer()); - } - - // Check if FIFO and resampling is required to match the input rate to the - // output rate. If so, a special thread loop, optimized for this case, will - // be used. This mode is also called varispeed mode. - // Note that we can also use this mode when input and output rates are the - // same but native buffer sizes differ (can happen if two different audio - // devices are used). For this case, the resampler uses a target ratio of - // 1.0 but SetRatio is called to compensate for clock-drift. The FIFO is - // required to compensate for the difference in buffer sizes. - // TODO(henrika): we could perhaps improve the performance for the second - // case here by only using the FIFO and avoid resampling. Not sure how much - // that would give and we risk not compensation for clock drift. - if (hw_input_params.sample_rate() != params_.sample_rate() || - hw_input_params.frames_per_buffer() != params_.frames_per_buffer()) { - DoVarispeedInitialization(hw_input_params, params_); - } - - // Render side (event driven only in varispeed mode): - - ScopedComPtr<IAudioClient> audio_output_client = - CoreAudioUtil::CreateDefaultClient(eRender, eConsole); - if (!audio_output_client) - return false; - - if (!CoreAudioUtil::IsFormatSupported(audio_output_client, - share_mode_, - &output_format_)) { - return false; - } - - if (share_mode_ == AUDCLNT_SHAREMODE_SHARED) { - // The |render_event_| will be NULL unless varispeed mode is utilized. - hr = CoreAudioUtil::SharedModeInitialize( - audio_output_client, &output_format_, render_event_.Get(), - &endpoint_render_buffer_size_frames_); - } else { - // TODO(henrika): add support for AUDCLNT_SHAREMODE_EXCLUSIVE. - } - if (FAILED(hr)) - return false; - - ScopedComPtr<IAudioRenderClient> audio_render_client = - CoreAudioUtil::CreateRenderClient(audio_output_client); - if (!audio_render_client) - return false; - - // Capture side (always event driven but format depends on varispeed or not): - - ScopedComPtr<IAudioClient> audio_input_client; - if (input_device_id_ == AudioManagerBase::kDefaultDeviceId) { - audio_input_client = CoreAudioUtil::CreateDefaultClient(eCapture, eConsole); - } else { - ScopedComPtr<IMMDevice> audio_input_device( - CoreAudioUtil::CreateDevice(input_device_id_)); - audio_input_client = CoreAudioUtil::CreateClient(audio_input_device); - } - if (!audio_input_client) - return false; - - if (!CoreAudioUtil::IsFormatSupported(audio_input_client, - share_mode_, - &input_format_)) { - return false; - } - - if (share_mode_ == AUDCLNT_SHAREMODE_SHARED) { - // Include valid event handle for event-driven initialization. - // The input side is always event driven independent of if varispeed is - // used or not. - hr = CoreAudioUtil::SharedModeInitialize( - audio_input_client, &input_format_, capture_event_.Get(), - &endpoint_capture_buffer_size_frames_); - } else { - // TODO(henrika): add support for AUDCLNT_SHAREMODE_EXCLUSIVE. - } - if (FAILED(hr)) - return false; - - ScopedComPtr<IAudioCaptureClient> audio_capture_client = - CoreAudioUtil::CreateCaptureClient(audio_input_client); - if (!audio_capture_client) - return false; - - // Varispeed mode requires additional preparations. - if (VarispeedMode()) - ResetVarispeed(); - - // Store all valid COM interfaces. - audio_output_client_ = audio_output_client; - audio_render_client_ = audio_render_client; - audio_input_client_ = audio_input_client; - audio_capture_client_ = audio_capture_client; - - opened_ = true; - return SUCCEEDED(hr); -} - -void WASAPIUnifiedStream::Start(AudioSourceCallback* callback) { - TRACE_EVENT0("audio", "WASAPIUnifiedStream::Start"); - DVLOG(1) << "WASAPIUnifiedStream::Start()"; - DCHECK_EQ(GetCurrentThreadId(), creating_thread_id_); - CHECK(callback); - CHECK(opened_); - - if (audio_io_thread_) { - CHECK_EQ(callback, source_); - return; - } - - source_ = callback; - - if (VarispeedMode()) { - ResetVarispeed(); - fifo_rate_compensation_ = 1.0; - average_delta_ = 0.0; - input_callback_received_ = false; - update_output_delay_ = false; - } - - // Create and start the thread that will listen for capture events. - // We will also listen on render events on the same thread if varispeed - // mode is utilized. - audio_io_thread_.reset( - new base::DelegateSimpleThread(this, "wasapi_io_thread")); - audio_io_thread_->Start(); - if (!audio_io_thread_->HasBeenStarted()) { - DLOG(ERROR) << "Failed to start WASAPI IO thread."; - return; - } - - // Start input streaming data between the endpoint buffer and the audio - // engine. - HRESULT hr = audio_input_client_->Start(); - if (FAILED(hr)) { - StopAndJoinThread(hr); - return; - } - - // Ensure that the endpoint buffer is prepared with silence. - if (share_mode_ == AUDCLNT_SHAREMODE_SHARED) { - if (!CoreAudioUtil::FillRenderEndpointBufferWithSilence( - audio_output_client_, audio_render_client_)) { - DLOG(WARNING) << "Failed to prepare endpoint buffers with silence."; - return; - } - } - num_written_frames_ = endpoint_render_buffer_size_frames_; - - // Start output streaming data between the endpoint buffer and the audio - // engine. - hr = audio_output_client_->Start(); - if (FAILED(hr)) { - StopAndJoinThread(hr); - return; - } -} - -void WASAPIUnifiedStream::Stop() { - TRACE_EVENT0("audio", "WASAPIUnifiedStream::Stop"); - DVLOG(1) << "WASAPIUnifiedStream::Stop()"; - DCHECK_EQ(GetCurrentThreadId(), creating_thread_id_); - if (!audio_io_thread_) - return; - - // Stop input audio streaming. - HRESULT hr = audio_input_client_->Stop(); - if (FAILED(hr)) { - DLOG_IF(ERROR, hr != AUDCLNT_E_NOT_INITIALIZED) - << "Failed to stop input streaming: " << std::hex << hr; - } - - // Stop output audio streaming. - hr = audio_output_client_->Stop(); - if (FAILED(hr)) { - DLOG_IF(ERROR, hr != AUDCLNT_E_NOT_INITIALIZED) - << "Failed to stop output streaming: " << std::hex << hr; - } - - // Wait until the thread completes and perform cleanup. - SetEvent(stop_streaming_event_.Get()); - audio_io_thread_->Join(); - audio_io_thread_.reset(); - - // Ensure that we don't quit the main thread loop immediately next - // time Start() is called. - ResetEvent(stop_streaming_event_.Get()); - - // Clear source callback, it'll be set again on the next Start() call. - source_ = NULL; - - // Flush all pending data and reset the audio clock stream position to 0. - hr = audio_output_client_->Reset(); - if (FAILED(hr)) { - DLOG_IF(ERROR, hr != AUDCLNT_E_NOT_INITIALIZED) - << "Failed to reset output streaming: " << std::hex << hr; - } - - audio_input_client_->Reset(); - if (FAILED(hr)) { - DLOG_IF(ERROR, hr != AUDCLNT_E_NOT_INITIALIZED) - << "Failed to reset input streaming: " << std::hex << hr; - } - - // Extra safety check to ensure that the buffers are cleared. - // If the buffers are not cleared correctly, the next call to Start() - // would fail with AUDCLNT_E_BUFFER_ERROR at IAudioRenderClient::GetBuffer(). - // TODO(henrika): this check is is only needed for shared-mode streams. - UINT32 num_queued_frames = 0; - audio_output_client_->GetCurrentPadding(&num_queued_frames); - DCHECK_EQ(0u, num_queued_frames); -} - -void WASAPIUnifiedStream::Close() { - TRACE_EVENT0("audio", "WASAPIUnifiedStream::Close"); - DVLOG(1) << "WASAPIUnifiedStream::Close()"; - DCHECK_EQ(GetCurrentThreadId(), creating_thread_id_); - - // It is valid to call Close() before calling open or Start(). - // It is also valid to call Close() after Start() has been called. - Stop(); - - // Inform the audio manager that we have been closed. This will cause our - // destruction. - manager_->ReleaseOutputStream(this); -} - -void WASAPIUnifiedStream::SetVolume(double volume) { - DVLOG(1) << "SetVolume(volume=" << volume << ")"; - if (volume < 0 || volume > 1) - return; - volume_ = volume; -} - -void WASAPIUnifiedStream::GetVolume(double* volume) { - DVLOG(1) << "GetVolume()"; - *volume = static_cast<double>(volume_); -} - - -void WASAPIUnifiedStream::ProvideInput(int frame_delay, AudioBus* audio_bus) { - // TODO(henrika): utilize frame_delay? - // A non-zero framed delay means multiple callbacks were necessary to - // fulfill the requested number of frames. - if (frame_delay > 0) - DVLOG(3) << "frame_delay: " << frame_delay; - -#ifndef NDEBUG - resampler_margin_[num_elements_[RESAMPLER_MARGIN]] = - fifo_->frames() - audio_bus->frames(); - num_elements_[RESAMPLER_MARGIN]++; -#endif - - if (fifo_->frames() < audio_bus->frames()) { - DVLOG(ERROR) << "Not enough data in the FIFO (" - << fifo_->frames() << " < " << audio_bus->frames() << ")"; - audio_bus->Zero(); - return; - } - - fifo_->Consume(audio_bus, 0, audio_bus->frames()); -} - -void WASAPIUnifiedStream::SetIOFormats(const AudioParameters& input_params, - const AudioParameters& output_params) { - for (int n = 0; n < 2; ++n) { - const AudioParameters& params = (n == 0) ? input_params : output_params; - WAVEFORMATPCMEX* xformat = (n == 0) ? &input_format_ : &output_format_; - WAVEFORMATEX* format = &xformat->Format; - - // Begin with the WAVEFORMATEX structure that specifies the basic format. - format->wFormatTag = WAVE_FORMAT_EXTENSIBLE; - format->nChannels = params.channels(); - format->nSamplesPerSec = params.sample_rate(); - format->wBitsPerSample = params.bits_per_sample(); - format->nBlockAlign = (format->wBitsPerSample / 8) * format->nChannels; - format->nAvgBytesPerSec = format->nSamplesPerSec * format->nBlockAlign; - format->cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); - - // Add the parts which are unique to WAVE_FORMAT_EXTENSIBLE. - // Note that we always open up using the native channel layout. - (*xformat).Samples.wValidBitsPerSample = format->wBitsPerSample; - (*xformat).dwChannelMask = - CoreAudioUtil::GetChannelConfig( - std::string(), n == 0 ? eCapture : eRender); - (*xformat).SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - } - - input_buffer_size_frames_ = input_params.frames_per_buffer(); - output_buffer_size_frames_ = output_params.frames_per_buffer(); - VLOG(1) << "#audio frames per input buffer : " << input_buffer_size_frames_; - VLOG(1) << "#audio frames per output buffer: " << output_buffer_size_frames_; - -#ifndef NDEBUG - input_params_[0] = input_format_.Format.nSamplesPerSec; - input_params_[1] = input_buffer_size_frames_; - output_params_[0] = output_format_.Format.nSamplesPerSec; - output_params_[1] = output_buffer_size_frames_; -#endif -} - -void WASAPIUnifiedStream::DoVarispeedInitialization( - const AudioParameters& input_params, const AudioParameters& output_params) { - DVLOG(1) << "WASAPIUnifiedStream::DoVarispeedInitialization()"; - - // A FIFO is required in this mode for input to output buffering. - // Note that it will add some latency. - fifo_.reset(new AudioFifo(input_params.channels(), kFifoSize)); - VLOG(1) << "Using FIFO of size " << fifo_->max_frames() - << " (#channels=" << input_params.channels() << ")"; - - // Create the multi channel resampler using the initial sample rate ratio. - // We will call MultiChannelResampler::SetRatio() during runtime to - // allow arbitrary combinations of input and output devices running off - // different clocks and using different drivers, with potentially - // differing sample-rates. Note that the requested block size is given by - // the native input buffer size |input_buffer_size_frames_|. - io_sample_rate_ratio_ = input_params.sample_rate() / - static_cast<double>(output_params.sample_rate()); - DVLOG(2) << "io_sample_rate_ratio: " << io_sample_rate_ratio_; - resampler_.reset(new MultiChannelResampler( - input_params.channels(), io_sample_rate_ratio_, input_buffer_size_frames_, - base::Bind(&WASAPIUnifiedStream::ProvideInput, base::Unretained(this)))); - VLOG(1) << "Resampling from " << input_params.sample_rate() << " to " - << output_params.sample_rate(); - - // The optimal number of frames we'd like to keep in the FIFO at all times. - // The actual size will vary but the goal is to ensure that the average size - // is given by this value. - target_fifo_frames_ = kTargetFifoSafetyFactor * input_buffer_size_frames_; - VLOG(1) << "Target FIFO size: " << target_fifo_frames_; - - // Create the event which the audio engine will signal each time it - // wants an audio buffer to render. - render_event_.Set(CreateEvent(NULL, FALSE, FALSE, NULL)); - - // Allocate memory for temporary audio bus used to store resampled input - // audio. - resampled_bus_ = AudioBus::Create( - input_params.channels(), output_buffer_size_frames_); - - // Buffer initial silence corresponding to target I/O buffering. - ResetVarispeed(); -} - -void WASAPIUnifiedStream::ResetVarispeed() { - DCHECK(VarispeedMode()); - - // Buffer initial silence corresponding to target I/O buffering. - fifo_->Clear(); - scoped_ptr<AudioBus> silence = - AudioBus::Create(input_format_.Format.nChannels, - target_fifo_frames_); - silence->Zero(); - fifo_->Push(silence.get()); - resampler_->Flush(); -} - -void WASAPIUnifiedStream::Run() { - ScopedCOMInitializer com_init(ScopedCOMInitializer::kMTA); - - // Increase the thread priority. - audio_io_thread_->SetThreadPriority(base::kThreadPriority_RealtimeAudio); - - // Enable MMCSS to ensure that this thread receives prioritized access to - // CPU resources. - // TODO(henrika): investigate if it is possible to include these additional - // settings in SetThreadPriority() as well. - DWORD task_index = 0; - HANDLE mm_task = avrt::AvSetMmThreadCharacteristics(L"Pro Audio", - &task_index); - bool mmcss_is_ok = - (mm_task && avrt::AvSetMmThreadPriority(mm_task, AVRT_PRIORITY_CRITICAL)); - if (!mmcss_is_ok) { - // Failed to enable MMCSS on this thread. It is not fatal but can lead - // to reduced QoS at high load. - DWORD err = GetLastError(); - LOG(WARNING) << "Failed to enable MMCSS (error code=" << err << ")."; - } - - // The IAudioClock interface enables us to monitor a stream's data - // rate and the current position in the stream. Allocate it before we - // start spinning. - ScopedComPtr<IAudioClock> audio_output_clock; - HRESULT hr = audio_output_client_->GetService( - __uuidof(IAudioClock), audio_output_clock.ReceiveVoid()); - LOG_IF(WARNING, FAILED(hr)) << "Failed to create IAudioClock: " - << std::hex << hr; - - bool streaming = true; - bool error = false; - - HANDLE wait_array[3]; - size_t num_handles = 0; - wait_array[num_handles++] = stop_streaming_event_; - wait_array[num_handles++] = capture_event_; - if (render_event_) { - // One extra event handle is needed in varispeed mode. - wait_array[num_handles++] = render_event_; - } - - // Keep streaming audio until stop event is signaled. - // Capture events are always used but render events are only active in - // varispeed mode. - while (streaming && !error) { - // Wait for a close-down event, or a new capture event. - DWORD wait_result = WaitForMultipleObjects(num_handles, - wait_array, - FALSE, - INFINITE); - switch (wait_result) { - case WAIT_OBJECT_0 + 0: - // |stop_streaming_event_| has been set. - streaming = false; - break; - case WAIT_OBJECT_0 + 1: - // |capture_event_| has been set - if (VarispeedMode()) { - ProcessInputAudio(); - } else { - ProcessInputAudio(); - ProcessOutputAudio(audio_output_clock); - } - break; - case WAIT_OBJECT_0 + 2: - DCHECK(VarispeedMode()); - // |render_event_| has been set - ProcessOutputAudio(audio_output_clock); - break; - default: - error = true; - break; - } - } - - if (streaming && error) { - // Stop audio streaming since something has gone wrong in our main thread - // loop. Note that, we are still in a "started" state, hence a Stop() call - // is required to join the thread properly. - audio_input_client_->Stop(); - audio_output_client_->Stop(); - PLOG(ERROR) << "WASAPI streaming failed."; - } - - // Disable MMCSS. - if (mm_task && !avrt::AvRevertMmThreadCharacteristics(mm_task)) { - PLOG(WARNING) << "Failed to disable MMCSS"; - } -} - -void WASAPIUnifiedStream::ProcessInputAudio() { - TRACE_EVENT0("audio", "WASAPIUnifiedStream::ProcessInputAudio"); - - BYTE* data_ptr = NULL; - UINT32 num_captured_frames = 0; - DWORD flags = 0; - UINT64 device_position = 0; - UINT64 capture_time_stamp = 0; - - const int bytes_per_sample = input_format_.Format.wBitsPerSample >> 3; - - base::TimeTicks now_tick = base::TimeTicks::HighResNow(); - -#ifndef NDEBUG - if (VarispeedMode()) { - input_time_stamps_[num_elements_[INPUT_TIME_STAMP]] = - now_tick.ToInternalValue(); - num_elements_[INPUT_TIME_STAMP]++; - } -#endif - - // Retrieve the amount of data in the capture endpoint buffer. - // |endpoint_capture_time_stamp| is the value of the performance - // counter at the time that the audio endpoint device recorded - // the device position of the first audio frame in the data packet. - HRESULT hr = audio_capture_client_->GetBuffer(&data_ptr, - &num_captured_frames, - &flags, - &device_position, - &capture_time_stamp); - if (FAILED(hr)) { - DLOG(ERROR) << "Failed to get data from the capture buffer"; - return; - } - - if (hr == AUDCLNT_S_BUFFER_EMPTY) { - // The return coded is a success code but a new packet is *not* available - // and none of the output parameters in the GetBuffer() call contains valid - // values. Best we can do is to deliver silence and avoid setting - // |input_callback_received_| since this only seems to happen for the - // initial event(s) on some devices. - input_bus_->Zero(); - } else { - // Valid data has been recorded and it is now OK to set the flag which - // informs the render side that capturing has started. - input_callback_received_ = true; - } - - if (num_captured_frames != 0) { - if (flags & AUDCLNT_BUFFERFLAGS_SILENT) { - // Clear out the capture buffer since silence is reported. - input_bus_->Zero(); - } else { - // Store captured data in an audio bus after de-interleaving - // the data to match the audio bus structure. - input_bus_->FromInterleaved( - data_ptr, num_captured_frames, bytes_per_sample); - } - } - - hr = audio_capture_client_->ReleaseBuffer(num_captured_frames); - DLOG_IF(ERROR, FAILED(hr)) << "Failed to release capture buffer"; - - // Buffer input into FIFO if varispeed mode is used. The render event - // will drive resampling of this data to match the output side. - if (VarispeedMode()) { - int available_frames = fifo_->max_frames() - fifo_->frames(); - if (input_bus_->frames() <= available_frames) { - fifo_->Push(input_bus_.get()); - } -#ifndef NDEBUG - num_frames_in_fifo_[num_elements_[NUM_FRAMES_IN_FIFO]] = - fifo_->frames(); - num_elements_[NUM_FRAMES_IN_FIFO]++; -#endif - } - - // Save resource by not asking for new delay estimates each time. - // These estimates are fairly stable and it is perfectly safe to only - // sample at a rate of ~1Hz. - // TODO(henrika): we might have to increase the update rate in varispeed - // mode since the delay variations are higher in this mode. - if ((now_tick - last_delay_sample_time_).InMilliseconds() > - kTimeDiffInMillisecondsBetweenDelayMeasurements && - input_callback_received_) { - // Calculate the estimated capture delay, i.e., the latency between - // the recording time and the time we when we are notified about - // the recorded data. Note that the capture time stamp is given in - // 100-nanosecond (0.1 microseconds) units. - base::TimeDelta diff = - now_tick - base::TimeTicks::FromInternalValue(0.1 * capture_time_stamp); - capture_delay_ms_ = diff.InMillisecondsF(); - - last_delay_sample_time_ = now_tick; - update_output_delay_ = true; - } -} - -void WASAPIUnifiedStream::ProcessOutputAudio(IAudioClock* audio_output_clock) { - TRACE_EVENT0("audio", "WASAPIUnifiedStream::ProcessOutputAudio"); - - if (!input_callback_received_) { - if (share_mode_ == AUDCLNT_SHAREMODE_SHARED) { - if (!CoreAudioUtil::FillRenderEndpointBufferWithSilence( - audio_output_client_, audio_render_client_)) - DLOG(WARNING) << "Failed to prepare endpoint buffers with silence."; - } - return; - } - - // Rate adjusted resampling is required in varispeed mode. It means that - // recorded audio samples will be read from the FIFO, resampled to match the - // output sample-rate and then stored in |resampled_bus_|. - if (VarispeedMode()) { - // Calculate a varispeed rate scalar factor to compensate for drift between - // input and output. We use the actual number of frames still in the FIFO - // compared with the ideal value of |target_fifo_frames_|. - int delta = fifo_->frames() - target_fifo_frames_; - - // Average |delta| because it can jitter back/forth quite frequently - // by +/- the hardware buffer-size *if* the input and output callbacks are - // happening at almost exactly the same time. Also, if the input and output - // sample-rates are different then |delta| will jitter quite a bit due to - // the rate conversion happening in the varispeed, plus the jittering of - // the callbacks. The average value is what's important here. - // We use an exponential smoothing filter to reduce the variations. - average_delta_ += kAlpha * (delta - average_delta_); - - // Compute a rate compensation which always attracts us back to the - // |target_fifo_frames_| over a period of kCorrectionTimeSeconds. - double correction_time_frames = - kCorrectionTimeSeconds * output_format_.Format.nSamplesPerSec; - fifo_rate_compensation_ = - (correction_time_frames + average_delta_) / correction_time_frames; - -#ifndef NDEBUG - fifo_rate_comps_[num_elements_[RATE_COMPENSATION]] = - fifo_rate_compensation_; - num_elements_[RATE_COMPENSATION]++; -#endif - - // Adjust for FIFO drift. - const double new_ratio = io_sample_rate_ratio_ * fifo_rate_compensation_; - resampler_->SetRatio(new_ratio); - // Get resampled input audio from FIFO where the size is given by the - // output side. - resampler_->Resample(resampled_bus_->frames(), resampled_bus_.get()); - } - - // Derive a new total delay estimate if the capture side has set the - // |update_output_delay_| flag. - if (update_output_delay_) { - // Calculate the estimated render delay, i.e., the time difference - // between the time when data is added to the endpoint buffer and - // when the data is played out on the actual speaker. - const double stream_pos = CurrentStreamPosInMilliseconds( - num_written_frames_ + output_buffer_size_frames_, - output_format_.Format.nSamplesPerSec); - const double speaker_pos = - SpeakerStreamPosInMilliseconds(audio_output_clock); - const double render_delay_ms = stream_pos - speaker_pos; - const double fifo_delay_ms = VarispeedMode() ? - FrameCountToMilliseconds(target_fifo_frames_, input_format_) : 0; - - // Derive the total delay, i.e., the sum of the input and output - // delays. Also convert the value into byte units. An extra FIFO delay - // is added for varispeed usage cases. - total_delay_ms_ = VarispeedMode() ? - capture_delay_ms_ + render_delay_ms + fifo_delay_ms : - capture_delay_ms_ + render_delay_ms; - DVLOG(2) << "total_delay_ms : " << total_delay_ms_; - DVLOG(3) << " capture_delay_ms: " << capture_delay_ms_; - DVLOG(3) << " render_delay_ms : " << render_delay_ms; - DVLOG(3) << " fifo_delay_ms : " << fifo_delay_ms; - total_delay_bytes_ = MillisecondsToBytes(total_delay_ms_, output_format_); - - // Wait for new signal from the capture side. - update_output_delay_ = false; - } - - // Select source depending on if varispeed is utilized or not. - // Also, the source might be the output of a channel mixer if channel mixing - // is required to match the native input channels to the number of input - // channels used by the client (given by |input_channels_| in this case). - AudioBus* input_bus = VarispeedMode() ? - resampled_bus_.get() : input_bus_.get(); - if (channel_mixer_) { - DCHECK_EQ(input_bus->frames(), channel_bus_->frames()); - // Most common case is 1->2 channel upmixing. - channel_mixer_->Transform(input_bus, channel_bus_.get()); - // Use the output from the channel mixer as new input bus. - input_bus = channel_bus_.get(); - } - - // Prepare for rendering by calling OnMoreIOData(). - int frames_filled = source_->OnMoreIOData( - input_bus, - output_bus_.get(), - AudioBuffersState(0, total_delay_bytes_)); - DCHECK_EQ(frames_filled, output_bus_->frames()); - - // Keep track of number of rendered frames since we need it for - // our delay calculations. - num_written_frames_ += frames_filled; - - // Derive the the amount of available space in the endpoint buffer. - // Avoid render attempt if there is no room for a captured packet. - UINT32 num_queued_frames = 0; - audio_output_client_->GetCurrentPadding(&num_queued_frames); - if (endpoint_render_buffer_size_frames_ - num_queued_frames < - output_buffer_size_frames_) - return; - - // Grab all available space in the rendering endpoint buffer - // into which the client can write a data packet. - uint8* audio_data = NULL; - HRESULT hr = audio_render_client_->GetBuffer(output_buffer_size_frames_, - &audio_data); - if (FAILED(hr)) { - DLOG(ERROR) << "Failed to access render buffer"; - return; - } - - const int bytes_per_sample = output_format_.Format.wBitsPerSample >> 3; - - // Convert the audio bus content to interleaved integer data using - // |audio_data| as destination. - output_bus_->Scale(volume_); - output_bus_->ToInterleaved( - output_buffer_size_frames_, bytes_per_sample, audio_data); - - // Release the buffer space acquired in the GetBuffer() call. - audio_render_client_->ReleaseBuffer(output_buffer_size_frames_, 0); - DLOG_IF(ERROR, FAILED(hr)) << "Failed to release render buffer"; - - return; -} - -void WASAPIUnifiedStream::HandleError(HRESULT err) { - CHECK((started() && GetCurrentThreadId() == audio_io_thread_->tid()) || - (!started() && GetCurrentThreadId() == creating_thread_id_)); - NOTREACHED() << "Error code: " << std::hex << err; - if (source_) - source_->OnError(this); -} - -void WASAPIUnifiedStream::StopAndJoinThread(HRESULT err) { - CHECK(GetCurrentThreadId() == creating_thread_id_); - DCHECK(audio_io_thread_.get()); - SetEvent(stop_streaming_event_.Get()); - audio_io_thread_->Join(); - audio_io_thread_.reset(); - HandleError(err); -} - -} // namespace media diff --git a/media/audio/win/audio_unified_win.h b/media/audio/win/audio_unified_win.h deleted file mode 100644 index 76c5329..0000000 --- a/media/audio/win/audio_unified_win.h +++ /dev/null @@ -1,352 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef MEDIA_AUDIO_WIN_AUDIO_UNIFIED_WIN_H_ -#define MEDIA_AUDIO_WIN_AUDIO_UNIFIED_WIN_H_ - -#include <Audioclient.h> -#include <MMDeviceAPI.h> - -#include <string> - -#include "base/compiler_specific.h" -#include "base/gtest_prod_util.h" -#include "base/threading/platform_thread.h" -#include "base/threading/simple_thread.h" -#include "base/win/scoped_co_mem.h" -#include "base/win/scoped_comptr.h" -#include "base/win/scoped_handle.h" -#include "media/audio/audio_io.h" -#include "media/audio/audio_parameters.h" -#include "media/base/audio_fifo.h" -#include "media/base/channel_mixer.h" -#include "media/base/media_export.h" -#include "media/base/multi_channel_resampler.h" - -namespace media { - -class AudioManagerWin; - -// Implementation of AudioOutputStream for Windows using the Core Audio API -// where both capturing and rendering takes place on the same thread to enable -// audio I/O. This class allows arbitrary combinations of input and output -// devices running off different clocks and using different drivers, with -// potentially differing sample-rates. -// -// It is required to first acquire the native sample rate of the selected -// output device and then use the same rate when creating this object. -// The inner operation depends on the input sample rate which is determined -// during construction. Three different main modes are supported: -// -// 1) input rate == output rate => input side drives output side directly. -// 2) input rate != output rate => both sides are driven independently by -// events and a FIFO plus a resampling unit is used to compensate for -// differences in sample rates between the two sides. -// 3) input rate == output rate but native buffer sizes are not identical => -// same inner functionality as in (2) to compensate for the differences -// in buffer sizes and also compensate for any potential clock drift -// between the two devices. -// -// Mode detection is is done at construction and using mode (1) will lead to -// best performance (lower delay and no "varispeed distortion"), i.e., it is -// recommended to use same sample rates for input and output. Mode (2) uses a -// resampler which supports rate adjustments to fine tune for things like -// clock drift and differences in sample rates between different devices. -// Mode (2) - which uses a FIFO and a adjustable multi-channel resampler - -// is also called the varispeed mode and it is used for case (3) as well to -// compensate for the difference in buffer sizes mainly. -// Mode (3) can happen if two different audio devices are used. -// As an example: some devices needs a buffer size of 441 @ 44.1kHz and others -// 448 @ 44.1kHz. This is a rare case and will only happen for sample rates -// which are even multiples of 11025 Hz (11025, 22050, 44100, 88200 etc.). -// -// Implementation notes: -// -// - Open() can fail if the input and output parameters do not fulfill -// certain conditions. See source for Open() for more details. -// - Channel mixing will be performed if the clients asks for a larger -// number of channels than the native audio layer provides. -// Example: client wants stereo but audio layer provides mono. In this case -// upmixing from mono to stereo (1->2) will be done. -// -// TODO(henrika): -// -// - Add support for exclusive mode. -// - Add support for KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, i.e., 32-bit float -// as internal sample-value representation. -// - Perform fine-tuning for non-matching sample rates to reduce latency. -// -class MEDIA_EXPORT WASAPIUnifiedStream - : public AudioOutputStream, - public base::DelegateSimpleThread::Delegate { - public: - // 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 std::string& input_device_id); - - // The dtor is typically called by the AudioManager only and it is usually - // triggered by calling AudioOutputStream::Close(). - virtual ~WASAPIUnifiedStream(); - - // Implementation of AudioOutputStream. - virtual bool Open() OVERRIDE; - virtual void Start(AudioSourceCallback* callback) OVERRIDE; - virtual void Stop() OVERRIDE; - virtual void Close() OVERRIDE; - virtual void SetVolume(double volume) OVERRIDE; - virtual void GetVolume(double* volume) OVERRIDE; - - bool started() const { - return audio_io_thread_.get() != NULL; - } - - // Returns true if input sample rate differs from the output sample rate. - // A FIFO and a adjustable multi-channel resampler are utilized in this mode. - bool VarispeedMode() const { return (fifo_ && resampler_); } - - private: - enum { - // Time in milliseconds between two successive delay measurements. - // We save resources by not updating the delay estimates for each capture - // event (typically 100Hz rate). - kTimeDiffInMillisecondsBetweenDelayMeasurements = 1000, - - // Max possible FIFO size. - kFifoSize = 16384, - - // This value was determined empirically for minimum latency while still - // guarding against FIFO under-runs. The actual target size will be equal - // to kTargetFifoSafetyFactor * (native input buffer size). - // TODO(henrika): tune this value for lowest possible latency for all - // possible sample rate combinations. - kTargetFifoSafetyFactor = 2 - }; - - // Additional initialization required when input and output sample rate - // differs. Allocates resources for |fifo_|, |resampler_|, |render_event_|, - // and the |capture_bus_| and configures the |input_format_| structure - // given the provided input and output audio parameters. - void DoVarispeedInitialization(const AudioParameters& input_params, - const AudioParameters& output_params); - - // Clears varispeed related components such as the FIFO and the resampler. - void ResetVarispeed(); - - // Builds WAVEFORMATEX structures for input and output based on input and - // output audio parameters. - void SetIOFormats(const AudioParameters& input_params, - const AudioParameters& output_params); - - // DelegateSimpleThread::Delegate implementation. - virtual void Run() OVERRIDE; - - // MultiChannelResampler::MultiChannelAudioSourceProvider implementation. - // Callback for providing more data into the resampler. - // Only used in varispeed mode, i.e., when input rate != output rate. - virtual void ProvideInput(int frame_delay, AudioBus* audio_bus); - - // Issues the OnError() callback to the |source_|. - void HandleError(HRESULT err); - - // Stops and joins the audio thread in case of an error. - void StopAndJoinThread(HRESULT err); - - // Converts unique endpoint ID to user-friendly device name. - std::string GetDeviceName(LPCWSTR device_id) const; - - // Called on the audio IO thread for each capture event. - // Buffers captured audio into a FIFO if varispeed is used or into an audio - // bus if input and output sample rates are identical. - void ProcessInputAudio(); - - // Called on the audio IO thread for each render event when varispeed is - // active or for each capture event when varispeed is not used. - // In varispeed mode, it triggers a resampling callback, which reads from the - // FIFO, and calls AudioSourceCallback::OnMoreIOData using the resampled - // input signal and at the same time asks for data to play out. - // If input and output rates are the same - instead of reading from the FIFO - // and do resampling - we read directly from the audio bus used to store - // captured data in ProcessInputAudio. - void ProcessOutputAudio(IAudioClock* audio_output_clock); - - // Contains the thread ID of the creating thread. - base::PlatformThreadId creating_thread_id_; - - // Our creator, the audio manager needs to be notified when we close. - AudioManagerWin* manager_; - - // Contains the audio parameter structure provided at construction. - AudioParameters params_; - // For convenience, same as in params_. - 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. - AUDCLNT_SHAREMODE share_mode_; - - // Rendering and capturing is driven by this thread (no message loop). - // All OnMoreIOData() callbacks will be called from this thread. - scoped_ptr<base::DelegateSimpleThread> audio_io_thread_; - - // Contains the desired audio output format which is set up at construction. - // It is required to first acquire the native sample rate of the selected - // output device and then use the same rate when creating this object. - WAVEFORMATPCMEX output_format_; - - // Contains the native audio input format which is set up at construction - // if varispeed mode is utilized. - WAVEFORMATPCMEX input_format_; - - // True when successfully opened. - bool opened_; - - // Volume level from 0 to 1 used for output scaling. - double volume_; - - // Size in audio frames of each audio packet where an audio packet - // is defined as the block of data which the destination is expected to - // receive in each OnMoreIOData() callback. - size_t output_buffer_size_frames_; - - // Size in audio frames of each audio packet where an audio packet - // is defined as the block of data which the source is expected to - // deliver in each OnMoreIOData() callback. - size_t input_buffer_size_frames_; - - // Length of the audio endpoint buffer. - uint32 endpoint_render_buffer_size_frames_; - uint32 endpoint_capture_buffer_size_frames_; - - // Counts the number of audio frames written to the endpoint buffer. - uint64 num_written_frames_; - - // Time stamp for last delay measurement. - base::TimeTicks last_delay_sample_time_; - - // Contains the total (sum of render and capture) delay in milliseconds. - double total_delay_ms_; - - // Contains the total (sum of render and capture and possibly FIFO) delay - // in bytes. The update frequency is set by a constant called - // |kTimeDiffInMillisecondsBetweenDelayMeasurements|. - int total_delay_bytes_; - - // Pointer to the client that will deliver audio samples to be played out. - AudioSourceCallback* source_; - - // IMMDevice interfaces which represents audio endpoint devices. - base::win::ScopedComPtr<IMMDevice> endpoint_render_device_; - base::win::ScopedComPtr<IMMDevice> endpoint_capture_device_; - - // IAudioClient interfaces which enables a client to create and initialize - // an audio stream between an audio application and the audio engine. - base::win::ScopedComPtr<IAudioClient> audio_output_client_; - base::win::ScopedComPtr<IAudioClient> audio_input_client_; - - // IAudioRenderClient interfaces enables a client to write output - // data to a rendering endpoint buffer. - base::win::ScopedComPtr<IAudioRenderClient> audio_render_client_; - - // IAudioCaptureClient interfaces enables a client to read input - // data from a capturing endpoint buffer. - base::win::ScopedComPtr<IAudioCaptureClient> audio_capture_client_; - - // The audio engine will signal this event each time a buffer has been - // recorded. - base::win::ScopedHandle capture_event_; - - // The audio engine will signal this event each time it needs a new - // audio buffer to play out. - // Only utilized in varispeed mode. - base::win::ScopedHandle render_event_; - - // This event will be signaled when streaming shall stop. - base::win::ScopedHandle stop_streaming_event_; - - // Container for retrieving data from AudioSourceCallback::OnMoreIOData(). - scoped_ptr<AudioBus> output_bus_; - - // Container for sending data to AudioSourceCallback::OnMoreIOData(). - scoped_ptr<AudioBus> input_bus_; - - // Container for storing output from the channel mixer. - scoped_ptr<AudioBus> channel_bus_; - - // All members below are only allocated, or used, in varispeed mode: - - // Temporary storage of resampled input audio data. - scoped_ptr<AudioBus> resampled_bus_; - - // Set to true first time a capture event has been received in varispeed - // mode. - bool input_callback_received_; - - // MultiChannelResampler is a multi channel wrapper for SincResampler; - // allowing high quality sample rate conversion of multiple channels at once. - scoped_ptr<MultiChannelResampler> resampler_; - - // Resampler I/O ratio. - double io_sample_rate_ratio_; - - // Used for input to output buffering. - scoped_ptr<AudioFifo> fifo_; - - // The channel mixer is only created and utilized if number of input channels - // is larger than the native number of input channels (e.g client wants - // stereo but the audio device only supports mono). - scoped_ptr<ChannelMixer> channel_mixer_; - - // The optimal number of frames we'd like to keep in the FIFO at all times. - int target_fifo_frames_; - - // A running average of the measured delta between actual number of frames - // in the FIFO versus |target_fifo_frames_|. - double average_delta_; - - // A varispeed rate scalar which is calculated based on FIFO drift. - double fifo_rate_compensation_; - - // Set to true when input side signals output side that a new delay - // estimate is needed. - bool update_output_delay_; - - // Capture side stores its delay estimate so the sum can be derived in - // the render side. - double capture_delay_ms_; - - // TODO(henrika): possibly remove these members once the performance is - // properly tuned. Only used for off-line debugging. -#ifndef NDEBUG - enum LogElementNames { - INPUT_TIME_STAMP, - NUM_FRAMES_IN_FIFO, - RESAMPLER_MARGIN, - RATE_COMPENSATION - }; - - scoped_ptr<int64[]> input_time_stamps_; - scoped_ptr<int[]> num_frames_in_fifo_; - scoped_ptr<int[]> resampler_margin_; - scoped_ptr<double[]> fifo_rate_comps_; - scoped_ptr<int[]> num_elements_; - scoped_ptr<int[]> input_params_; - scoped_ptr<int[]> output_params_; - - FILE* data_file_; - FILE* param_file_; -#endif - - DISALLOW_COPY_AND_ASSIGN(WASAPIUnifiedStream); -}; - -} // namespace media - -#endif // MEDIA_AUDIO_WIN_AUDIO_UNIFIED_WIN_H_ diff --git a/media/audio/win/audio_unified_win_unittest.cc b/media/audio/win/audio_unified_win_unittest.cc deleted file mode 100644 index fadec61..0000000 --- a/media/audio/win/audio_unified_win_unittest.cc +++ /dev/null @@ -1,356 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/basictypes.h" -#include "base/command_line.h" -#include "base/file_util.h" -#include "base/message_loop/message_loop.h" -#include "base/path_service.h" -#include "base/test/test_timeouts.h" -#include "base/time/time.h" -#include "base/win/scoped_com_initializer.h" -#include "media/audio/audio_io.h" -#include "media/audio/audio_manager.h" -#include "media/audio/mock_audio_source_callback.h" -#include "media/audio/win/audio_unified_win.h" -#include "media/audio/win/core_audio_util_win.h" -#include "media/base/channel_mixer.h" -#include "media/base/media_switches.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using ::testing::_; -using ::testing::AtLeast; -using ::testing::Between; -using ::testing::DoAll; -using ::testing::NotNull; -using ::testing::Return; -using base::win::ScopedCOMInitializer; - -namespace media { - -static const size_t kMaxDeltaSamples = 1000; -static const char kDeltaTimeMsFileName[] = "unified_delta_times_ms.txt"; - -// Verify that the delay estimate in the OnMoreIOData() callback is larger -// than an expected minumum value. -MATCHER_P(DelayGreaterThan, value, "") { - return (arg.hardware_delay_bytes > value.hardware_delay_bytes); -} - -// Used to terminate a loop from a different thread than the loop belongs to. -// |loop| should be a MessageLoopProxy. -ACTION_P(QuitLoop, loop) { - loop->PostTask(FROM_HERE, base::MessageLoop::QuitClosure()); -} - -// AudioOutputStream::AudioSourceCallback implementation which enables audio -// play-through. It also creates a text file that contains times between two -// successive callbacks. Units are in milliseconds. This file can be used for -// off-line analysis of the callback sequence. -class UnifiedSourceCallback : public AudioOutputStream::AudioSourceCallback { - public: - explicit UnifiedSourceCallback() - : previous_call_time_(base::TimeTicks::Now()), - text_file_(NULL), - elements_to_write_(0) { - delta_times_.reset(new int[kMaxDeltaSamples]); - } - - virtual ~UnifiedSourceCallback() { - base::FilePath file_name; - EXPECT_TRUE(PathService::Get(base::DIR_EXE, &file_name)); - file_name = file_name.AppendASCII(kDeltaTimeMsFileName); - - EXPECT_TRUE(!text_file_); - text_file_ = base::OpenFile(file_name, "wt"); - DLOG_IF(ERROR, !text_file_) << "Failed to open log file."; - VLOG(0) << ">> Output file " << file_name.value() << " has been created."; - - // Write the array which contains delta times to a text file. - size_t elements_written = 0; - while (elements_written < elements_to_write_) { - fprintf(text_file_, "%d\n", delta_times_[elements_written]); - ++elements_written; - } - base::CloseFile(text_file_); - } - - virtual int OnMoreData(AudioBus* dest, - AudioBuffersState buffers_state) { - NOTREACHED(); - return 0; - }; - - virtual int OnMoreIOData(AudioBus* source, - AudioBus* dest, - AudioBuffersState buffers_state) { - // Store time between this callback and the previous callback. - const base::TimeTicks now_time = base::TimeTicks::Now(); - const int diff = (now_time - previous_call_time_).InMilliseconds(); - previous_call_time_ = now_time; - if (elements_to_write_ < kMaxDeltaSamples) { - delta_times_[elements_to_write_] = diff; - ++elements_to_write_; - } - - // Play out the recorded audio samples in loop back. Perform channel mixing - // if required using a channel mixer which is created only if needed. - if (source->channels() == dest->channels()) { - source->CopyTo(dest); - } else { - // A channel mixer is required for converting audio between two different - // channel layouts. - if (!channel_mixer_) { - // Guessing the channel layout will work OK for this unit test. - // Main thing is that the number of channels is correct. - ChannelLayout input_layout = GuessChannelLayout(source->channels()); - ChannelLayout output_layout = GuessChannelLayout(dest->channels()); - channel_mixer_.reset(new ChannelMixer(input_layout, output_layout)); - DVLOG(1) << "Remixing channel layout from " << input_layout - << " to " << output_layout << "; from " - << source->channels() << " channels to " - << dest->channels() << " channels."; - } - if (channel_mixer_) - channel_mixer_->Transform(source, dest); - } - return source->frames(); - }; - - virtual void OnError(AudioOutputStream* stream) { - NOTREACHED(); - } - - private: - base::TimeTicks previous_call_time_; - scoped_ptr<int[]> delta_times_; - FILE* text_file_; - size_t elements_to_write_; - scoped_ptr<ChannelMixer> channel_mixer_; -}; - -// Convenience method which ensures that we fulfill all required conditions -// to run unified audio tests on Windows. -static bool CanRunUnifiedAudioTests(AudioManager* audio_man) { - if (!CoreAudioUtil::IsSupported()) { - LOG(WARNING) << "This tests requires Windows Vista or higher."; - return false; - } - - if (!audio_man->HasAudioOutputDevices()) { - LOG(WARNING) << "No output devices detected."; - return false; - } - - if (!audio_man->HasAudioInputDevices()) { - LOG(WARNING) << "No input devices detected."; - return false; - } - - return true; -} - -// Convenience class which simplifies creation of a unified AudioOutputStream -// object. -class AudioUnifiedStreamWrapper { - public: - explicit AudioUnifiedStreamWrapper(AudioManager* audio_manager) - : com_init_(ScopedCOMInitializer::kMTA), - audio_man_(audio_manager) { - // We open up both both sides (input and output) using the preferred - // set of audio parameters. These parameters corresponds to the mix format - // that the audio engine uses internally for processing of shared-mode - // output streams. - AudioParameters out_params; - EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetPreferredAudioParameters( - eRender, eConsole, &out_params))); - - // WebAudio is the only real user of unified audio and it always asks - // for stereo. - // TODO(henrika): extend support to other input channel layouts as well. - const int kInputChannels = 2; - - params_.Reset(out_params.format(), - out_params.channel_layout(), - out_params.channels(), - kInputChannels, - out_params.sample_rate(), - out_params.bits_per_sample(), - out_params.frames_per_buffer()); - } - - ~AudioUnifiedStreamWrapper() {} - - // Creates an AudioOutputStream object using default parameters. - WASAPIUnifiedStream* Create() { - return static_cast<WASAPIUnifiedStream*>(CreateOutputStream()); - } - - // Creates an AudioOutputStream object using default parameters but a - // specified input device. - WASAPIUnifiedStream* Create(const std::string device_id) { - return static_cast<WASAPIUnifiedStream*>(CreateOutputStream(device_id)); - } - - AudioParameters::Format format() const { return params_.format(); } - int channels() const { return params_.channels(); } - int bits_per_sample() const { return params_.bits_per_sample(); } - int sample_rate() const { return params_.sample_rate(); } - int frames_per_buffer() const { return params_.frames_per_buffer(); } - int bytes_per_buffer() const { return params_.GetBytesPerBuffer(); } - int input_channels() const { return params_.input_channels(); } - - private: - AudioOutputStream* CreateOutputStream() { - // Get the unique device ID of the default capture device instead of using - // AudioManagerBase::kDefaultDeviceId since it provides slightly better - // test coverage and will utilize the same code path as if a non default - // input device was used. - ScopedComPtr<IMMDevice> audio_device = - CoreAudioUtil::CreateDefaultDevice(eCapture, eConsole); - AudioDeviceName name; - EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetDeviceName(audio_device, &name))); - const std::string& input_device_id = name.unique_id; - EXPECT_TRUE(CoreAudioUtil::DeviceIsDefault(eCapture, eConsole, - input_device_id)); - - // Create the unified audio I/O stream using the default input device. - AudioOutputStream* aos = audio_man_->MakeAudioOutputStream(params_, - "", input_device_id); - EXPECT_TRUE(aos); - return aos; - } - - AudioOutputStream* CreateOutputStream(const std::string& input_device_id) { - // Create the unified audio I/O stream using the specified input device. - AudioOutputStream* aos = audio_man_->MakeAudioOutputStream(params_, - "", input_device_id); - EXPECT_TRUE(aos); - return aos; - } - - ScopedCOMInitializer com_init_; - AudioManager* audio_man_; - AudioParameters params_; -}; - -// Convenience method which creates a default WASAPIUnifiedStream object. -static WASAPIUnifiedStream* CreateDefaultUnifiedStream( - AudioManager* audio_manager) { - AudioUnifiedStreamWrapper aosw(audio_manager); - return aosw.Create(); -} - -// Convenience method which creates a default WASAPIUnifiedStream object but -// with a specified audio input device. -static WASAPIUnifiedStream* CreateDefaultUnifiedStream( - AudioManager* audio_manager, const std::string& device_id) { - AudioUnifiedStreamWrapper aosw(audio_manager); - return aosw.Create(device_id); -} - -// Test Open(), Close() calling sequence. -TEST(WASAPIUnifiedStreamTest, OpenAndClose) { - scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); - if (!CanRunUnifiedAudioTests(audio_manager.get())) - return; - - WASAPIUnifiedStream* wus = CreateDefaultUnifiedStream(audio_manager.get()); - EXPECT_TRUE(wus->Open()); - wus->Close(); -} - -// Test Open(), Close() calling sequence for all available capture devices. -TEST(WASAPIUnifiedStreamTest, OpenAndCloseForAllInputDevices) { - scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); - if (!CanRunUnifiedAudioTests(audio_manager.get())) - return; - - AudioDeviceNames device_names; - audio_manager->GetAudioInputDeviceNames(&device_names); - for (AudioDeviceNames::iterator i = device_names.begin(); - i != device_names.end(); ++i) { - WASAPIUnifiedStream* wus = CreateDefaultUnifiedStream( - audio_manager.get(), i->unique_id); - EXPECT_TRUE(wus->Open()); - wus->Close(); - } -} - -// Test Open(), Start(), Close() calling sequence. -TEST(WASAPIUnifiedStreamTest, OpenStartAndClose) { - scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); - if (!CanRunUnifiedAudioTests(audio_manager.get())) - return; - - MockAudioSourceCallback source; - AudioUnifiedStreamWrapper ausw(audio_manager.get()); - WASAPIUnifiedStream* wus = ausw.Create(); - - EXPECT_TRUE(wus->Open()); - EXPECT_CALL(source, OnError(wus)) - .Times(0); - EXPECT_CALL(source, OnMoreIOData(NotNull(), NotNull(), _)) - .Times(Between(0, 1)) - .WillOnce(Return(ausw.frames_per_buffer())); - wus->Start(&source); - wus->Close(); -} - -// Verify that IO callbacks starts as they should. -TEST(WASAPIUnifiedStreamTest, StartLoopbackAudio) { - scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); - if (!CanRunUnifiedAudioTests(audio_manager.get())) - return; - - base::MessageLoopForUI loop; - MockAudioSourceCallback source; - AudioUnifiedStreamWrapper ausw(audio_manager.get()); - WASAPIUnifiedStream* wus = ausw.Create(); - - // Set up expected minimum delay estimation where we use a minium delay - // which is equal to the sum of render and capture sizes. We can never - // reach a delay lower than this value. - AudioBuffersState min_total_audio_delay(0, 2 * ausw.bytes_per_buffer()); - - EXPECT_TRUE(wus->Open()); - EXPECT_CALL(source, OnError(wus)) - .Times(0); - EXPECT_CALL(source, OnMoreIOData( - NotNull(), NotNull(), DelayGreaterThan(min_total_audio_delay))) - .Times(AtLeast(2)) - .WillOnce(Return(ausw.frames_per_buffer())) - .WillOnce(DoAll( - QuitLoop(loop.message_loop_proxy()), - Return(ausw.frames_per_buffer()))); - wus->Start(&source); - loop.PostDelayedTask(FROM_HERE, base::MessageLoop::QuitClosure(), - TestTimeouts::action_timeout()); - loop.Run(); - wus->Stop(); - wus->Close(); -} - -// Perform a real-time test in loopback where the recorded audio is echoed -// back to the speaker. This test allows the user to verify that the audio -// sounds OK. A text file with name |kDeltaTimeMsFileName| is also generated. -TEST(WASAPIUnifiedStreamTest, DISABLED_RealTimePlayThrough) { - scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting()); - if (!CanRunUnifiedAudioTests(audio_manager.get())) - return; - - base::MessageLoopForUI loop; - UnifiedSourceCallback source; - WASAPIUnifiedStream* wus = CreateDefaultUnifiedStream(audio_manager.get()); - - EXPECT_TRUE(wus->Open()); - wus->Start(&source); - loop.PostDelayedTask(FROM_HERE, base::MessageLoop::QuitClosure(), - base::TimeDelta::FromMilliseconds(10000)); - loop.Run(); - wus->Close(); -} - -} // namespace media diff --git a/media/media.gyp b/media/media.gyp index 3bf503f..4ae986d 100644 --- a/media/media.gyp +++ b/media/media.gyp @@ -131,8 +131,6 @@ 'audio/fake_audio_output_stream.cc', 'audio/fake_audio_output_stream.h', 'audio/linux/audio_manager_linux.cc', - 'audio/mac/aggregate_device_manager.cc', - 'audio/mac/aggregate_device_manager.h', 'audio/mac/audio_auhal_mac.cc', 'audio/mac/audio_auhal_mac.h', 'audio/mac/audio_device_listener_mac.cc', @@ -145,10 +143,6 @@ 'audio/mac/audio_low_latency_output_mac.h', 'audio/mac/audio_manager_mac.cc', 'audio/mac/audio_manager_mac.h', - 'audio/mac/audio_synchronized_mac.cc', - 'audio/mac/audio_synchronized_mac.h', - 'audio/mac/audio_unified_mac.cc', - 'audio/mac/audio_unified_mac.h', 'audio/null_audio_sink.cc', 'audio/null_audio_sink.h', 'audio/openbsd/audio_manager_openbsd.cc', @@ -159,8 +153,6 @@ 'audio/pulse/pulse_input.h', 'audio/pulse/pulse_output.cc', 'audio/pulse/pulse_output.h', - 'audio/pulse/pulse_unified.cc', - 'audio/pulse/pulse_unified.h', 'audio/pulse/pulse_util.cc', 'audio/pulse/pulse_util.h', 'audio/sample_rates.cc', @@ -187,8 +179,6 @@ 'audio/win/audio_low_latency_output_win.h', 'audio/win/audio_manager_win.cc', 'audio/win/audio_manager_win.h', - 'audio/win/audio_unified_win.cc', - 'audio/win/audio_unified_win.h', 'audio/win/avrt_wrapper_win.cc', 'audio/win/avrt_wrapper_win.h', 'audio/win/core_audio_util_win.cc', @@ -769,8 +759,6 @@ 'audio/pulse/pulse_input.h', 'audio/pulse/pulse_output.cc', 'audio/pulse/pulse_output.h', - 'audio/pulse/pulse_unified.cc', - 'audio/pulse/pulse_unified.h', 'audio/pulse/pulse_util.cc', 'audio/pulse/pulse_util.h', ], @@ -939,7 +927,6 @@ 'audio/win/audio_low_latency_input_win_unittest.cc', 'audio/win/audio_low_latency_output_win_unittest.cc', 'audio/win/audio_output_win_unittest.cc', - 'audio/win/audio_unified_win_unittest.cc', 'audio/win/core_audio_util_win_unittest.cc', 'base/android/media_codec_bridge_unittest.cc', 'base/android/media_source_player_unittest.cc', |