| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/renderer/media/webrtc_audio_renderer.h" | 5 #include "content/renderer/media/webrtc_audio_renderer.h" |
| 6 | 6 |
| 7 #include <string> | 7 #include <string> |
| 8 #include <utility> | 8 #include <utility> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| 11 #include "base/bind.h" |
| 11 #include "base/run_loop.h" | 12 #include "base/run_loop.h" |
| 12 #include "base/single_thread_task_runner.h" | |
| 13 #include "build/build_config.h" | 13 #include "build/build_config.h" |
| 14 #include "content/public/renderer/media_stream_audio_renderer.h" | 14 #include "content/public/renderer/media_stream_audio_renderer.h" |
| 15 #include "content/renderer/media/audio_device_factory.h" | 15 #include "content/renderer/media/restartable_audio_output_device_factory.h" |
| 16 #include "content/renderer/media/audio_message_filter.h" | |
| 17 #include "content/renderer/media/webrtc/mock_peer_connection_dependency_factory.
h" | |
| 18 #include "content/renderer/media/webrtc_audio_device_impl.h" | 16 #include "content/renderer/media/webrtc_audio_device_impl.h" |
| 19 #include "media/audio/audio_output_device.h" | 17 #include "media/base/audio_renderer_sink.h" |
| 20 #include "media/audio/audio_output_ipc.h" | 18 #include "media/base/output_device.h" |
| 21 #include "media/base/audio_bus.h" | |
| 22 #include "media/base/mock_audio_renderer_sink.h" | |
| 23 #include "testing/gmock/include/gmock/gmock.h" | 19 #include "testing/gmock/include/gmock/gmock.h" |
| 24 #include "testing/gtest/include/gtest/gtest.h" | 20 #include "testing/gtest/include/gtest/gtest.h" |
| 25 #include "third_party/WebKit/public/platform/WebMediaStream.h" | 21 #include "third_party/WebKit/public/platform/WebMediaStream.h" |
| 26 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" | 22 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" |
| 27 #include "third_party/WebKit/public/web/WebHeap.h" | 23 #include "third_party/WebKit/public/web/WebHeap.h" |
| 28 #include "third_party/libjingle/source/talk/app/webrtc/mediastreaminterface.h" | 24 #include "third_party/libjingle/source/talk/app/webrtc/mediastreaminterface.h" |
| 29 | 25 |
| 30 using testing::Return; | 26 using testing::Return; |
| 31 using testing::_; | 27 using testing::_; |
| 32 | 28 |
| 33 namespace content { | 29 namespace content { |
| 34 | 30 |
| 35 namespace { | 31 namespace { |
| 36 | 32 |
| 37 const int kHardwareSampleRate = 44100; | 33 const int kHardwareSampleRate = 44100; |
| 38 const int kHardwareBufferSize = 512; | 34 const int kHardwareBufferSize = 512; |
| 39 const char kDefaultOutputDeviceId[] = ""; | 35 const char kDefaultOutputDeviceId[] = ""; |
| 40 const char kOtherOutputDeviceId[] = "other-output-device"; | 36 const char kOtherOutputDeviceId[] = "other-output-device"; |
| 41 const char kInvalidOutputDeviceId[] = "invalid-device"; | 37 const char kInvalidOutputDeviceId[] = "invalid-device"; |
| 42 | 38 |
| 43 class MockAudioOutputIPC : public media::AudioOutputIPC { | 39 class FakeRestartableSink |
| 40 : NON_EXPORTED_BASE(public media::RestartableAudioRendererSink), |
| 41 NON_EXPORTED_BASE(public media::OutputDevice) { |
| 44 public: | 42 public: |
| 45 MockAudioOutputIPC() {} | 43 FakeRestartableSink(const std::string& device_id) : device_id_(device_id) {} |
| 46 virtual ~MockAudioOutputIPC() {} | 44 MOCK_METHOD2(Initialize, |
| 47 | 45 void(const media::AudioParameters&, RenderCallback*)); |
| 48 MOCK_METHOD4(RequestDeviceAuthorization, | |
| 49 void(media::AudioOutputIPCDelegate* delegate, | |
| 50 int session_id, | |
| 51 const std::string& device_id, | |
| 52 const url::Origin& security_origin)); | |
| 53 MOCK_METHOD2(CreateStream, | |
| 54 void(media::AudioOutputIPCDelegate* delegate, | |
| 55 const media::AudioParameters& params)); | |
| 56 MOCK_METHOD0(PlayStream, void()); | |
| 57 MOCK_METHOD0(PauseStream, void()); | |
| 58 MOCK_METHOD0(CloseStream, void()); | |
| 59 MOCK_METHOD1(SetVolume, void(double volume)); | |
| 60 MOCK_METHOD2(SwitchOutputDevice, | |
| 61 void(const std::string& device_id, | |
| 62 const url::Origin& security_origin)); | |
| 63 }; | |
| 64 | |
| 65 class FakeAudioOutputDevice | |
| 66 : NON_EXPORTED_BASE(public media::AudioOutputDevice) { | |
| 67 public: | |
| 68 FakeAudioOutputDevice( | |
| 69 scoped_ptr<media::AudioOutputIPC> ipc, | |
| 70 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner, | |
| 71 const std::string& device_id) | |
| 72 : AudioOutputDevice(std::move(ipc), | |
| 73 io_task_runner, | |
| 74 0, | |
| 75 std::string(), | |
| 76 url::Origin()), | |
| 77 device_id_(device_id) {} | |
| 78 MOCK_METHOD0(Start, void()); | 46 MOCK_METHOD0(Start, void()); |
| 79 MOCK_METHOD0(Stop, void()); | 47 MOCK_METHOD0(Stop, void()); |
| 80 MOCK_METHOD0(Pause, void()); | 48 MOCK_METHOD0(Pause, void()); |
| 81 MOCK_METHOD0(Play, void()); | 49 MOCK_METHOD0(Play, void()); |
| 82 MOCK_METHOD1(SetVolume, bool(double volume)); | 50 MOCK_METHOD1(SetVolume, bool(double volume)); |
| 51 OutputDevice* GetOutputDevice() { return this; } |
| 52 MOCK_METHOD3(SwitchOutputDevice, |
| 53 void(const std::string&, |
| 54 const url::Origin&, |
| 55 const media::SwitchOutputDeviceCB&)); |
| 83 | 56 |
| 84 media::OutputDeviceStatus GetDeviceStatus() override { | 57 media::OutputDeviceStatus GetDeviceStatus() override { |
| 85 return device_id_ == kInvalidOutputDeviceId | 58 return device_id_ == kInvalidOutputDeviceId |
| 86 ? media::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL | 59 ? media::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL |
| 87 : media::OUTPUT_DEVICE_STATUS_OK; | 60 : media::OUTPUT_DEVICE_STATUS_OK; |
| 88 } | 61 } |
| 89 | 62 |
| 90 std::string GetDeviceId() const { return device_id_; } | 63 std::string GetDeviceId() const { return device_id_; } |
| 91 | 64 |
| 92 media::AudioParameters GetOutputParameters() override { | 65 media::AudioParameters GetOutputParameters() override { |
| 93 return media::AudioParameters(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, | 66 return media::AudioParameters(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, |
| 94 media::CHANNEL_LAYOUT_STEREO, | 67 media::CHANNEL_LAYOUT_STEREO, |
| 95 kHardwareSampleRate, 16, kHardwareBufferSize); | 68 kHardwareSampleRate, 16, kHardwareBufferSize); |
| 96 } | 69 } |
| 97 | 70 |
| 98 protected: | 71 protected: |
| 99 virtual ~FakeAudioOutputDevice() {} | 72 virtual ~FakeRestartableSink() {} |
| 100 | 73 |
| 101 private: | 74 private: |
| 102 const std::string device_id_; | 75 const std::string device_id_; |
| 103 }; | 76 }; |
| 104 | 77 |
| 105 class MockAudioRendererSource : public WebRtcAudioRendererSource { | 78 class MockAudioRendererSource : public WebRtcAudioRendererSource { |
| 106 public: | 79 public: |
| 107 MockAudioRendererSource() {} | 80 MockAudioRendererSource() {} |
| 108 virtual ~MockAudioRendererSource() {} | 81 virtual ~MockAudioRendererSource() {} |
| 109 MOCK_METHOD4(RenderData, void(media::AudioBus* audio_bus, | 82 MOCK_METHOD4(RenderData, void(media::AudioBus* audio_bus, |
| 110 int sample_rate, | 83 int sample_rate, |
| 111 int audio_delay_milliseconds, | 84 int audio_delay_milliseconds, |
| 112 base::TimeDelta* current_time)); | 85 base::TimeDelta* current_time)); |
| 113 MOCK_METHOD1(RemoveAudioRenderer, void(WebRtcAudioRenderer* renderer)); | 86 MOCK_METHOD1(RemoveAudioRenderer, void(WebRtcAudioRenderer* renderer)); |
| 114 MOCK_METHOD0(AudioRendererThreadStopped, void()); | 87 MOCK_METHOD0(AudioRendererThreadStopped, void()); |
| 115 }; | 88 }; |
| 116 | 89 |
| 117 } // namespace | 90 } // namespace |
| 118 | 91 |
| 119 class WebRtcAudioRendererTest : public testing::Test, | 92 class WebRtcAudioRendererTest : public testing::Test, |
| 120 public AudioDeviceFactory { | 93 public RestartableAudioOutputDeviceFactory { |
| 121 public: | 94 public: |
| 122 MOCK_METHOD1(MockSwitchDeviceCallback, void(media::OutputDeviceStatus)); | 95 MOCK_METHOD1(MockSwitchDeviceCallback, void(media::OutputDeviceStatus)); |
| 123 void SwitchDeviceCallback(base::RunLoop* loop, | 96 void SwitchDeviceCallback(base::RunLoop* loop, |
| 124 media::OutputDeviceStatus result) { | 97 media::OutputDeviceStatus result) { |
| 125 MockSwitchDeviceCallback(result); | 98 MockSwitchDeviceCallback(result); |
| 126 loop->Quit(); | 99 loop->Quit(); |
| 127 } | 100 } |
| 128 | 101 |
| 129 protected: | 102 protected: |
| 130 WebRtcAudioRendererTest() | 103 WebRtcAudioRendererTest() |
| 131 : message_loop_(new base::MessageLoopForIO), | 104 : message_loop_(new base::MessageLoopForIO), |
| 132 mock_ipc_(nullptr), | |
| 133 source_(new MockAudioRendererSource()) { | 105 source_(new MockAudioRendererSource()) { |
| 134 blink::WebVector<blink::WebMediaStreamTrack> dummy_tracks; | 106 blink::WebVector<blink::WebMediaStreamTrack> dummy_tracks; |
| 135 stream_.initialize("new stream", dummy_tracks, dummy_tracks); | 107 stream_.initialize("new stream", dummy_tracks, dummy_tracks); |
| 136 } | 108 } |
| 137 | 109 |
| 138 void SetupRenderer(const std::string& device_id) { | 110 void SetupRenderer(const std::string& device_id) { |
| 139 renderer_ = new WebRtcAudioRenderer(message_loop_->task_runner(), stream_, | 111 renderer_ = new WebRtcAudioRenderer(message_loop_->task_runner(), stream_, |
| 140 1, 1, device_id, url::Origin()); | 112 1, 1, device_id, url::Origin()); |
| 141 EXPECT_CALL(*this, MockCreateOutputDevice(1, _, device_id, _)); | 113 EXPECT_CALL(*this, MockCreateOutputDevice( |
| 114 RestartableAudioOutputDeviceFactory::kSourceWebRTC, |
| 115 _, _, device_id, _)); |
| 142 EXPECT_TRUE(renderer_->Initialize(source_.get())); | 116 EXPECT_TRUE(renderer_->Initialize(source_.get())); |
| 143 | 117 |
| 144 renderer_proxy_ = renderer_->CreateSharedAudioRendererProxy(stream_); | 118 renderer_proxy_ = renderer_->CreateSharedAudioRendererProxy(stream_); |
| 145 } | 119 } |
| 146 | 120 |
| 147 MOCK_METHOD1(CreateInputDevice, media::AudioInputDevice*(int)); | 121 MOCK_METHOD5(MockCreateOutputDevice, |
| 148 MOCK_METHOD4(MockCreateOutputDevice, | 122 media::RestartableAudioRendererSink*(SourceType, |
| 149 media::AudioOutputDevice*(int, | 123 int, |
| 150 int, | 124 int, |
| 151 const std::string&, | 125 const std::string&, |
| 152 const url::Origin&)); | 126 const url::Origin&)); |
| 153 media::AudioOutputDevice* CreateOutputDevice( | 127 media::RestartableAudioRendererSink* CreateOutputDevice( |
| 128 SourceType source_type, |
| 154 int render_frame_id, | 129 int render_frame_id, |
| 155 int session_id, | 130 int session_id, |
| 156 const std::string& device_id, | 131 const std::string& device_id, |
| 157 const url::Origin& security_origin) { | 132 const url::Origin& security_origin) { |
| 158 MockAudioOutputIPC* fake_ipc = new MockAudioOutputIPC(); | 133 FakeRestartableSink* fake_device = new FakeRestartableSink(device_id); |
| 159 FakeAudioOutputDevice* fake_device = | |
| 160 new FakeAudioOutputDevice(scoped_ptr<media::AudioOutputIPC>(fake_ipc), | |
| 161 message_loop_->task_runner(), device_id); | |
| 162 if (device_id != kInvalidOutputDeviceId) { | 134 if (device_id != kInvalidOutputDeviceId) { |
| 163 mock_output_device_ = fake_device; | 135 mock_output_device_ = fake_device; |
| 164 mock_ipc_ = fake_ipc; | |
| 165 EXPECT_CALL(*mock_output_device_.get(), Start()); | 136 EXPECT_CALL(*mock_output_device_.get(), Start()); |
| 166 } | 137 } |
| 167 | 138 |
| 168 MockCreateOutputDevice(render_frame_id, session_id, device_id, | 139 MockCreateOutputDevice(source_type, render_frame_id, session_id, device_id, |
| 169 security_origin); | 140 security_origin); |
| 170 return fake_device; | 141 return fake_device; |
| 171 } | 142 } |
| 172 | 143 |
| 173 void TearDown() override { | 144 void TearDown() override { |
| 174 renderer_proxy_ = nullptr; | 145 renderer_proxy_ = nullptr; |
| 175 renderer_ = nullptr; | 146 renderer_ = nullptr; |
| 176 stream_.reset(); | 147 stream_.reset(); |
| 177 source_.reset(); | 148 source_.reset(); |
| 178 mock_output_device_ = nullptr; | 149 mock_output_device_ = nullptr; |
| 179 blink::WebHeap::collectAllGarbageForTesting(); | 150 blink::WebHeap::collectAllGarbageForTesting(); |
| 180 } | 151 } |
| 181 | 152 |
| 182 // Used to construct |mock_output_device_|. | |
| 183 scoped_ptr<base::MessageLoopForIO> message_loop_; | 153 scoped_ptr<base::MessageLoopForIO> message_loop_; |
| 184 MockAudioOutputIPC* mock_ipc_; // Owned by AudioOuputDevice. | 154 scoped_refptr<FakeRestartableSink> mock_output_device_; |
| 185 | |
| 186 scoped_refptr<FakeAudioOutputDevice> mock_output_device_; | |
| 187 scoped_ptr<MockAudioRendererSource> source_; | 155 scoped_ptr<MockAudioRendererSource> source_; |
| 188 blink::WebMediaStream stream_; | 156 blink::WebMediaStream stream_; |
| 189 scoped_refptr<WebRtcAudioRenderer> renderer_; | 157 scoped_refptr<WebRtcAudioRenderer> renderer_; |
| 190 scoped_refptr<MediaStreamAudioRenderer> renderer_proxy_; | 158 scoped_refptr<MediaStreamAudioRenderer> renderer_proxy_; |
| 191 }; | 159 }; |
| 192 | 160 |
| 193 // Verify that the renderer will be stopped if the only proxy is stopped. | 161 // Verify that the renderer will be stopped if the only proxy is stopped. |
| 194 TEST_F(WebRtcAudioRendererTest, StopRenderer) { | 162 TEST_F(WebRtcAudioRendererTest, StopRenderer) { |
| 195 SetupRenderer(kDefaultOutputDeviceId); | 163 SetupRenderer(kDefaultOutputDeviceId); |
| 196 renderer_proxy_->Start(); | 164 renderer_proxy_->Start(); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 274 EXPECT_CALL(*source_.get(), RemoveAudioRenderer(renderer_.get())); | 242 EXPECT_CALL(*source_.get(), RemoveAudioRenderer(renderer_.get())); |
| 275 renderer_proxy_->Stop(); | 243 renderer_proxy_->Stop(); |
| 276 } | 244 } |
| 277 | 245 |
| 278 TEST_F(WebRtcAudioRendererTest, SwitchOutputDevice) { | 246 TEST_F(WebRtcAudioRendererTest, SwitchOutputDevice) { |
| 279 SetupRenderer(kDefaultOutputDeviceId); | 247 SetupRenderer(kDefaultOutputDeviceId); |
| 280 EXPECT_EQ(kDefaultOutputDeviceId, mock_output_device_->GetDeviceId()); | 248 EXPECT_EQ(kDefaultOutputDeviceId, mock_output_device_->GetDeviceId()); |
| 281 renderer_proxy_->Start(); | 249 renderer_proxy_->Start(); |
| 282 | 250 |
| 283 EXPECT_CALL(*mock_output_device_.get(), Stop()); | 251 EXPECT_CALL(*mock_output_device_.get(), Stop()); |
| 284 EXPECT_CALL(*this, MockCreateOutputDevice(_, _, kOtherOutputDeviceId, _)); | 252 EXPECT_CALL(*this, MockCreateOutputDevice( |
| 253 RestartableAudioOutputDeviceFactory::kSourceWebRTC, _, |
| 254 _, kOtherOutputDeviceId, _)); |
| 285 EXPECT_CALL(*source_.get(), AudioRendererThreadStopped()); | 255 EXPECT_CALL(*source_.get(), AudioRendererThreadStopped()); |
| 286 EXPECT_CALL(*this, MockSwitchDeviceCallback(media::OUTPUT_DEVICE_STATUS_OK)); | 256 EXPECT_CALL(*this, MockSwitchDeviceCallback(media::OUTPUT_DEVICE_STATUS_OK)); |
| 287 base::RunLoop loop; | 257 base::RunLoop loop; |
| 288 renderer_proxy_->GetOutputDevice()->SwitchOutputDevice( | 258 renderer_proxy_->GetOutputDevice()->SwitchOutputDevice( |
| 289 kOtherOutputDeviceId, url::Origin(), | 259 kOtherOutputDeviceId, url::Origin(), |
| 290 base::Bind(&WebRtcAudioRendererTest::SwitchDeviceCallback, | 260 base::Bind(&WebRtcAudioRendererTest::SwitchDeviceCallback, |
| 291 base::Unretained(this), &loop)); | 261 base::Unretained(this), &loop)); |
| 292 loop.Run(); | 262 loop.Run(); |
| 293 EXPECT_EQ(kOtherOutputDeviceId, mock_output_device_->GetDeviceId()); | 263 EXPECT_EQ(kOtherOutputDeviceId, mock_output_device_->GetDeviceId()); |
| 294 | 264 |
| 295 EXPECT_CALL(*mock_output_device_.get(), Stop()); | 265 EXPECT_CALL(*mock_output_device_.get(), Stop()); |
| 296 EXPECT_CALL(*source_.get(), RemoveAudioRenderer(renderer_.get())); | 266 EXPECT_CALL(*source_.get(), RemoveAudioRenderer(renderer_.get())); |
| 297 renderer_proxy_->Stop(); | 267 renderer_proxy_->Stop(); |
| 298 } | 268 } |
| 299 | 269 |
| 300 TEST_F(WebRtcAudioRendererTest, SwitchOutputDeviceInvalidDevice) { | 270 TEST_F(WebRtcAudioRendererTest, SwitchOutputDeviceInvalidDevice) { |
| 301 SetupRenderer(kDefaultOutputDeviceId); | 271 SetupRenderer(kDefaultOutputDeviceId); |
| 302 EXPECT_EQ(kDefaultOutputDeviceId, mock_output_device_->GetDeviceId()); | 272 EXPECT_EQ(kDefaultOutputDeviceId, mock_output_device_->GetDeviceId()); |
| 303 renderer_proxy_->Start(); | 273 renderer_proxy_->Start(); |
| 304 | 274 |
| 305 EXPECT_CALL(*this, MockCreateOutputDevice(_, _, kInvalidOutputDeviceId, _)); | 275 EXPECT_CALL(*this, MockCreateOutputDevice( |
| 276 RestartableAudioOutputDeviceFactory::kSourceWebRTC, _, |
| 277 _, kInvalidOutputDeviceId, _)); |
| 306 EXPECT_CALL(*this, MockSwitchDeviceCallback( | 278 EXPECT_CALL(*this, MockSwitchDeviceCallback( |
| 307 media::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL)); | 279 media::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL)); |
| 308 base::RunLoop loop; | 280 base::RunLoop loop; |
| 309 renderer_proxy_->GetOutputDevice()->SwitchOutputDevice( | 281 renderer_proxy_->GetOutputDevice()->SwitchOutputDevice( |
| 310 kInvalidOutputDeviceId, url::Origin(), | 282 kInvalidOutputDeviceId, url::Origin(), |
| 311 base::Bind(&WebRtcAudioRendererTest::SwitchDeviceCallback, | 283 base::Bind(&WebRtcAudioRendererTest::SwitchDeviceCallback, |
| 312 base::Unretained(this), &loop)); | 284 base::Unretained(this), &loop)); |
| 313 loop.Run(); | 285 loop.Run(); |
| 314 EXPECT_EQ(kDefaultOutputDeviceId, mock_output_device_->GetDeviceId()); | 286 EXPECT_EQ(kDefaultOutputDeviceId, mock_output_device_->GetDeviceId()); |
| 315 | 287 |
| 316 EXPECT_CALL(*mock_output_device_.get(), Stop()); | 288 EXPECT_CALL(*mock_output_device_.get(), Stop()); |
| 317 EXPECT_CALL(*source_.get(), RemoveAudioRenderer(renderer_.get())); | 289 EXPECT_CALL(*source_.get(), RemoveAudioRenderer(renderer_.get())); |
| 318 renderer_proxy_->Stop(); | 290 renderer_proxy_->Stop(); |
| 319 } | 291 } |
| 320 | 292 |
| 321 } // namespace content | 293 } // namespace content |
| OLD | NEW |