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/mac/audio_manager_mac.h" | 5 #include "media/audio/mac/audio_manager_mac.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <algorithm> |
| 8 #include <vector> | |
| 8 | 9 |
| 9 #include "base/bind.h" | 10 #include "base/bind.h" |
| 10 #include "base/command_line.h" | 11 #include "base/command_line.h" |
| 11 #include "base/mac/mac_logging.h" | 12 #include "base/mac/mac_logging.h" |
| 12 #include "base/mac/scoped_cftyperef.h" | 13 #include "base/mac/scoped_cftyperef.h" |
| 13 #include "base/macros.h" | 14 #include "base/macros.h" |
| 14 #include "base/memory/free_deleter.h" | 15 #include "base/memory/free_deleter.h" |
| 15 #include "base/power_monitor/power_monitor.h" | 16 #include "base/power_monitor/power_monitor.h" |
| 16 #include "base/power_monitor/power_observer.h" | 17 #include "base/power_monitor/power_observer.h" |
| 17 #include "base/strings/sys_string_conversions.h" | 18 #include "base/strings/sys_string_conversions.h" |
| (...skipping 836 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 854 // see if the size can actually be changed. If there is any other active | 855 // see if the size can actually be changed. If there is any other active |
| 855 // streams on the same device, either input or output, a larger size than | 856 // streams on the same device, either input or output, a larger size than |
| 856 // their requested buffer size can't be set. The reason is that an existing | 857 // their requested buffer size can't be set. The reason is that an existing |
| 857 // stream can't handle buffer size larger than its requested buffer size. | 858 // stream can't handle buffer size larger than its requested buffer size. |
| 858 // See http://crbug.com/428706 for a reason why. | 859 // See http://crbug.com/428706 for a reason why. |
| 859 | 860 |
| 860 if (buffer_size == desired_buffer_size) | 861 if (buffer_size == desired_buffer_size) |
| 861 return true; | 862 return true; |
| 862 | 863 |
| 863 if (desired_buffer_size > buffer_size) { | 864 if (desired_buffer_size > buffer_size) { |
| 864 // Do NOT set the buffer size if there is another output stream using | 865 // Do NOT set the buffer size if there is another output stream using |
|
o1ka
2016/04/22 12:24:24
May we probably skip those checks when called from
henrika (OOO until Aug 14)
2016/04/25 13:54:13
Latest implementation only calls it once for all s
o1ka
2016/04/25 15:13:26
Acknowledged.
| |
| 865 // the same device with a smaller requested buffer size. | 866 // the same device with a smaller requested buffer size. |
| 866 // Note, for the caller stream, its requested_buffer_size() will be the same | 867 // Note, for the caller stream, its requested_buffer_size() will be the same |
| 867 // as |desired_buffer_size|, so it won't return true due to comparing with | 868 // as |desired_buffer_size|, so it won't return true due to comparing with |
| 868 // itself. | 869 // itself. |
| 869 for (auto* stream : output_streams_) { | 870 for (auto* stream : output_streams_) { |
| 870 if (stream->device_id() == device_id && | 871 if (stream->device_id() == device_id && |
| 871 stream->requested_buffer_size() < desired_buffer_size) { | 872 stream->requested_buffer_size() < desired_buffer_size) { |
| 872 return true; | 873 return true; |
| 873 } | 874 } |
| 874 } | 875 } |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 910 << "AudioUnitSetProperty(kAudioDevicePropertyBufferFrameSize) failed. " | 911 << "AudioUnitSetProperty(kAudioDevicePropertyBufferFrameSize) failed. " |
| 911 << "Size:: " << buffer_size; | 912 << "Size:: " << buffer_size; |
| 912 *size_was_changed = (result == noErr); | 913 *size_was_changed = (result == noErr); |
| 913 DVLOG_IF(1, result == noErr) << "IO buffer size changed to: " << buffer_size; | 914 DVLOG_IF(1, result == noErr) << "IO buffer size changed to: " << buffer_size; |
| 914 // Store the currently used (after a change) I/O buffer frame size. | 915 // Store the currently used (after a change) I/O buffer frame size. |
| 915 *io_buffer_frame_size = buffer_size; | 916 *io_buffer_frame_size = buffer_size; |
| 916 | 917 |
| 917 return (result == noErr); | 918 return (result == noErr); |
| 918 } | 919 } |
| 919 | 920 |
| 921 #if !defined(NDEBUG) | |
| 922 void AudioManagerMac::PrintOutputBufferSizes() { | |
| 923 for (auto* stream : output_streams_) { | |
| 924 DVLOG(1) << "[id=0x" << std::hex << stream->device_id() << "] " << std::dec | |
| 925 << "requested: " << stream->requested_buffer_size() << ", " | |
| 926 << "actual: " << stream->actual_buffer_size(); | |
| 927 } | |
| 928 } | |
| 929 #endif // !defined(NDEBUG) | |
| 930 | |
| 931 bool AudioManagerMac::IncreaseIOBufferSizeIfPossible(AudioDeviceID device_id) { | |
|
o1ka
2016/04/22 12:24:24
Add a thread check for clarity?
henrika (OOO until Aug 14)
2016/04/25 13:54:13
Done.
| |
| 932 DVLOG(1) << "IncreaseIOBufferSizeIfPossible(id=0x" << std::hex << device_id | |
| 933 << ")"; | |
| 934 // Build a map of buffer sizes [requested, actual] from all existing output | |
| 935 // audio streams using the specified |device_id|. | |
| 936 std::map<size_t, size_t> size_map; | |
| 937 std::list<AUHALStream*> output_streams; | |
| 938 for (auto* stream : output_streams_) { | |
| 939 if (stream->device_id() == device_id) { | |
| 940 size_map[stream->requested_buffer_size()] = stream->actual_buffer_size(); | |
|
o1ka
2016/04/22 12:24:24
Shouldn't it be that all the streams have the same
henrika (OOO until Aug 14)
2016/04/25 13:54:13
Now changed.
| |
| 941 output_streams.push_back(stream); | |
| 942 } | |
| 943 } | |
| 944 | |
| 945 if (size_map.empty()) { | |
| 946 DVLOG(1) << "No action since there is no active stream for given device id"; | |
| 947 return false; | |
| 948 } | |
| 949 | |
| 950 // The elements are sorted according to the key object which is the | |
| 951 // requested buffer size in this case. The associated value is the actual | |
| 952 // buffer size and if these are equal for the first pair in the lists it means | |
| 953 // that we are already using the lowest possible buffer size. Hence, it is not | |
| 954 // possible to do any increase. | |
| 955 if (size_map.begin()->first == size_map.begin()->second) { | |
| 956 DVLOG(1) << "No action since lowest possible size is already in use: " | |
| 957 << size_map.begin()->first; | |
| 958 return false; | |
| 959 } | |
| 960 | |
| 961 // Add a handy log message to track the current status before trying to make | |
| 962 // a change. | |
| 963 for (auto it = size_map.begin(); it != size_map.end(); ++it) { | |
| 964 DVLOG(1) << "requested:" << it->first << " actual: " << it->second; | |
| 965 } | |
| 966 | |
| 967 // First pair in the map now contains the lowest requested buffer size that | |
| 968 // is not yet in use since another stream required a smaller value. It should | |
| 969 // now be safe to increase the I/O buffer size to this new (higher) value. | |
| 970 // Doing so will save system resources. | |
| 971 const size_t increased_io_buffer_frame_size = size_map.begin()->first; | |
| 972 | |
| 973 bool size_was_changed = false; | |
| 974 size_t io_buffer_frame_size = 0; | |
| 975 bool result = false; | |
| 976 for (auto* stream : output_streams) { | |
| 977 result = MaybeChangeBufferSize(device_id, stream->audio_unit(), 0, | |
| 978 increased_io_buffer_frame_size, | |
| 979 &size_was_changed, &io_buffer_frame_size); | |
| 980 DCHECK(size_was_changed); | |
| 981 DCHECK_EQ(io_buffer_frame_size, increased_io_buffer_frame_size); | |
| 982 } | |
| 983 | |
| 984 return true; | |
| 985 } | |
| 986 | |
| 987 bool AudioManagerMac::AudioDeviceIsUsedForInput(AudioDeviceID device_id) { | |
| 988 if (!basic_input_streams_.empty()) { | |
| 989 // For Audio Queues and in the default case (Mac OS X), the audio comes | |
| 990 // from the system’s default audio input device as set by a user in System | |
| 991 // Preferences. | |
| 992 AudioDeviceID default_id; | |
| 993 GetDefaultDevice(&default_id, true); | |
| 994 if (default_id == device_id) | |
| 995 return true; | |
| 996 } | |
| 997 | |
| 998 // Each low latency streams has its own device ID. | |
| 999 for (auto* stream : low_latency_input_streams_) { | |
| 1000 if (stream->device_id() == device_id) | |
| 1001 return true; | |
| 1002 } | |
| 1003 return false; | |
| 1004 } | |
| 1005 | |
| 920 void AudioManagerMac::ReleaseOutputStream(AudioOutputStream* stream) { | 1006 void AudioManagerMac::ReleaseOutputStream(AudioOutputStream* stream) { |
|
o1ka
2016/04/22 12:24:24
I assume it can't race with MakeLowLatencyOutputSt
henrika (OOO until Aug 14)
2016/04/25 13:54:13
Added thread checks.
| |
| 1007 const AudioDeviceID id = static_cast<AUHALStream*>(stream)->device_id(); | |
| 1008 DVLOG(1) << "Closing down output stream with id=0x" << std::hex << id; | |
| 1009 | |
| 1010 // Start by closing down the specified output stream. | |
| 921 output_streams_.remove(static_cast<AUHALStream*>(stream)); | 1011 output_streams_.remove(static_cast<AUHALStream*>(stream)); |
| 1012 #if !defined(NDEBUG) | |
| 1013 PrintOutputBufferSizes(); | |
| 1014 #endif // !defined(NDEBUG) | |
| 922 AudioManagerBase::ReleaseOutputStream(stream); | 1015 AudioManagerBase::ReleaseOutputStream(stream); |
| 1016 | |
| 1017 // Prevent attempt to alter buffer size if the released stream was the last | |
| 1018 // output stream. | |
| 1019 if (output_streams_.empty()) | |
| 1020 return; | |
| 1021 | |
| 1022 if (!AudioDeviceIsUsedForInput(id)) { | |
| 1023 // The current audio device is not used for input. See if it is possible to | |
| 1024 // increase the IO buffer size (saves power) given the remaining output | |
| 1025 // audio streams and their buffer size requirements. | |
| 1026 IncreaseIOBufferSizeIfPossible(id); | |
| 1027 } | |
| 923 } | 1028 } |
| 924 | 1029 |
| 925 void AudioManagerMac::ReleaseInputStream(AudioInputStream* stream) { | 1030 void AudioManagerMac::ReleaseInputStream(AudioInputStream* stream) { |
| 926 auto stream_it = std::find(basic_input_streams_.begin(), | 1031 auto stream_it = std::find(basic_input_streams_.begin(), |
| 927 basic_input_streams_.end(), | 1032 basic_input_streams_.end(), |
| 928 stream); | 1033 stream); |
| 929 if (stream_it == basic_input_streams_.end()) | 1034 if (stream_it == basic_input_streams_.end()) |
| 930 low_latency_input_streams_.remove(static_cast<AUAudioInputStream*>(stream)); | 1035 low_latency_input_streams_.remove(static_cast<AUAudioInputStream*>(stream)); |
| 931 else | 1036 else |
| 932 basic_input_streams_.erase(stream_it); | 1037 basic_input_streams_.erase(stream_it); |
| 933 | 1038 |
| 934 AudioManagerBase::ReleaseInputStream(stream); | 1039 AudioManagerBase::ReleaseInputStream(stream); |
| 935 } | 1040 } |
| 936 | 1041 |
| 937 ScopedAudioManagerPtr CreateAudioManager( | 1042 ScopedAudioManagerPtr CreateAudioManager( |
| 938 scoped_refptr<base::SingleThreadTaskRunner> task_runner, | 1043 scoped_refptr<base::SingleThreadTaskRunner> task_runner, |
| 939 scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner, | 1044 scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner, |
| 940 AudioLogFactory* audio_log_factory) { | 1045 AudioLogFactory* audio_log_factory) { |
| 941 return ScopedAudioManagerPtr( | 1046 return ScopedAudioManagerPtr( |
| 942 new AudioManagerMac(std::move(task_runner), std::move(worker_task_runner), | 1047 new AudioManagerMac(std::move(task_runner), std::move(worker_task_runner), |
| 943 audio_log_factory)); | 1048 audio_log_factory)); |
| 944 } | 1049 } |
| 945 | 1050 |
| 946 } // namespace media | 1051 } // namespace media |
| OLD | NEW |