Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "media/audio/audio_input_controller.h" | 5 #include "media/audio/audio_input_controller.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/strings/stringprintf.h" | 8 #include "base/strings/stringprintf.h" |
| 9 #include "base/threading/thread_restrictions.h" | 9 #include "base/threading/thread_restrictions.h" |
| 10 #include "base/time/time.h" | 10 #include "base/time/time.h" |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 66 result, | 66 result, |
| 67 CAPTURE_STARTUP_RESULT_MAX + 1); | 67 CAPTURE_STARTUP_RESULT_MAX + 1); |
| 68 | 68 |
| 69 } | 69 } |
| 70 | 70 |
| 71 namespace media { | 71 namespace media { |
| 72 | 72 |
| 73 // static | 73 // static |
| 74 AudioInputController::Factory* AudioInputController::factory_ = NULL; | 74 AudioInputController::Factory* AudioInputController::factory_ = NULL; |
| 75 | 75 |
| 76 AudioInputController::AudioInputController(EventHandler* handler, | 76 AudioInputController::AudioInputController(AudioManager* audio_manager, |
| 77 EventHandler* handler, | |
| 77 SyncWriter* sync_writer, | 78 SyncWriter* sync_writer, |
| 78 UserInputMonitor* user_input_monitor) | 79 UserInputMonitor* user_input_monitor) |
| 79 : creator_task_runner_(base::MessageLoopProxy::current()), | 80 : creator_task_runner_(base::MessageLoopProxy::current()), |
| 80 handler_(handler), | 81 handler_(handler), |
| 82 audio_manager_(audio_manager), | |
| 81 stream_(NULL), | 83 stream_(NULL), |
| 82 data_is_active_(false), | 84 data_is_active_(false), |
| 83 state_(CLOSED), | 85 state_(CLOSED), |
| 84 sync_writer_(sync_writer), | 86 sync_writer_(sync_writer), |
| 85 max_volume_(0.0), | 87 max_volume_(0.0), |
| 86 user_input_monitor_(user_input_monitor), | 88 user_input_monitor_(user_input_monitor), |
| 87 #if defined(AUDIO_POWER_MONITORING) | 89 #if defined(AUDIO_POWER_MONITORING) |
| 88 silence_state_(SILENCE_STATE_NO_MEASUREMENT), | 90 silence_state_(SILENCE_STATE_NO_MEASUREMENT), |
| 89 #endif | 91 #endif |
| 90 prev_key_down_count_(0) { | 92 prev_key_down_count_(0) { |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 104 UserInputMonitor* user_input_monitor) { | 106 UserInputMonitor* user_input_monitor) { |
| 105 DCHECK(audio_manager); | 107 DCHECK(audio_manager); |
| 106 | 108 |
| 107 if (!params.IsValid() || (params.channels() > kMaxInputChannels)) | 109 if (!params.IsValid() || (params.channels() > kMaxInputChannels)) |
| 108 return NULL; | 110 return NULL; |
| 109 | 111 |
| 110 if (factory_) { | 112 if (factory_) { |
| 111 return factory_->Create( | 113 return factory_->Create( |
| 112 audio_manager, event_handler, params, user_input_monitor); | 114 audio_manager, event_handler, params, user_input_monitor); |
| 113 } | 115 } |
| 114 scoped_refptr<AudioInputController> controller( | 116 scoped_refptr<AudioInputController> controller(new AudioInputController( |
| 115 new AudioInputController(event_handler, NULL, user_input_monitor)); | 117 audio_manager, event_handler, NULL, user_input_monitor)); |
| 116 | 118 |
| 117 controller->task_runner_ = audio_manager->GetTaskRunner(); | 119 controller->task_runner_ = audio_manager->GetTaskRunner(); |
| 118 | 120 |
| 119 // Create and open a new audio input stream from the existing | 121 // Create and open a new audio input stream from the existing |
| 120 // audio-device thread. | 122 // audio-device thread. |
| 121 if (!controller->task_runner_->PostTask(FROM_HERE, | 123 if (!controller->task_runner_->PostTask( |
| 122 base::Bind(&AudioInputController::DoCreate, controller, | 124 FROM_HERE, |
| 123 base::Unretained(audio_manager), params, device_id))) { | 125 base::Bind(&AudioInputController::DoCreate, |
| 126 controller, | |
| 127 params, | |
| 128 device_id))) { | |
| 124 controller = NULL; | 129 controller = NULL; |
| 125 } | 130 } |
| 126 | 131 |
| 127 return controller; | 132 return controller; |
| 128 } | 133 } |
| 129 | 134 |
| 130 // static | 135 // static |
| 131 scoped_refptr<AudioInputController> AudioInputController::CreateLowLatency( | 136 scoped_refptr<AudioInputController> AudioInputController::CreateLowLatency( |
| 132 AudioManager* audio_manager, | 137 AudioManager* audio_manager, |
| 133 EventHandler* event_handler, | 138 EventHandler* event_handler, |
| 134 const AudioParameters& params, | 139 const AudioParameters& params, |
| 135 const std::string& device_id, | 140 const std::string& device_id, |
| 136 SyncWriter* sync_writer, | 141 SyncWriter* sync_writer, |
| 137 UserInputMonitor* user_input_monitor) { | 142 UserInputMonitor* user_input_monitor) { |
| 138 DCHECK(audio_manager); | 143 DCHECK(audio_manager); |
| 139 DCHECK(sync_writer); | 144 DCHECK(sync_writer); |
| 140 | 145 |
| 141 if (!params.IsValid() || (params.channels() > kMaxInputChannels)) | 146 if (!params.IsValid() || (params.channels() > kMaxInputChannels)) |
| 142 return NULL; | 147 return NULL; |
| 143 | 148 |
| 144 // Create the AudioInputController object and ensure that it runs on | 149 // Create the AudioInputController object and ensure that it runs on |
| 145 // the audio-manager thread. | 150 // the audio-manager thread. |
| 146 scoped_refptr<AudioInputController> controller( | 151 scoped_refptr<AudioInputController> controller(new AudioInputController( |
| 147 new AudioInputController(event_handler, sync_writer, user_input_monitor)); | 152 audio_manager, event_handler, sync_writer, user_input_monitor)); |
| 148 controller->task_runner_ = audio_manager->GetTaskRunner(); | 153 controller->task_runner_ = audio_manager->GetTaskRunner(); |
| 149 | 154 |
| 150 // Create and open a new audio input stream from the existing | 155 // Create and open a new audio input stream from the existing |
| 151 // audio-device thread. Use the provided audio-input device. | 156 // audio-device thread. Use the provided audio-input device. |
| 152 if (!controller->task_runner_->PostTask(FROM_HERE, | 157 if (!controller->task_runner_->PostTask( |
| 153 base::Bind(&AudioInputController::DoCreate, controller, | 158 FROM_HERE, |
| 154 base::Unretained(audio_manager), params, device_id))) { | 159 base::Bind(&AudioInputController::DoCreate, |
| 160 controller, | |
| 161 params, | |
| 162 device_id))) { | |
| 155 controller = NULL; | 163 controller = NULL; |
| 156 } | 164 } |
| 157 | 165 |
| 158 return controller; | 166 return controller; |
| 159 } | 167 } |
| 160 | 168 |
| 161 // static | 169 // static |
| 162 scoped_refptr<AudioInputController> AudioInputController::CreateForStream( | 170 scoped_refptr<AudioInputController> AudioInputController::CreateForStream( |
| 163 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, | 171 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
| 164 EventHandler* event_handler, | 172 EventHandler* event_handler, |
| 165 AudioInputStream* stream, | 173 AudioInputStream* stream, |
| 166 SyncWriter* sync_writer, | 174 SyncWriter* sync_writer, |
| 167 UserInputMonitor* user_input_monitor) { | 175 UserInputMonitor* user_input_monitor) { |
| 168 DCHECK(sync_writer); | 176 DCHECK(sync_writer); |
| 169 DCHECK(stream); | 177 DCHECK(stream); |
| 170 | 178 |
| 171 // Create the AudioInputController object and ensure that it runs on | 179 // Create the AudioInputController object and ensure that it runs on |
| 172 // the audio-manager thread. | 180 // the audio-manager thread. |
| 173 scoped_refptr<AudioInputController> controller( | 181 scoped_refptr<AudioInputController> controller(new AudioInputController( |
| 174 new AudioInputController(event_handler, sync_writer, user_input_monitor)); | 182 NULL, event_handler, sync_writer, user_input_monitor)); |
| 175 controller->task_runner_ = task_runner; | 183 controller->task_runner_ = task_runner; |
| 176 | 184 |
| 177 // TODO(miu): See TODO at top of file. Until that's resolved, we need to | 185 // TODO(miu): See TODO at top of file. Until that's resolved, we need to |
| 178 // disable the error auto-detection here (since the audio mirroring | 186 // disable the error auto-detection here (since the audio mirroring |
| 179 // implementation will reliably report error and close events). Note, of | 187 // implementation will reliably report error and close events). Note, of |
| 180 // course, that we're assuming CreateForStream() has been called for the audio | 188 // course, that we're assuming CreateForStream() has been called for the audio |
| 181 // mirroring use case only. | 189 // mirroring use case only. |
| 182 if (!controller->task_runner_->PostTask( | 190 if (!controller->task_runner_->PostTask( |
| 183 FROM_HERE, | 191 FROM_HERE, |
| 184 base::Bind(&AudioInputController::DoCreateForStream, | 192 base::Bind(&AudioInputController::DoCreateForStream, |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 206 void AudioInputController::SetVolume(double volume) { | 214 void AudioInputController::SetVolume(double volume) { |
| 207 task_runner_->PostTask(FROM_HERE, base::Bind( | 215 task_runner_->PostTask(FROM_HERE, base::Bind( |
| 208 &AudioInputController::DoSetVolume, this, volume)); | 216 &AudioInputController::DoSetVolume, this, volume)); |
| 209 } | 217 } |
| 210 | 218 |
| 211 void AudioInputController::SetAutomaticGainControl(bool enabled) { | 219 void AudioInputController::SetAutomaticGainControl(bool enabled) { |
| 212 task_runner_->PostTask(FROM_HERE, base::Bind( | 220 task_runner_->PostTask(FROM_HERE, base::Bind( |
| 213 &AudioInputController::DoSetAutomaticGainControl, this, enabled)); | 221 &AudioInputController::DoSetAutomaticGainControl, this, enabled)); |
| 214 } | 222 } |
| 215 | 223 |
| 216 void AudioInputController::DoCreate(AudioManager* audio_manager, | 224 void AudioInputController::DoCreate(const AudioParameters& params, |
| 217 const AudioParameters& params, | |
| 218 const std::string& device_id) { | 225 const std::string& device_id) { |
| 219 DCHECK(task_runner_->BelongsToCurrentThread()); | 226 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 220 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CreateTime"); | 227 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CreateTime"); |
| 228 if (handler_) { | |
| 229 std::string log_string = | |
| 230 base::StringPrintf("AIC::DoCreate(device_id=%s)", device_id.c_str()); | |
|
Henrik Grunell
2014/08/22 16:14:42
What device id is this? Unique in what way? Can it
no longer working on chromium
2014/08/25 08:20:05
This is the uniqie id of the device, we can't log
henrika (OOO until Aug 14)
2014/08/25 12:47:44
Removing. Thanks.
| |
| 231 handler_->OnLog(this, log_string); | |
| 232 } | |
| 221 | 233 |
| 222 #if defined(AUDIO_POWER_MONITORING) | 234 #if defined(AUDIO_POWER_MONITORING) |
| 223 // Create the audio (power) level meter given the provided audio parameters. | 235 // Create the audio (power) level meter given the provided audio parameters. |
| 224 // An AudioBus is also needed to wrap the raw data buffer from the native | 236 // An AudioBus is also needed to wrap the raw data buffer from the native |
| 225 // layer to match AudioPowerMonitor::Scan(). | 237 // layer to match AudioPowerMonitor::Scan(). |
| 226 // TODO(henrika): Remove use of extra AudioBus. See http://crbug.com/375155. | 238 // TODO(henrika): Remove use of extra AudioBus. See http://crbug.com/375155. |
| 227 audio_level_.reset(new media::AudioPowerMonitor( | 239 audio_level_.reset(new media::AudioPowerMonitor( |
| 228 params.sample_rate(), | 240 params.sample_rate(), |
| 229 TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMilliseconds))); | 241 TimeDelta::FromMilliseconds(kPowerMeasurementTimeConstantMilliseconds))); |
| 230 audio_params_ = params; | 242 audio_params_ = params; |
| 231 silence_state_ = SILENCE_STATE_NO_MEASUREMENT; | 243 silence_state_ = SILENCE_STATE_NO_MEASUREMENT; |
| 232 #endif | 244 #endif |
| 233 | 245 |
| 246 if (audio_manager_) | |
| 247 audio_manager_->AddStateChangeListener(this); | |
| 248 | |
| 234 // TODO(miu): See TODO at top of file. Until that's resolved, assume all | 249 // TODO(miu): See TODO at top of file. Until that's resolved, assume all |
| 235 // platform audio input requires the |no_data_timer_| be used to auto-detect | 250 // platform audio input requires the |no_data_timer_| be used to auto-detect |
| 236 // errors. In reality, probably only Windows needs to be treated as | 251 // errors. In reality, probably only Windows needs to be treated as |
| 237 // unreliable here. | 252 // unreliable here. |
| 238 DoCreateForStream(audio_manager->MakeAudioInputStream(params, device_id)); | 253 DoCreateForStream(audio_manager_->MakeAudioInputStream(params, device_id)); |
| 239 } | 254 } |
| 240 | 255 |
| 241 void AudioInputController::DoCreateForStream( | 256 void AudioInputController::DoCreateForStream( |
| 242 AudioInputStream* stream_to_control) { | 257 AudioInputStream* stream_to_control) { |
| 243 DCHECK(task_runner_->BelongsToCurrentThread()); | 258 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 244 | 259 |
| 245 DCHECK(!stream_); | 260 DCHECK(!stream_); |
| 246 stream_ = stream_to_control; | 261 stream_ = stream_to_control; |
| 247 | 262 |
| 248 if (!stream_) { | 263 if (!stream_) { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 291 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.RecordTime"); | 306 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.RecordTime"); |
| 292 | 307 |
| 293 if (state_ != CREATED) | 308 if (state_ != CREATED) |
| 294 return; | 309 return; |
| 295 | 310 |
| 296 { | 311 { |
| 297 base::AutoLock auto_lock(lock_); | 312 base::AutoLock auto_lock(lock_); |
| 298 state_ = RECORDING; | 313 state_ = RECORDING; |
| 299 } | 314 } |
| 300 | 315 |
| 316 if (handler_) | |
| 317 handler_->OnLog(this, "AIC::DoRecord"); | |
|
no longer working on chromium
2014/08/25 08:20:05
I don't really think you should log these, DoRecor
henrika (OOO until Aug 14)
2014/08/25 12:47:44
Well, if it does that may very well be a reason wh
| |
| 318 | |
| 301 if (no_data_timer_) { | 319 if (no_data_timer_) { |
| 302 // Start the data timer. Once |kTimerResetIntervalSeconds| have passed, | 320 // Start the data timer. Once |kTimerResetIntervalSeconds| have passed, |
| 303 // a callback to FirstCheckForNoData() is made. | 321 // a callback to FirstCheckForNoData() is made. |
| 304 no_data_timer_->Reset(); | 322 no_data_timer_->Reset(); |
| 305 } | 323 } |
| 306 | 324 |
| 307 stream_->Start(this); | 325 stream_->Start(this); |
| 308 if (handler_) | 326 if (handler_) |
| 309 handler_->OnRecording(this); | 327 handler_->OnRecording(this); |
| 310 } | 328 } |
| 311 | 329 |
| 312 void AudioInputController::DoClose() { | 330 void AudioInputController::DoClose() { |
| 313 DCHECK(task_runner_->BelongsToCurrentThread()); | 331 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 314 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CloseTime"); | 332 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CloseTime"); |
| 315 | 333 |
| 316 if (state_ == CLOSED) | 334 if (state_ == CLOSED) |
| 317 return; | 335 return; |
| 318 | 336 |
| 337 if (handler_) | |
| 338 handler_->OnLog(this, "AIC::DoClose"); | |
| 339 | |
| 319 // Delete the timer on the same thread that created it. | 340 // Delete the timer on the same thread that created it. |
| 320 no_data_timer_.reset(); | 341 no_data_timer_.reset(); |
| 321 | 342 |
| 322 DoStopCloseAndClearStream(); | 343 DoStopCloseAndClearStream(); |
| 323 SetDataIsActive(false); | 344 SetDataIsActive(false); |
| 324 | 345 |
| 346 if (audio_manager_) | |
| 347 audio_manager_->RemoveStateChangeListener(this); | |
|
Henrik Grunell
2014/08/22 16:14:43
Should the raw |audio_manager_| pointer be set to
henrika (OOO until Aug 14)
2014/08/25 12:47:44
It could but I can't really see the gain actually
| |
| 348 | |
| 325 if (SharedMemoryAndSyncSocketMode()) | 349 if (SharedMemoryAndSyncSocketMode()) |
| 326 sync_writer_->Close(); | 350 sync_writer_->Close(); |
| 327 | 351 |
| 328 if (user_input_monitor_) | 352 if (user_input_monitor_) |
| 329 user_input_monitor_->DisableKeyPressMonitoring(); | 353 user_input_monitor_->DisableKeyPressMonitoring(); |
| 330 | 354 |
| 331 #if defined(AUDIO_POWER_MONITORING) | 355 #if defined(AUDIO_POWER_MONITORING) |
| 332 // Send UMA stats if we have enabled power monitoring. | 356 // Send UMA stats if we have enabled power monitoring. |
| 333 if (audio_level_) { | 357 if (audio_level_) { |
| 334 LogSilenceState(silence_state_); | 358 LogSilenceState(silence_state_); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 376 return; | 400 return; |
| 377 | 401 |
| 378 stream_->SetAutomaticGainControl(enabled); | 402 stream_->SetAutomaticGainControl(enabled); |
| 379 } | 403 } |
| 380 | 404 |
| 381 void AudioInputController::FirstCheckForNoData() { | 405 void AudioInputController::FirstCheckForNoData() { |
| 382 DCHECK(task_runner_->BelongsToCurrentThread()); | 406 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 383 LogCaptureStartupResult(GetDataIsActive() ? | 407 LogCaptureStartupResult(GetDataIsActive() ? |
| 384 CAPTURE_STARTUP_OK : | 408 CAPTURE_STARTUP_OK : |
| 385 CAPTURE_STARTUP_NO_DATA_CALLBACK); | 409 CAPTURE_STARTUP_NO_DATA_CALLBACK); |
| 410 if (handler_) { | |
| 411 GetDataIsActive() | |
| 412 ? handler_->OnLog(this, "AIC::FirstCheckForNoData => data is active") | |
|
no longer working on chromium
2014/08/25 08:20:05
this does not look like clang format, could you pl
henrika (OOO until Aug 14)
2014/08/25 12:47:44
I did run git cl format and this is what it gives
| |
| 413 : handler_->OnLog(this, | |
| 414 "AIC::FirstCheckForNoData => data is NOT active"); | |
| 415 } | |
| 386 DoCheckForNoData(); | 416 DoCheckForNoData(); |
| 387 } | 417 } |
| 388 | 418 |
| 389 void AudioInputController::DoCheckForNoData() { | 419 void AudioInputController::DoCheckForNoData() { |
| 390 DCHECK(task_runner_->BelongsToCurrentThread()); | 420 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 391 | 421 |
| 392 if (!GetDataIsActive()) { | 422 if (!GetDataIsActive()) { |
| 393 // The data-is-active marker will be false only if it has been more than | 423 // The data-is-active marker will be false only if it has been more than |
| 394 // one second since a data packet was recorded. This can happen if a | 424 // one second since a data packet was recorded. This can happen if a |
| 395 // capture device has been removed or disabled. | 425 // capture device has been removed or disabled. |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 519 silence_state_ = SILENCE_STATE_AUDIO_AND_SILENCE; | 549 silence_state_ = SILENCE_STATE_AUDIO_AND_SILENCE; |
| 520 else | 550 else |
| 521 DCHECK(silence_state_ == SILENCE_STATE_ONLY_AUDIO || | 551 DCHECK(silence_state_ == SILENCE_STATE_ONLY_AUDIO || |
| 522 silence_state_ == SILENCE_STATE_AUDIO_AND_SILENCE); | 552 silence_state_ == SILENCE_STATE_AUDIO_AND_SILENCE); |
| 523 } | 553 } |
| 524 | 554 |
| 525 handler_->OnLog(this, log_string); | 555 handler_->OnLog(this, log_string); |
| 526 #endif | 556 #endif |
| 527 } | 557 } |
| 528 | 558 |
| 559 void AudioInputController::OnStateChange(const std::string state) { | |
| 560 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 561 if (handler_) | |
| 562 handler_->OnLog(this, state); | |
| 563 } | |
| 564 | |
| 529 void AudioInputController::OnError(AudioInputStream* stream) { | 565 void AudioInputController::OnError(AudioInputStream* stream) { |
| 530 // Handle error on the audio-manager thread. | 566 // Handle error on the audio-manager thread. |
| 531 task_runner_->PostTask(FROM_HERE, base::Bind( | 567 task_runner_->PostTask(FROM_HERE, base::Bind( |
| 532 &AudioInputController::DoReportError, this)); | 568 &AudioInputController::DoReportError, this)); |
| 533 } | 569 } |
| 534 | 570 |
| 535 void AudioInputController::DoStopCloseAndClearStream() { | 571 void AudioInputController::DoStopCloseAndClearStream() { |
| 536 DCHECK(task_runner_->BelongsToCurrentThread()); | 572 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 537 | 573 |
| 538 // Allow calling unconditionally and bail if we don't have a stream to close. | 574 // Allow calling unconditionally and bail if we don't have a stream to close. |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 556 | 592 |
| 557 #if defined(AUDIO_POWER_MONITORING) | 593 #if defined(AUDIO_POWER_MONITORING) |
| 558 void AudioInputController::LogSilenceState(SilenceState value) { | 594 void AudioInputController::LogSilenceState(SilenceState value) { |
| 559 UMA_HISTOGRAM_ENUMERATION("Media.AudioInputControllerSessionSilenceReport", | 595 UMA_HISTOGRAM_ENUMERATION("Media.AudioInputControllerSessionSilenceReport", |
| 560 value, | 596 value, |
| 561 SILENCE_STATE_MAX + 1); | 597 SILENCE_STATE_MAX + 1); |
| 562 } | 598 } |
| 563 #endif | 599 #endif |
| 564 | 600 |
| 565 } // namespace media | 601 } // namespace media |
| OLD | NEW |