| 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/mac/audio_manager_mac.h" | 5 #include "media/audio/mac/audio_manager_mac.h" |
| 6 | 6 |
| 7 #include <CoreAudio/AudioHardware.h> | 7 #include <CoreAudio/AudioHardware.h> |
| 8 #include <string> | 8 #include <string> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 421 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 432 GetAudioDeviceInfo(false, device_names); | 432 GetAudioDeviceInfo(false, device_names); |
| 433 } | 433 } |
| 434 | 434 |
| 435 AudioParameters AudioManagerMac::GetInputStreamParameters( | 435 AudioParameters AudioManagerMac::GetInputStreamParameters( |
| 436 const std::string& device_id) { | 436 const std::string& device_id) { |
| 437 AudioDeviceID device = GetAudioDeviceIdByUId(true, device_id); | 437 AudioDeviceID device = GetAudioDeviceIdByUId(true, device_id); |
| 438 if (device == kAudioObjectUnknown) { | 438 if (device == kAudioObjectUnknown) { |
| 439 DLOG(ERROR) << "Invalid device " << device_id; | 439 DLOG(ERROR) << "Invalid device " << device_id; |
| 440 return AudioParameters( | 440 return AudioParameters( |
| 441 AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, | 441 AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, |
| 442 kFallbackSampleRate, 16, ChooseBufferSize(kFallbackSampleRate)); | 442 kFallbackSampleRate, 16, ChooseBufferSize(true, kFallbackSampleRate)); |
| 443 } | 443 } |
| 444 | 444 |
| 445 int channels = 0; | 445 int channels = 0; |
| 446 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; | 446 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; |
| 447 if (GetDeviceChannels(device, kAudioDevicePropertyScopeInput, &channels) && | 447 if (GetDeviceChannels(device, kAudioDevicePropertyScopeInput, &channels) && |
| 448 channels <= 2) { | 448 channels <= 2) { |
| 449 channel_layout = GuessChannelLayout(channels); | 449 channel_layout = GuessChannelLayout(channels); |
| 450 } else { | 450 } else { |
| 451 DLOG(ERROR) << "Failed to get the device channels, use stereo as default " | 451 DLOG(ERROR) << "Failed to get the device channels, use stereo as default " |
| 452 << "for device " << device_id; | 452 << "for device " << device_id; |
| 453 } | 453 } |
| 454 | 454 |
| 455 int sample_rate = HardwareSampleRateForDevice(device); | 455 int sample_rate = HardwareSampleRateForDevice(device); |
| 456 if (!sample_rate) | 456 if (!sample_rate) |
| 457 sample_rate = kFallbackSampleRate; | 457 sample_rate = kFallbackSampleRate; |
| 458 | 458 |
| 459 // Due to the sharing of the input and output buffer sizes, we need to choose | 459 // Due to the sharing of the input and output buffer sizes, we need to choose |
| 460 // the input buffer size based on the output sample rate. See | 460 // the input buffer size based on the output sample rate. See |
| 461 // http://crbug.com/154352. | 461 // http://crbug.com/154352. |
| 462 const int buffer_size = ChooseBufferSize(sample_rate); | 462 const int buffer_size = ChooseBufferSize(true, sample_rate); |
| 463 | 463 |
| 464 // TODO(xians): query the native channel layout for the specific device. | 464 // TODO(xians): query the native channel layout for the specific device. |
| 465 return AudioParameters( | 465 return AudioParameters( |
| 466 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, | 466 AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, |
| 467 sample_rate, 16, buffer_size); | 467 sample_rate, 16, buffer_size); |
| 468 } | 468 } |
| 469 | 469 |
| 470 std::string AudioManagerMac::GetAssociatedOutputDeviceID( | 470 std::string AudioManagerMac::GetAssociatedOutputDeviceID( |
| 471 const std::string& input_device_id) { | 471 const std::string& input_device_id) { |
| 472 AudioDeviceID device = GetAudioDeviceIdByUId(true, input_device_id); | 472 AudioDeviceID device = GetAudioDeviceIdByUId(true, input_device_id); |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 633 } | 633 } |
| 634 | 634 |
| 635 AudioParameters AudioManagerMac::GetPreferredOutputStreamParameters( | 635 AudioParameters AudioManagerMac::GetPreferredOutputStreamParameters( |
| 636 const std::string& output_device_id, | 636 const std::string& output_device_id, |
| 637 const AudioParameters& input_params) { | 637 const AudioParameters& input_params) { |
| 638 const AudioDeviceID device = GetAudioDeviceIdByUId(false, output_device_id); | 638 const AudioDeviceID device = GetAudioDeviceIdByUId(false, output_device_id); |
| 639 if (device == kAudioObjectUnknown) { | 639 if (device == kAudioObjectUnknown) { |
| 640 DLOG(ERROR) << "Invalid output device " << output_device_id; | 640 DLOG(ERROR) << "Invalid output device " << output_device_id; |
| 641 return input_params.IsValid() ? input_params : AudioParameters( | 641 return input_params.IsValid() ? input_params : AudioParameters( |
| 642 AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, | 642 AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, |
| 643 kFallbackSampleRate, 16, ChooseBufferSize(kFallbackSampleRate)); | 643 kFallbackSampleRate, 16, ChooseBufferSize(false, kFallbackSampleRate)); |
| 644 } | 644 } |
| 645 | 645 |
| 646 const bool has_valid_input_params = input_params.IsValid(); | 646 const bool has_valid_input_params = input_params.IsValid(); |
| 647 const int hardware_sample_rate = HardwareSampleRateForDevice(device); | 647 const int hardware_sample_rate = HardwareSampleRateForDevice(device); |
| 648 | 648 |
| 649 // Allow pass through buffer sizes. If concurrent input and output streams | 649 // Allow pass through buffer sizes. If concurrent input and output streams |
| 650 // exist, they will use the smallest buffer size amongst them. As such, each | 650 // exist, they will use the smallest buffer size amongst them. As such, each |
| 651 // stream must be able to FIFO requests appropriately when this happens. | 651 // stream must be able to FIFO requests appropriately when this happens. |
| 652 int buffer_size = ChooseBufferSize(hardware_sample_rate); | 652 int buffer_size = ChooseBufferSize(false, hardware_sample_rate); |
| 653 if (has_valid_input_params) { | 653 if (has_valid_input_params) { |
| 654 buffer_size = | 654 buffer_size = |
| 655 std::min(kMaximumInputOutputBufferSize, | 655 std::min(kMaximumInputOutputBufferSize, |
| 656 std::max(input_params.frames_per_buffer(), buffer_size)); | 656 std::max(input_params.frames_per_buffer(), buffer_size)); |
| 657 } | 657 } |
| 658 | 658 |
| 659 int hardware_channels; | 659 int hardware_channels; |
| 660 if (!GetDeviceChannels(device, kAudioDevicePropertyScopeOutput, | 660 if (!GetDeviceChannels(device, kAudioDevicePropertyScopeOutput, |
| 661 &hardware_channels)) { | 661 &hardware_channels)) { |
| 662 hardware_channels = 2; | 662 hardware_channels = 2; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 710 | 710 |
| 711 if (current_sample_rate_ == new_sample_rate && | 711 if (current_sample_rate_ == new_sample_rate && |
| 712 current_output_device_ == new_output_device) | 712 current_output_device_ == new_output_device) |
| 713 return; | 713 return; |
| 714 | 714 |
| 715 current_sample_rate_ = new_sample_rate; | 715 current_sample_rate_ = new_sample_rate; |
| 716 current_output_device_ = new_output_device; | 716 current_output_device_ = new_output_device; |
| 717 NotifyAllOutputDeviceChangeListeners(); | 717 NotifyAllOutputDeviceChangeListeners(); |
| 718 } | 718 } |
| 719 | 719 |
| 720 int AudioManagerMac::ChooseBufferSize(int output_sample_rate) { | 720 int AudioManagerMac::ChooseBufferSize(bool is_input, int sample_rate) { |
| 721 int buffer_size = kMinimumInputOutputBufferSize; | 721 // kMinimumInputOutputBufferSize is too small for the output side because |
| 722 // CoreAudio can get into under-run if the renderer fails delivering data |
| 723 // to the browser within the allowed time by the OS. The workaround is to |
| 724 // use 256 samples as the default output buffer size for sample rates |
| 725 // smaller than 96KHz. |
| 726 // TODO(xians): Remove this workaround after WebAudio supports user defined |
| 727 // buffer size. See https://github.com/WebAudio/web-audio-api/issues/348 |
| 728 // for details. |
| 729 int buffer_size = is_input ? |
| 730 kMinimumInputOutputBufferSize : 2 * kMinimumInputOutputBufferSize; |
| 722 const int user_buffer_size = GetUserBufferSize(); | 731 const int user_buffer_size = GetUserBufferSize(); |
| 723 if (user_buffer_size) { | 732 if (user_buffer_size) { |
| 724 buffer_size = user_buffer_size; | 733 buffer_size = user_buffer_size; |
| 725 } else if (output_sample_rate > 48000) { | 734 } else if (sample_rate > 48000) { |
| 726 // The default buffer size is too small for higher sample rates and may lead | 735 // The default buffer size is too small for higher sample rates and may lead |
| 727 // to glitching. Adjust upwards by multiples of the default size. | 736 // to glitching. Adjust upwards by multiples of the default size. |
| 728 if (output_sample_rate <= 96000) | 737 if (sample_rate <= 96000) |
| 729 buffer_size = 2 * kMinimumInputOutputBufferSize; | 738 buffer_size = 2 * kMinimumInputOutputBufferSize; |
| 730 else if (output_sample_rate <= 192000) | 739 else if (sample_rate <= 192000) |
| 731 buffer_size = 4 * kMinimumInputOutputBufferSize; | 740 buffer_size = 4 * kMinimumInputOutputBufferSize; |
| 732 } | 741 } |
| 733 | 742 |
| 734 return buffer_size; | 743 return buffer_size; |
| 735 } | 744 } |
| 736 | 745 |
| 737 bool AudioManagerMac::ShouldDeferStreamStart() { | 746 bool AudioManagerMac::ShouldDeferStreamStart() { |
| 738 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); | 747 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); |
| 739 return power_observer_->ShouldDeferStreamStart(); | 748 return power_observer_->ShouldDeferStreamStart(); |
| 740 } | 749 } |
| 741 | 750 |
| 742 void AudioManagerMac::ReleaseOutputStream(AudioOutputStream* stream) { | 751 void AudioManagerMac::ReleaseOutputStream(AudioOutputStream* stream) { |
| 743 output_streams_.remove(stream); | 752 output_streams_.remove(stream); |
| 744 AudioManagerBase::ReleaseOutputStream(stream); | 753 AudioManagerBase::ReleaseOutputStream(stream); |
| 745 } | 754 } |
| 746 | 755 |
| 747 void AudioManagerMac::ReleaseInputStream(AudioInputStream* stream) { | 756 void AudioManagerMac::ReleaseInputStream(AudioInputStream* stream) { |
| 748 input_streams_.remove(stream); | 757 input_streams_.remove(stream); |
| 749 AudioManagerBase::ReleaseInputStream(stream); | 758 AudioManagerBase::ReleaseInputStream(stream); |
| 750 } | 759 } |
| 751 | 760 |
| 752 AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory) { | 761 AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory) { |
| 753 return new AudioManagerMac(audio_log_factory); | 762 return new AudioManagerMac(audio_log_factory); |
| 754 } | 763 } |
| 755 | 764 |
| 756 } // namespace media | 765 } // namespace media |
| OLD | NEW |