| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "base/environment.h" | 5 #include "base/environment.h" |
| 6 #include "base/memory/scoped_ptr.h" | 6 #include "base/memory/scoped_ptr.h" |
| 7 #include "base/message_loop.h" | 7 #include "base/message_loop.h" |
| 8 #include "base/process_util.h" | 8 #include "base/process_util.h" |
| 9 #include "base/sync_socket.h" | 9 #include "base/sync_socket.h" |
| 10 #include "content/browser/browser_thread.h" | 10 #include "content/browser/browser_thread.h" |
| 11 #include "content/browser/renderer_host/media/audio_renderer_host.h" | 11 #include "content/browser/renderer_host/media/audio_renderer_host.h" |
| 12 #include "content/common/media/audio_messages.h" | 12 #include "content/common/media/audio_messages.h" |
| 13 #include "ipc/ipc_message_utils.h" | 13 #include "ipc/ipc_message_utils.h" |
| 14 #include "media/audio/audio_manager.h" | 14 #include "media/audio/audio_manager.h" |
| 15 #include "media/audio/fake_audio_output_stream.h" | 15 #include "media/audio/fake_audio_output_stream.h" |
| 16 #include "testing/gmock/include/gmock/gmock.h" | 16 #include "testing/gmock/include/gmock/gmock.h" |
| 17 #include "testing/gtest/include/gtest/gtest.h" | 17 #include "testing/gtest/include/gtest/gtest.h" |
| 18 | 18 |
| 19 using ::testing::_; | 19 using ::testing::_; |
| 20 using ::testing::DoAll; | 20 using ::testing::DoAll; |
| 21 using ::testing::InSequence; | 21 using ::testing::InSequence; |
| 22 using ::testing::InvokeWithoutArgs; | 22 using ::testing::InvokeWithoutArgs; |
| 23 using ::testing::Return; | 23 using ::testing::Return; |
| 24 using ::testing::SaveArg; | 24 using ::testing::SaveArg; |
| 25 using ::testing::SetArgumentPointee; | 25 using ::testing::SetArgumentPointee; |
| 26 | 26 |
| 27 static const int kInvalidId = -1; | |
| 28 static const int kRouteId = 200; | |
| 29 static const int kStreamId = 50; | 27 static const int kStreamId = 50; |
| 30 | 28 |
| 31 static bool IsRunningHeadless() { | 29 static bool IsRunningHeadless() { |
| 32 scoped_ptr<base::Environment> env(base::Environment::Create()); | 30 scoped_ptr<base::Environment> env(base::Environment::Create()); |
| 33 if (env->HasVar("CHROME_HEADLESS")) | 31 if (env->HasVar("CHROME_HEADLESS")) |
| 34 return true; | 32 return true; |
| 35 return false; | 33 return false; |
| 36 } | 34 } |
| 37 | 35 |
| 38 class MockAudioRendererHost : public AudioRendererHost { | 36 class MockAudioRendererHost : public AudioRendererHost { |
| 39 public: | 37 public: |
| 40 MockAudioRendererHost() : shared_memory_length_(0) { | 38 MockAudioRendererHost() : shared_memory_length_(0) { |
| 41 } | 39 } |
| 42 | 40 |
| 43 virtual ~MockAudioRendererHost() { | 41 virtual ~MockAudioRendererHost() { |
| 44 } | 42 } |
| 45 | 43 |
| 46 // A list of mock methods. | 44 // A list of mock methods. |
| 47 MOCK_METHOD3(OnRequestPacket, | 45 MOCK_METHOD2(OnRequestPacket, |
| 48 void(int routing_id, int stream_id, | 46 void(int stream_id, AudioBuffersState buffers_state)); |
| 49 AudioBuffersState buffers_state)); | 47 MOCK_METHOD2(OnStreamCreated, |
| 50 MOCK_METHOD3(OnStreamCreated, | 48 void(int stream_id, int length)); |
| 51 void(int routing_id, int stream_id, int length)); | 49 MOCK_METHOD2(OnLowLatencyStreamCreated, |
| 52 MOCK_METHOD3(OnLowLatencyStreamCreated, | 50 void(int stream_id, int length)); |
| 53 void(int routing_id, int stream_id, int length)); | 51 MOCK_METHOD1(OnStreamPlaying, void(int stream_id)); |
| 54 MOCK_METHOD2(OnStreamPlaying, void(int routing_id, int stream_id)); | 52 MOCK_METHOD1(OnStreamPaused, void(int stream_id)); |
| 55 MOCK_METHOD2(OnStreamPaused, void(int routing_id, int stream_id)); | 53 MOCK_METHOD1(OnStreamError, void(int stream_id)); |
| 56 MOCK_METHOD2(OnStreamError, void(int routing_id, int stream_id)); | 54 MOCK_METHOD2(OnStreamVolume, |
| 57 MOCK_METHOD3(OnStreamVolume, | 55 void(int stream_id, double volume)); |
| 58 void(int routing_id, int stream_id, double volume)); | |
| 59 | 56 |
| 60 base::SharedMemory* shared_memory() { return shared_memory_.get(); } | 57 base::SharedMemory* shared_memory() { return shared_memory_.get(); } |
| 61 uint32 shared_memory_length() { return shared_memory_length_; } | 58 uint32 shared_memory_length() { return shared_memory_length_; } |
| 62 | 59 |
| 63 base::SyncSocket* sync_socket() { return sync_socket_.get(); } | 60 base::SyncSocket* sync_socket() { return sync_socket_.get(); } |
| 64 | 61 |
| 65 private: | 62 private: |
| 66 // This method is used to dispatch IPC messages to the renderer. We intercept | 63 // This method is used to dispatch IPC messages to the renderer. We intercept |
| 67 // these messages here and dispatch to our mock methods to verify the | 64 // these messages here and dispatch to our mock methods to verify the |
| 68 // conversation between this object and the renderer. | 65 // conversation between this object and the renderer. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 84 IPC_END_MESSAGE_MAP() | 81 IPC_END_MESSAGE_MAP() |
| 85 EXPECT_TRUE(handled); | 82 EXPECT_TRUE(handled); |
| 86 | 83 |
| 87 delete message; | 84 delete message; |
| 88 return true; | 85 return true; |
| 89 } | 86 } |
| 90 | 87 |
| 91 // These handler methods do minimal things and delegate to the mock methods. | 88 // These handler methods do minimal things and delegate to the mock methods. |
| 92 void OnRequestPacket(const IPC::Message& msg, int stream_id, | 89 void OnRequestPacket(const IPC::Message& msg, int stream_id, |
| 93 AudioBuffersState buffers_state) { | 90 AudioBuffersState buffers_state) { |
| 94 OnRequestPacket(msg.routing_id(), stream_id, buffers_state); | 91 OnRequestPacket(stream_id, buffers_state); |
| 95 } | 92 } |
| 96 | 93 |
| 97 void OnStreamCreated(const IPC::Message& msg, int stream_id, | 94 void OnStreamCreated(const IPC::Message& msg, int stream_id, |
| 98 base::SharedMemoryHandle handle, uint32 length) { | 95 base::SharedMemoryHandle handle, uint32 length) { |
| 99 // Maps the shared memory. | 96 // Maps the shared memory. |
| 100 shared_memory_.reset(new base::SharedMemory(handle, false)); | 97 shared_memory_.reset(new base::SharedMemory(handle, false)); |
| 101 ASSERT_TRUE(shared_memory_->Map(length)); | 98 ASSERT_TRUE(shared_memory_->Map(length)); |
| 102 ASSERT_TRUE(shared_memory_->memory()); | 99 ASSERT_TRUE(shared_memory_->memory()); |
| 103 shared_memory_length_ = length; | 100 shared_memory_length_ = length; |
| 104 | 101 |
| 105 // And then delegate the call to the mock method. | 102 // And then delegate the call to the mock method. |
| 106 OnStreamCreated(msg.routing_id(), stream_id, length); | 103 OnStreamCreated(stream_id, length); |
| 107 } | 104 } |
| 108 | 105 |
| 109 void OnLowLatencyStreamCreated(const IPC::Message& msg, int stream_id, | 106 void OnLowLatencyStreamCreated(const IPC::Message& msg, int stream_id, |
| 110 base::SharedMemoryHandle handle, | 107 base::SharedMemoryHandle handle, |
| 111 #if defined(OS_WIN) | 108 #if defined(OS_WIN) |
| 112 base::SyncSocket::Handle socket_handle, | 109 base::SyncSocket::Handle socket_handle, |
| 113 #else | 110 #else |
| 114 base::FileDescriptor socket_descriptor, | 111 base::FileDescriptor socket_descriptor, |
| 115 #endif | 112 #endif |
| 116 uint32 length) { | 113 uint32 length) { |
| 117 // Maps the shared memory. | 114 // Maps the shared memory. |
| 118 shared_memory_.reset(new base::SharedMemory(handle, false)); | 115 shared_memory_.reset(new base::SharedMemory(handle, false)); |
| 119 CHECK(shared_memory_->Map(length)); | 116 CHECK(shared_memory_->Map(length)); |
| 120 CHECK(shared_memory_->memory()); | 117 CHECK(shared_memory_->memory()); |
| 121 shared_memory_length_ = length; | 118 shared_memory_length_ = length; |
| 122 | 119 |
| 123 // Create the SyncSocket using the handle. | 120 // Create the SyncSocket using the handle. |
| 124 base::SyncSocket::Handle sync_socket_handle; | 121 base::SyncSocket::Handle sync_socket_handle; |
| 125 #if defined(OS_WIN) | 122 #if defined(OS_WIN) |
| 126 sync_socket_handle = socket_handle; | 123 sync_socket_handle = socket_handle; |
| 127 #else | 124 #else |
| 128 sync_socket_handle = socket_descriptor.fd; | 125 sync_socket_handle = socket_descriptor.fd; |
| 129 #endif | 126 #endif |
| 130 sync_socket_.reset(new base::SyncSocket(sync_socket_handle)); | 127 sync_socket_.reset(new base::SyncSocket(sync_socket_handle)); |
| 131 | 128 |
| 132 // And then delegate the call to the mock method. | 129 // And then delegate the call to the mock method. |
| 133 OnLowLatencyStreamCreated(msg.routing_id(), stream_id, length); | 130 OnLowLatencyStreamCreated(stream_id, length); |
| 134 } | 131 } |
| 135 | 132 |
| 136 void OnStreamStateChanged(const IPC::Message& msg, int stream_id, | 133 void OnStreamStateChanged(const IPC::Message& msg, int stream_id, |
| 137 AudioStreamState state) { | 134 AudioStreamState state) { |
| 138 if (state == kAudioStreamPlaying) { | 135 if (state == kAudioStreamPlaying) { |
| 139 OnStreamPlaying(msg.routing_id(), stream_id); | 136 OnStreamPlaying(stream_id); |
| 140 } else if (state == kAudioStreamPaused) { | 137 } else if (state == kAudioStreamPaused) { |
| 141 OnStreamPaused(msg.routing_id(), stream_id); | 138 OnStreamPaused(stream_id); |
| 142 } else if (state == kAudioStreamError) { | 139 } else if (state == kAudioStreamError) { |
| 143 OnStreamError(msg.routing_id(), stream_id); | 140 OnStreamError(stream_id); |
| 144 } else { | 141 } else { |
| 145 FAIL() << "Unknown stream state"; | 142 FAIL() << "Unknown stream state"; |
| 146 } | 143 } |
| 147 } | 144 } |
| 148 | 145 |
| 149 void OnStreamVolume(const IPC::Message& msg, int stream_id, double volume) { | 146 void OnStreamVolume(const IPC::Message& msg, int stream_id, double volume) { |
| 150 OnStreamVolume(msg.routing_id(), stream_id, volume); | 147 OnStreamVolume(stream_id, volume); |
| 151 } | 148 } |
| 152 | 149 |
| 153 scoped_ptr<base::SharedMemory> shared_memory_; | 150 scoped_ptr<base::SharedMemory> shared_memory_; |
| 154 scoped_ptr<base::SyncSocket> sync_socket_; | 151 scoped_ptr<base::SyncSocket> sync_socket_; |
| 155 uint32 shared_memory_length_; | 152 uint32 shared_memory_length_; |
| 156 | 153 |
| 157 DISALLOW_COPY_AND_ASSIGN(MockAudioRendererHost); | 154 DISALLOW_COPY_AND_ASSIGN(MockAudioRendererHost); |
| 158 }; | 155 }; |
| 159 | 156 |
| 160 ACTION_P(QuitMessageLoop, message_loop) { | 157 ACTION_P(QuitMessageLoop, message_loop) { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 189 // We need to continue running message_loop_ to complete all destructions. | 186 // We need to continue running message_loop_ to complete all destructions. |
| 190 SyncWithAudioThread(); | 187 SyncWithAudioThread(); |
| 191 | 188 |
| 192 io_thread_.reset(); | 189 io_thread_.reset(); |
| 193 } | 190 } |
| 194 | 191 |
| 195 void Create() { | 192 void Create() { |
| 196 InSequence s; | 193 InSequence s; |
| 197 // 1. We will first receive a OnStreamCreated() signal. | 194 // 1. We will first receive a OnStreamCreated() signal. |
| 198 EXPECT_CALL(*host_, | 195 EXPECT_CALL(*host_, |
| 199 OnStreamCreated(kRouteId, kStreamId, _)); | 196 OnStreamCreated(kStreamId, _)); |
| 200 | 197 |
| 201 // 2. First packet request will arrive. | 198 // 2. First packet request will arrive. |
| 202 EXPECT_CALL(*host_, OnRequestPacket(kRouteId, kStreamId, _)) | 199 EXPECT_CALL(*host_, OnRequestPacket(kStreamId, _)) |
| 203 .WillOnce(QuitMessageLoop(message_loop_.get())); | 200 .WillOnce(QuitMessageLoop(message_loop_.get())); |
| 204 | 201 |
| 205 IPC::Message msg; | |
| 206 msg.set_routing_id(kRouteId); | |
| 207 | |
| 208 AudioParameters params; | 202 AudioParameters params; |
| 209 if (mock_stream_) | 203 if (mock_stream_) |
| 210 params.format = AudioParameters::AUDIO_MOCK; | 204 params.format = AudioParameters::AUDIO_MOCK; |
| 211 else | 205 else |
| 212 params.format = AudioParameters::AUDIO_PCM_LINEAR; | 206 params.format = AudioParameters::AUDIO_PCM_LINEAR; |
| 213 params.channels = 2; | 207 params.channels = 2; |
| 214 params.sample_rate = AudioParameters::kAudioCDSampleRate; | 208 params.sample_rate = AudioParameters::kAudioCDSampleRate; |
| 215 params.bits_per_sample = 16; | 209 params.bits_per_sample = 16; |
| 216 params.samples_per_packet = 0; | 210 params.samples_per_packet = 0; |
| 217 | 211 |
| 218 // Send a create stream message to the audio output stream and wait until | 212 // Send a create stream message to the audio output stream and wait until |
| 219 // we receive the created message. | 213 // we receive the created message. |
| 220 host_->OnCreateStream(msg, kStreamId, params, false); | 214 host_->OnCreateStream(kStreamId, params, false); |
| 221 message_loop_->Run(); | 215 message_loop_->Run(); |
| 222 } | 216 } |
| 223 | 217 |
| 224 void CreateLowLatency() { | 218 void CreateLowLatency() { |
| 225 InSequence s; | 219 InSequence s; |
| 226 // We will first receive a OnLowLatencyStreamCreated() signal. | 220 // We will first receive a OnLowLatencyStreamCreated() signal. |
| 227 EXPECT_CALL(*host_, | 221 EXPECT_CALL(*host_, |
| 228 OnLowLatencyStreamCreated(kRouteId, kStreamId, _)) | 222 OnLowLatencyStreamCreated(kStreamId, _)) |
| 229 .WillOnce(QuitMessageLoop(message_loop_.get())); | 223 .WillOnce(QuitMessageLoop(message_loop_.get())); |
| 230 | 224 |
| 231 IPC::Message msg; | |
| 232 msg.set_routing_id(kRouteId); | |
| 233 | |
| 234 AudioParameters params; | 225 AudioParameters params; |
| 235 if (mock_stream_) | 226 if (mock_stream_) |
| 236 params.format = AudioParameters::AUDIO_MOCK; | 227 params.format = AudioParameters::AUDIO_MOCK; |
| 237 else | 228 else |
| 238 params.format = AudioParameters::AUDIO_PCM_LINEAR; | 229 params.format = AudioParameters::AUDIO_PCM_LINEAR; |
| 239 params.channels = 2; | 230 params.channels = 2; |
| 240 params.sample_rate = AudioParameters::kAudioCDSampleRate; | 231 params.sample_rate = AudioParameters::kAudioCDSampleRate; |
| 241 params.bits_per_sample = 16; | 232 params.bits_per_sample = 16; |
| 242 params.samples_per_packet = 0; | 233 params.samples_per_packet = 0; |
| 243 | 234 |
| 244 // Send a create stream message to the audio output stream and wait until | 235 // Send a create stream message to the audio output stream and wait until |
| 245 // we receive the created message. | 236 // we receive the created message. |
| 246 host_->OnCreateStream(msg, kStreamId, params, true); | 237 host_->OnCreateStream(kStreamId, params, true); |
| 247 message_loop_->Run(); | 238 message_loop_->Run(); |
| 248 } | 239 } |
| 249 | 240 |
| 250 void Close() { | 241 void Close() { |
| 251 // Send a message to AudioRendererHost to tell it we want to close the | 242 // Send a message to AudioRendererHost to tell it we want to close the |
| 252 // stream. | 243 // stream. |
| 253 IPC::Message msg; | 244 host_->OnCloseStream(kStreamId); |
| 254 msg.set_routing_id(kRouteId); | |
| 255 host_->OnCloseStream(msg, kStreamId); | |
| 256 message_loop_->RunAllPending(); | 245 message_loop_->RunAllPending(); |
| 257 } | 246 } |
| 258 | 247 |
| 259 void Play() { | 248 void Play() { |
| 260 EXPECT_CALL(*host_, OnStreamPlaying(kRouteId, kStreamId)) | 249 EXPECT_CALL(*host_, OnStreamPlaying(kStreamId)) |
| 261 .WillOnce(QuitMessageLoop(message_loop_.get())); | 250 .WillOnce(QuitMessageLoop(message_loop_.get())); |
| 262 | 251 |
| 263 IPC::Message msg; | 252 host_->OnPlayStream(kStreamId); |
| 264 msg.set_routing_id(kRouteId); | |
| 265 host_->OnPlayStream(msg, kStreamId); | |
| 266 message_loop_->Run(); | 253 message_loop_->Run(); |
| 267 } | 254 } |
| 268 | 255 |
| 269 void Pause() { | 256 void Pause() { |
| 270 EXPECT_CALL(*host_, OnStreamPaused(kRouteId, kStreamId)) | 257 EXPECT_CALL(*host_, OnStreamPaused(kStreamId)) |
| 271 .WillOnce(QuitMessageLoop(message_loop_.get())); | 258 .WillOnce(QuitMessageLoop(message_loop_.get())); |
| 272 | 259 |
| 273 IPC::Message msg; | 260 host_->OnPauseStream(kStreamId); |
| 274 msg.set_routing_id(kRouteId); | |
| 275 host_->OnPauseStream(msg, kStreamId); | |
| 276 message_loop_->Run(); | 261 message_loop_->Run(); |
| 277 } | 262 } |
| 278 | 263 |
| 279 void SetVolume(double volume) { | 264 void SetVolume(double volume) { |
| 280 IPC::Message msg; | 265 host_->OnSetVolume(kStreamId, volume); |
| 281 msg.set_routing_id(kRouteId); | |
| 282 host_->OnSetVolume(msg, kStreamId, volume); | |
| 283 message_loop_->RunAllPending(); | 266 message_loop_->RunAllPending(); |
| 284 } | 267 } |
| 285 | 268 |
| 286 void NotifyPacketReady() { | 269 void NotifyPacketReady() { |
| 287 EXPECT_CALL(*host_, OnRequestPacket(kRouteId, kStreamId, _)) | 270 EXPECT_CALL(*host_, OnRequestPacket(kStreamId, _)) |
| 288 .WillOnce(QuitMessageLoop(message_loop_.get())); | 271 .WillOnce(QuitMessageLoop(message_loop_.get())); |
| 289 | 272 |
| 290 IPC::Message msg; | |
| 291 msg.set_routing_id(kRouteId); | |
| 292 memset(host_->shared_memory()->memory(), 0, host_->shared_memory_length()); | 273 memset(host_->shared_memory()->memory(), 0, host_->shared_memory_length()); |
| 293 host_->OnNotifyPacketReady(msg, kStreamId, | 274 host_->OnNotifyPacketReady(kStreamId, host_->shared_memory_length()); |
| 294 host_->shared_memory_length()); | |
| 295 message_loop_->Run(); | 275 message_loop_->Run(); |
| 296 } | 276 } |
| 297 | 277 |
| 298 void SimulateError() { | 278 void SimulateError() { |
| 299 // Find the first AudioOutputController in the AudioRendererHost. | 279 // Find the first AudioOutputController in the AudioRendererHost. |
| 300 CHECK(host_->audio_entries_.size()) | 280 CHECK(host_->audio_entries_.size()) |
| 301 << "Calls Create() before calling this method"; | 281 << "Calls Create() before calling this method"; |
| 302 media::AudioOutputController* controller = | 282 media::AudioOutputController* controller = |
| 303 host_->audio_entries_.begin()->second->controller; | 283 host_->audio_entries_.begin()->second->controller; |
| 304 CHECK(controller) << "AudioOutputController not found"; | 284 CHECK(controller) << "AudioOutputController not found"; |
| 305 | 285 |
| 306 // Expect an error signal sent through IPC. | 286 // Expect an error signal sent through IPC. |
| 307 EXPECT_CALL(*host_, OnStreamError(kRouteId, kStreamId)); | 287 EXPECT_CALL(*host_, OnStreamError(kStreamId)); |
| 308 | 288 |
| 309 // Simulate an error sent from the audio device. | 289 // Simulate an error sent from the audio device. |
| 310 host_->OnError(controller, 0); | 290 host_->OnError(controller, 0); |
| 311 SyncWithAudioThread(); | 291 SyncWithAudioThread(); |
| 312 | 292 |
| 313 // Expect the audio stream record is removed. | 293 // Expect the audio stream record is removed. |
| 314 EXPECT_EQ(0u, host_->audio_entries_.size()); | 294 EXPECT_EQ(0u, host_->audio_entries_.size()); |
| 315 } | 295 } |
| 316 | 296 |
| 317 // Called on the audio thread. | 297 // Called on the audio thread. |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 478 | 458 |
| 479 // Simulate the case where a stream is not properly closed. | 459 // Simulate the case where a stream is not properly closed. |
| 480 TEST_F(AudioRendererHostTest, CreateLowLatencyAndShutdown) { | 460 TEST_F(AudioRendererHostTest, CreateLowLatencyAndShutdown) { |
| 481 if (!IsRunningHeadless()) | 461 if (!IsRunningHeadless()) |
| 482 EnableRealDevice(); | 462 EnableRealDevice(); |
| 483 | 463 |
| 484 CreateLowLatency(); | 464 CreateLowLatency(); |
| 485 } | 465 } |
| 486 | 466 |
| 487 // TODO(hclam): Add tests for data conversation in low latency mode. | 467 // TODO(hclam): Add tests for data conversation in low latency mode. |
| OLD | NEW |