| 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_io.h" | 5 #include "media/audio/audio_io.h" |
| 6 | 6 |
| 7 #include <windows.h> | 7 #include <windows.h> |
| 8 #include <objbase.h> // This has to be before initguid.h | 8 #include <objbase.h> // This has to be before initguid.h |
| 9 #include <initguid.h> | 9 #include <initguid.h> |
| 10 #include <mmsystem.h> | 10 #include <mmsystem.h> |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 122 // - The entire Windows audio stack was rewritten for Windows Vista and wave | 122 // - The entire Windows audio stack was rewritten for Windows Vista and wave |
| 123 // out performance was degraded compared to XP. | 123 // out performance was degraded compared to XP. |
| 124 // - The regression was fixed in Windows 7 and most configurations will work | 124 // - The regression was fixed in Windows 7 and most configurations will work |
| 125 // with 2, but some (e.g., some Sound Blasters) still need 3. | 125 // with 2, but some (e.g., some Sound Blasters) still need 3. |
| 126 // - Some XP configurations (even multi-processor ones) also need 3. | 126 // - Some XP configurations (even multi-processor ones) also need 3. |
| 127 return (base::win::GetVersion() == base::win::VERSION_VISTA) ? 4 : 3; | 127 return (base::win::GetVersion() == base::win::VERSION_VISTA) ? 4 : 3; |
| 128 } | 128 } |
| 129 | 129 |
| 130 AudioManagerWin::AudioManagerWin(AudioLogFactory* audio_log_factory) | 130 AudioManagerWin::AudioManagerWin(AudioLogFactory* audio_log_factory) |
| 131 : AudioManagerBase(audio_log_factory), | 131 : AudioManagerBase(audio_log_factory), |
| 132 enumeration_type_(kUninitializedEnumeration) { | 132 // |CoreAudioUtil::IsSupported()| uses static variables to avoid doing |
| 133 // multiple initializations. This is however not thread safe. |
| 134 // So, here we call it explicitly before we kick off the audio thread |
| 135 // or do any other work. |
| 136 enumeration_type_(CoreAudioUtil::IsSupported() ? |
| 137 kMMDeviceEnumeration : kWaveEnumeration) { |
| 133 SetMaxOutputStreamsAllowed(kMaxOutputStreams); | 138 SetMaxOutputStreamsAllowed(kMaxOutputStreams); |
| 134 | 139 |
| 135 // WARNING: This is executed on the UI loop, do not add any code here which | 140 // WARNING: This is executed on the UI loop, do not add any code here which |
| 136 // loads libraries or attempts to call out into the OS. Instead add such code | 141 // loads libraries or attempts to call out into the OS. Instead add such code |
| 137 // to the InitializeOnAudioThread() method below. | 142 // to the InitializeOnAudioThread() method below. |
| 138 | 143 |
| 139 // Task must be posted last to avoid races from handing out "this" to the | 144 // Task must be posted last to avoid races from handing out "this" to the |
| 140 // audio thread. | 145 // audio thread. |
| 141 GetTaskRunner()->PostTask(FROM_HERE, base::Bind( | 146 GetTaskRunner()->PostTask(FROM_HERE, base::Bind( |
| 142 &AudioManagerWin::InitializeOnAudioThread, base::Unretained(this))); | 147 &AudioManagerWin::InitializeOnAudioThread, base::Unretained(this))); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 154 return (::waveOutGetNumDevs() != 0); | 159 return (::waveOutGetNumDevs() != 0); |
| 155 } | 160 } |
| 156 | 161 |
| 157 bool AudioManagerWin::HasAudioInputDevices() { | 162 bool AudioManagerWin::HasAudioInputDevices() { |
| 158 return (::waveInGetNumDevs() != 0); | 163 return (::waveInGetNumDevs() != 0); |
| 159 } | 164 } |
| 160 | 165 |
| 161 void AudioManagerWin::InitializeOnAudioThread() { | 166 void AudioManagerWin::InitializeOnAudioThread() { |
| 162 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | 167 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); |
| 163 | 168 |
| 164 if (CoreAudioUtil::IsSupported()) { | 169 if (core_audio_supported()) { |
| 165 // Use the MMDevice API for device enumeration if Vista or higher. | |
| 166 enumeration_type_ = kMMDeviceEnumeration; | |
| 167 | |
| 168 // AudioDeviceListenerWin must be initialized on a COM thread and should | 170 // AudioDeviceListenerWin must be initialized on a COM thread and should |
| 169 // only be used if WASAPI / Core Audio is supported. | 171 // only be used if WASAPI / Core Audio is supported. |
| 170 output_device_listener_.reset(new AudioDeviceListenerWin(BindToCurrentLoop( | 172 output_device_listener_.reset(new AudioDeviceListenerWin(BindToCurrentLoop( |
| 171 base::Bind(&AudioManagerWin::NotifyAllOutputDeviceChangeListeners, | 173 base::Bind(&AudioManagerWin::NotifyAllOutputDeviceChangeListeners, |
| 172 base::Unretained(this))))); | 174 base::Unretained(this))))); |
| 173 } else { | |
| 174 // Use the Wave API for device enumeration if XP or lower. | |
| 175 enumeration_type_ = kWaveEnumeration; | |
| 176 } | 175 } |
| 177 } | 176 } |
| 178 | 177 |
| 179 void AudioManagerWin::ShutdownOnAudioThread() { | 178 void AudioManagerWin::ShutdownOnAudioThread() { |
| 180 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | 179 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); |
| 181 output_device_listener_.reset(); | 180 output_device_listener_.reset(); |
| 182 } | 181 } |
| 183 | 182 |
| 184 base::string16 AudioManagerWin::GetAudioInputDeviceModel() { | 183 base::string16 AudioManagerWin::GetAudioInputDeviceModel() { |
| 185 // Get the default audio capture device and its device interface name. | 184 // Get the default audio capture device and its device interface name. |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 241 if (device_found) | 240 if (device_found) |
| 242 return GetDeviceAndDriverInfo(device_info, &device_data); | 241 return GetDeviceAndDriverInfo(device_info, &device_data); |
| 243 } | 242 } |
| 244 | 243 |
| 245 return base::string16(); | 244 return base::string16(); |
| 246 } | 245 } |
| 247 | 246 |
| 248 void AudioManagerWin::ShowAudioInputSettings() { | 247 void AudioManagerWin::ShowAudioInputSettings() { |
| 249 std::wstring program; | 248 std::wstring program; |
| 250 std::string argument; | 249 std::string argument; |
| 251 if (!CoreAudioUtil::IsSupported()) { | 250 if (!core_audio_supported()) { |
| 252 program = L"sndvol32.exe"; | 251 program = L"sndvol32.exe"; |
| 253 argument = "-R"; | 252 argument = "-R"; |
| 254 } else { | 253 } else { |
| 255 program = L"control.exe"; | 254 program = L"control.exe"; |
| 256 argument = "mmsys.cpl,,1"; | 255 argument = "mmsys.cpl,,1"; |
| 257 } | 256 } |
| 258 | 257 |
| 259 base::FilePath path; | 258 base::FilePath path; |
| 260 PathService::Get(base::DIR_SYSTEM, &path); | 259 PathService::Get(base::DIR_SYSTEM, &path); |
| 261 path = path.Append(program); | 260 path = path.Append(program); |
| 262 CommandLine command_line(path); | 261 CommandLine command_line(path); |
| 263 command_line.AppendArg(argument); | 262 command_line.AppendArg(argument); |
| 264 base::LaunchProcess(command_line, base::LaunchOptions(), NULL); | 263 base::LaunchProcess(command_line, base::LaunchOptions(), NULL); |
| 265 } | 264 } |
| 266 | 265 |
| 267 void AudioManagerWin::GetAudioDeviceNamesImpl( | 266 void AudioManagerWin::GetAudioDeviceNamesImpl( |
| 268 bool input, | 267 bool input, |
| 269 AudioDeviceNames* device_names) { | 268 AudioDeviceNames* device_names) { |
| 270 DCHECK(device_names->empty()); | 269 DCHECK(device_names->empty()); |
| 271 DCHECK(enumeration_type() != kUninitializedEnumeration); | |
| 272 // Enumerate all active audio-endpoint capture devices. | 270 // Enumerate all active audio-endpoint capture devices. |
| 273 if (enumeration_type() == kWaveEnumeration) { | 271 if (enumeration_type() == kWaveEnumeration) { |
| 274 // Utilize the Wave API for Windows XP. | 272 // Utilize the Wave API for Windows XP. |
| 275 if (input) | 273 if (input) |
| 276 GetInputDeviceNamesWinXP(device_names); | 274 GetInputDeviceNamesWinXP(device_names); |
| 277 else | 275 else |
| 278 GetOutputDeviceNamesWinXP(device_names); | 276 GetOutputDeviceNamesWinXP(device_names); |
| 279 } else { | 277 } else { |
| 280 // Utilize the MMDevice API (part of Core Audio) for Vista and higher. | 278 // Utilize the MMDevice API (part of Core Audio) for Vista and higher. |
| 281 if (input) | 279 if (input) |
| (...skipping 15 matching lines...) Expand all Loading... |
| 297 GetAudioDeviceNamesImpl(true, device_names); | 295 GetAudioDeviceNamesImpl(true, device_names); |
| 298 } | 296 } |
| 299 | 297 |
| 300 void AudioManagerWin::GetAudioOutputDeviceNames( | 298 void AudioManagerWin::GetAudioOutputDeviceNames( |
| 301 AudioDeviceNames* device_names) { | 299 AudioDeviceNames* device_names) { |
| 302 GetAudioDeviceNamesImpl(false, device_names); | 300 GetAudioDeviceNamesImpl(false, device_names); |
| 303 } | 301 } |
| 304 | 302 |
| 305 AudioParameters AudioManagerWin::GetInputStreamParameters( | 303 AudioParameters AudioManagerWin::GetInputStreamParameters( |
| 306 const std::string& device_id) { | 304 const std::string& device_id) { |
| 307 int sample_rate = 48000; | 305 if (!core_audio_supported()) { |
| 308 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; | 306 return AudioParameters( |
| 309 if (CoreAudioUtil::IsSupported()) { | 307 AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO, 0, 48000, |
| 310 int hw_sample_rate = WASAPIAudioInputStream::HardwareSampleRate(device_id); | 308 16, kFallbackBufferSize, AudioParameters::NO_EFFECTS); |
| 311 if (hw_sample_rate) | |
| 312 sample_rate = hw_sample_rate; | |
| 313 channel_layout = | |
| 314 WASAPIAudioInputStream::HardwareChannelCount(device_id) == 1 ? | |
| 315 CHANNEL_LAYOUT_MONO : CHANNEL_LAYOUT_STEREO; | |
| 316 } | 309 } |
| 317 | 310 |
| 318 // TODO(Henrika): improve the default buffer size value for input stream. | 311 return WASAPIAudioInputStream::GetInputStreamParameters(device_id); |
| 319 return AudioParameters( | |
| 320 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, | |
| 321 sample_rate, 16, kFallbackBufferSize); | |
| 322 } | 312 } |
| 323 | 313 |
| 324 std::string AudioManagerWin::GetAssociatedOutputDeviceID( | 314 std::string AudioManagerWin::GetAssociatedOutputDeviceID( |
| 325 const std::string& input_device_id) { | 315 const std::string& input_device_id) { |
| 326 if (!CoreAudioUtil::IsSupported()) { | 316 if (!core_audio_supported()) { |
| 327 NOTIMPLEMENTED() | 317 NOTIMPLEMENTED() |
| 328 << "GetAssociatedOutputDeviceID is not supported on this OS"; | 318 << "GetAssociatedOutputDeviceID is not supported on this OS"; |
| 329 return std::string(); | 319 return std::string(); |
| 330 } | 320 } |
| 331 return CoreAudioUtil::GetMatchingOutputDeviceID(input_device_id); | 321 return CoreAudioUtil::GetMatchingOutputDeviceID(input_device_id); |
| 332 } | 322 } |
| 333 | 323 |
| 334 // Factory for the implementations of AudioOutputStream for AUDIO_PCM_LINEAR | 324 // Factory for the implementations of AudioOutputStream for AUDIO_PCM_LINEAR |
| 335 // mode. | 325 // mode. |
| 336 // - PCMWaveOutAudioOutputStream: Based on the waveOut API. | 326 // - PCMWaveOutAudioOutputStream: Based on the waveOut API. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 352 // - PCMWaveOutAudioOutputStream: Based on the waveOut API. | 342 // - PCMWaveOutAudioOutputStream: Based on the waveOut API. |
| 353 // - WASAPIAudioOutputStream: Based on Core Audio (WASAPI) API. | 343 // - WASAPIAudioOutputStream: Based on Core Audio (WASAPI) API. |
| 354 AudioOutputStream* AudioManagerWin::MakeLowLatencyOutputStream( | 344 AudioOutputStream* AudioManagerWin::MakeLowLatencyOutputStream( |
| 355 const AudioParameters& params, | 345 const AudioParameters& params, |
| 356 const std::string& device_id, | 346 const std::string& device_id, |
| 357 const std::string& input_device_id) { | 347 const std::string& input_device_id) { |
| 358 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); | 348 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); |
| 359 if (params.channels() > kWinMaxChannels) | 349 if (params.channels() > kWinMaxChannels) |
| 360 return NULL; | 350 return NULL; |
| 361 | 351 |
| 362 if (!CoreAudioUtil::IsSupported()) { | 352 if (!core_audio_supported()) { |
| 363 // Fall back to Windows Wave implementation on Windows XP or lower. | 353 // Fall back to Windows Wave implementation on Windows XP or lower. |
| 364 DLOG_IF(ERROR, !device_id.empty() && | 354 DLOG_IF(ERROR, !device_id.empty() && |
| 365 device_id != AudioManagerBase::kDefaultDeviceId) | 355 device_id != AudioManagerBase::kDefaultDeviceId) |
| 366 << "Opening by device id not supported by PCMWaveOutAudioOutputStream"; | 356 << "Opening by device id not supported by PCMWaveOutAudioOutputStream"; |
| 367 DVLOG(1) << "Using WaveOut since WASAPI requires at least Vista."; | 357 DVLOG(1) << "Using WaveOut since WASAPI requires at least Vista."; |
| 368 return new PCMWaveOutAudioOutputStream( | 358 return new PCMWaveOutAudioOutputStream( |
| 369 this, params, NumberOfWaveOutBuffers(), WAVE_MAPPER); | 359 this, params, NumberOfWaveOutBuffers(), WAVE_MAPPER); |
| 370 } | 360 } |
| 371 | 361 |
| 372 // TODO(rtoy): support more than stereo input. | 362 // TODO(rtoy): support more than stereo input. |
| (...skipping 20 matching lines...) Expand all Loading... |
| 393 const AudioParameters& params, const std::string& device_id) { | 383 const AudioParameters& params, const std::string& device_id) { |
| 394 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); | 384 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); |
| 395 return CreatePCMWaveInAudioInputStream(params, device_id); | 385 return CreatePCMWaveInAudioInputStream(params, device_id); |
| 396 } | 386 } |
| 397 | 387 |
| 398 // Factory for the implementations of AudioInputStream for | 388 // Factory for the implementations of AudioInputStream for |
| 399 // AUDIO_PCM_LOW_LATENCY mode. | 389 // AUDIO_PCM_LOW_LATENCY mode. |
| 400 AudioInputStream* AudioManagerWin::MakeLowLatencyInputStream( | 390 AudioInputStream* AudioManagerWin::MakeLowLatencyInputStream( |
| 401 const AudioParameters& params, const std::string& device_id) { | 391 const AudioParameters& params, const std::string& device_id) { |
| 402 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); | 392 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); |
| 393 DVLOG(1) << "MakeLowLatencyInputStream: " << device_id; |
| 403 AudioInputStream* stream = NULL; | 394 AudioInputStream* stream = NULL; |
| 404 if (!CoreAudioUtil::IsSupported()) { | 395 if (!core_audio_supported()) { |
| 405 // Fall back to Windows Wave implementation on Windows XP or lower. | 396 // Fall back to Windows Wave implementation on Windows XP or lower. |
| 406 DVLOG(1) << "Using WaveIn since WASAPI requires at least Vista."; | 397 DVLOG(1) << "Using WaveIn since WASAPI requires at least Vista."; |
| 407 stream = CreatePCMWaveInAudioInputStream(params, device_id); | 398 stream = CreatePCMWaveInAudioInputStream(params, device_id); |
| 408 } else { | 399 } else { |
| 409 stream = new WASAPIAudioInputStream(this, params, device_id); | 400 stream = new WASAPIAudioInputStream(this, params, device_id); |
| 410 } | 401 } |
| 411 | 402 |
| 412 return stream; | 403 return stream; |
| 413 } | 404 } |
| 414 | 405 |
| 415 std::string AudioManagerWin::GetDefaultOutputDeviceID() { | 406 std::string AudioManagerWin::GetDefaultOutputDeviceID() { |
| 416 if (!CoreAudioUtil::IsSupported()) | 407 if (!core_audio_supported()) |
| 417 return std::string(); | 408 return std::string(); |
| 418 return CoreAudioUtil::GetDefaultOutputDeviceID(); | 409 return CoreAudioUtil::GetDefaultOutputDeviceID(); |
| 419 } | 410 } |
| 420 | 411 |
| 421 AudioParameters AudioManagerWin::GetPreferredOutputStreamParameters( | 412 AudioParameters AudioManagerWin::GetPreferredOutputStreamParameters( |
| 422 const std::string& output_device_id, | 413 const std::string& output_device_id, |
| 423 const AudioParameters& input_params) { | 414 const AudioParameters& input_params) { |
| 424 const bool core_audio_supported = CoreAudioUtil::IsSupported(); | 415 DLOG_IF(ERROR, !core_audio_supported() && !output_device_id.empty()) |
| 425 DLOG_IF(ERROR, !core_audio_supported && !output_device_id.empty()) | |
| 426 << "CoreAudio is required to open non-default devices."; | 416 << "CoreAudio is required to open non-default devices."; |
| 427 | 417 |
| 428 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); | 418 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); |
| 429 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; | 419 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; |
| 430 int sample_rate = 48000; | 420 int sample_rate = 48000; |
| 431 int buffer_size = kFallbackBufferSize; | 421 int buffer_size = kFallbackBufferSize; |
| 432 int bits_per_sample = 16; | 422 int bits_per_sample = 16; |
| 433 int input_channels = 0; | 423 int input_channels = 0; |
| 434 bool use_input_params = !core_audio_supported; | 424 bool use_input_params = !core_audio_supported(); |
| 435 if (core_audio_supported) { | 425 if (core_audio_supported()) { |
| 436 if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio)) { | 426 if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio)) { |
| 437 // TODO(rtoy): tune these values for best possible WebAudio | 427 // TODO(rtoy): tune these values for best possible WebAudio |
| 438 // performance. WebRTC works well at 48kHz and a buffer size of 480 | 428 // performance. WebRTC works well at 48kHz and a buffer size of 480 |
| 439 // samples will be used for this case. Note that exclusive mode is | 429 // samples will be used for this case. Note that exclusive mode is |
| 440 // experimental. This sample rate will be combined with a buffer size of | 430 // experimental. This sample rate will be combined with a buffer size of |
| 441 // 256 samples, which corresponds to an output delay of ~5.33ms. | 431 // 256 samples, which corresponds to an output delay of ~5.33ms. |
| 442 sample_rate = 48000; | 432 sample_rate = 48000; |
| 443 buffer_size = 256; | 433 buffer_size = 256; |
| 444 if (input_params.IsValid()) | 434 if (input_params.IsValid()) |
| 445 channel_layout = input_params.channel_layout(); | 435 channel_layout = input_params.channel_layout(); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 457 } else { | 447 } else { |
| 458 use_input_params = true; | 448 use_input_params = true; |
| 459 } | 449 } |
| 460 } | 450 } |
| 461 } | 451 } |
| 462 | 452 |
| 463 if (input_params.IsValid()) { | 453 if (input_params.IsValid()) { |
| 464 // If the user has enabled checking supported channel layouts or we don't | 454 // If the user has enabled checking supported channel layouts or we don't |
| 465 // have a valid channel layout yet, try to use the input layout. See bugs | 455 // have a valid channel layout yet, try to use the input layout. See bugs |
| 466 // http://crbug.com/259165 and http://crbug.com/311906 for more details. | 456 // http://crbug.com/259165 and http://crbug.com/311906 for more details. |
| 467 if (core_audio_supported && | 457 if (core_audio_supported() && |
| 468 (cmd_line->HasSwitch(switches::kTrySupportedChannelLayouts) || | 458 (cmd_line->HasSwitch(switches::kTrySupportedChannelLayouts) || |
| 469 channel_layout == CHANNEL_LAYOUT_UNSUPPORTED)) { | 459 channel_layout == CHANNEL_LAYOUT_UNSUPPORTED)) { |
| 470 // Check if it is possible to open up at the specified input channel | 460 // Check if it is possible to open up at the specified input channel |
| 471 // layout but avoid checking if the specified layout is the same as the | 461 // layout but avoid checking if the specified layout is the same as the |
| 472 // hardware (preferred) layout. We do this extra check to avoid the | 462 // hardware (preferred) layout. We do this extra check to avoid the |
| 473 // CoreAudioUtil::IsChannelLayoutSupported() overhead in most cases. | 463 // CoreAudioUtil::IsChannelLayoutSupported() overhead in most cases. |
| 474 if (input_params.channel_layout() != channel_layout) { | 464 if (input_params.channel_layout() != channel_layout) { |
| 475 // TODO(henrika): Internally, IsChannelLayoutSupported does many of the | 465 // TODO(henrika): Internally, IsChannelLayoutSupported does many of the |
| 476 // operations that have already been done such as opening up a client | 466 // operations that have already been done such as opening up a client |
| 477 // and fetching the WAVEFORMATPCMEX format. Ideally we should only do | 467 // and fetching the WAVEFORMATPCMEX format. Ideally we should only do |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 528 return new PCMWaveInAudioInputStream(this, params, kNumInputBuffers, | 518 return new PCMWaveInAudioInputStream(this, params, kNumInputBuffers, |
| 529 xp_device_id); | 519 xp_device_id); |
| 530 } | 520 } |
| 531 | 521 |
| 532 /// static | 522 /// static |
| 533 AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory) { | 523 AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory) { |
| 534 return new AudioManagerWin(audio_log_factory); | 524 return new AudioManagerWin(audio_log_factory); |
| 535 } | 525 } |
| 536 | 526 |
| 537 } // namespace media | 527 } // namespace media |
| OLD | NEW |