Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(94)

Side by Side Diff: media/audio/mac/audio_manager_mac.cc

Issue 1903753002: Restores larger output buffer size when output stream requiring smaller size is closed (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: One more round based on feedback from olka@ Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 <limits>
9 #include <map>
10 #include <vector>
8 11
9 #include "base/bind.h" 12 #include "base/bind.h"
10 #include "base/command_line.h" 13 #include "base/command_line.h"
11 #include "base/mac/mac_logging.h" 14 #include "base/mac/mac_logging.h"
12 #include "base/mac/scoped_cftyperef.h" 15 #include "base/mac/scoped_cftyperef.h"
13 #include "base/macros.h" 16 #include "base/macros.h"
14 #include "base/memory/free_deleter.h" 17 #include "base/memory/free_deleter.h"
15 #include "base/power_monitor/power_monitor.h" 18 #include "base/power_monitor/power_monitor.h"
16 #include "base/power_monitor/power_observer.h" 19 #include "base/power_monitor/power_observer.h"
17 #include "base/strings/sys_string_conversions.h" 20 #include "base/strings/sys_string_conversions.h"
(...skipping 458 matching lines...) Expand 10 before | Expand all | Expand 10 after
476 } 479 }
477 480
478 void AudioManagerMac::GetAudioOutputDeviceNames( 481 void AudioManagerMac::GetAudioOutputDeviceNames(
479 media::AudioDeviceNames* device_names) { 482 media::AudioDeviceNames* device_names) {
480 DCHECK(device_names->empty()); 483 DCHECK(device_names->empty());
481 GetAudioDeviceInfo(false, device_names); 484 GetAudioDeviceInfo(false, device_names);
482 } 485 }
483 486
484 AudioParameters AudioManagerMac::GetInputStreamParameters( 487 AudioParameters AudioManagerMac::GetInputStreamParameters(
485 const std::string& device_id) { 488 const std::string& device_id) {
489 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
486 AudioDeviceID device = GetAudioDeviceIdByUId(true, device_id); 490 AudioDeviceID device = GetAudioDeviceIdByUId(true, device_id);
487 if (device == kAudioObjectUnknown) { 491 if (device == kAudioObjectUnknown) {
488 DLOG(ERROR) << "Invalid device " << device_id; 492 DLOG(ERROR) << "Invalid device " << device_id;
489 return AudioParameters( 493 return AudioParameters(
490 AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, 494 AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO,
491 kFallbackSampleRate, 16, ChooseBufferSize(true, kFallbackSampleRate)); 495 kFallbackSampleRate, 16, ChooseBufferSize(true, kFallbackSampleRate));
492 } 496 }
493 497
494 int channels = 0; 498 int channels = 0;
495 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; 499 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
591 if (default_device == *iter) 595 if (default_device == *iter)
592 return *iter; 596 return *iter;
593 } 597 }
594 598
595 // Failed to figure out which is the matching device, return an empty string. 599 // Failed to figure out which is the matching device, return an empty string.
596 return std::string(); 600 return std::string();
597 } 601 }
598 602
599 AudioOutputStream* AudioManagerMac::MakeLinearOutputStream( 603 AudioOutputStream* AudioManagerMac::MakeLinearOutputStream(
600 const AudioParameters& params) { 604 const AudioParameters& params) {
605 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
601 return MakeLowLatencyOutputStream(params, std::string()); 606 return MakeLowLatencyOutputStream(params, std::string());
602 } 607 }
603 608
604 AudioOutputStream* AudioManagerMac::MakeLowLatencyOutputStream( 609 AudioOutputStream* AudioManagerMac::MakeLowLatencyOutputStream(
605 const AudioParameters& params, 610 const AudioParameters& params,
606 const std::string& device_id) { 611 const std::string& device_id) {
612 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
607 bool device_listener_first_init = false; 613 bool device_listener_first_init = false;
608 // Lazily create the audio device listener on the first stream creation, 614 // Lazily create the audio device listener on the first stream creation,
609 // even if getting an audio device fails. Otherwise, if we have 0 audio 615 // even if getting an audio device fails. Otherwise, if we have 0 audio
610 // devices, the listener will never be initialized, and new valid devices 616 // devices, the listener will never be initialized, and new valid devices
611 // will never be detected. 617 // will never be detected.
612 if (!output_device_listener_) { 618 if (!output_device_listener_) {
613 // NOTE: Use BindToCurrentLoop() to ensure the callback is always PostTask'd 619 // NOTE: Use BindToCurrentLoop() to ensure the callback is always PostTask'd
614 // even if OSX calls us on the right thread. Some CoreAudio drivers will 620 // even if OSX calls us on the right thread. Some CoreAudio drivers will
615 // fire the callbacks during stream creation, leading to re-entrancy issues 621 // fire the callbacks during stream creation, leading to re-entrancy issues
616 // otherwise. See http://crbug.com/349604 622 // otherwise. See http://crbug.com/349604
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
665 return std::string(); 671 return std::string();
666 672
667 std::string ret(base::SysCFStringRefToUTF8(device_uid)); 673 std::string ret(base::SysCFStringRefToUTF8(device_uid));
668 CFRelease(device_uid); 674 CFRelease(device_uid);
669 675
670 return ret; 676 return ret;
671 } 677 }
672 678
673 AudioInputStream* AudioManagerMac::MakeLinearInputStream( 679 AudioInputStream* AudioManagerMac::MakeLinearInputStream(
674 const AudioParameters& params, const std::string& device_id) { 680 const AudioParameters& params, const std::string& device_id) {
681 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
675 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); 682 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
676 AudioInputStream* stream = new PCMQueueInAudioInputStream(this, params); 683 AudioInputStream* stream = new PCMQueueInAudioInputStream(this, params);
677 basic_input_streams_.push_back(stream); 684 basic_input_streams_.push_back(stream);
678 return stream; 685 return stream;
679 } 686 }
680 687
681 AudioInputStream* AudioManagerMac::MakeLowLatencyInputStream( 688 AudioInputStream* AudioManagerMac::MakeLowLatencyInputStream(
682 const AudioParameters& params, const std::string& device_id) { 689 const AudioParameters& params, const std::string& device_id) {
690 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
683 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); 691 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
684 // Gets the AudioDeviceID that refers to the AudioInputDevice with the device 692 // Gets the AudioDeviceID that refers to the AudioInputDevice with the device
685 // unique id. This AudioDeviceID is used to set the device for Audio Unit. 693 // unique id. This AudioDeviceID is used to set the device for Audio Unit.
686 AudioDeviceID audio_device_id = GetAudioDeviceIdByUId(true, device_id); 694 AudioDeviceID audio_device_id = GetAudioDeviceIdByUId(true, device_id);
687 AUAudioInputStream* stream = NULL; 695 AUAudioInputStream* stream = NULL;
688 if (audio_device_id != kAudioObjectUnknown) { 696 if (audio_device_id != kAudioObjectUnknown) {
689 stream = new AUAudioInputStream(this, params, audio_device_id); 697 stream = new AUAudioInputStream(this, params, audio_device_id);
690 low_latency_input_streams_.push_back(stream); 698 low_latency_input_streams_.push_back(stream);
691 } 699 }
692 700
693 return stream; 701 return stream;
694 } 702 }
695 703
696 AudioParameters AudioManagerMac::GetPreferredOutputStreamParameters( 704 AudioParameters AudioManagerMac::GetPreferredOutputStreamParameters(
697 const std::string& output_device_id, 705 const std::string& output_device_id,
698 const AudioParameters& input_params) { 706 const AudioParameters& input_params) {
707 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
699 const AudioDeviceID device = GetAudioDeviceIdByUId(false, output_device_id); 708 const AudioDeviceID device = GetAudioDeviceIdByUId(false, output_device_id);
700 if (device == kAudioObjectUnknown) { 709 if (device == kAudioObjectUnknown) {
701 DLOG(ERROR) << "Invalid output device " << output_device_id; 710 DLOG(ERROR) << "Invalid output device " << output_device_id;
702 return input_params.IsValid() ? input_params : AudioParameters( 711 return input_params.IsValid() ? input_params : AudioParameters(
703 AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, 712 AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO,
704 kFallbackSampleRate, 16, ChooseBufferSize(false, kFallbackSampleRate)); 713 kFallbackSampleRate, 16, ChooseBufferSize(false, kFallbackSampleRate));
705 } 714 }
706 715
707 const bool has_valid_input_params = input_params.IsValid(); 716 const bool has_valid_input_params = input_params.IsValid();
708 const int hardware_sample_rate = HardwareSampleRateForDevice(device); 717 const int hardware_sample_rate = HardwareSampleRateForDevice(device);
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after
910 << "AudioUnitSetProperty(kAudioDevicePropertyBufferFrameSize) failed. " 919 << "AudioUnitSetProperty(kAudioDevicePropertyBufferFrameSize) failed. "
911 << "Size:: " << buffer_size; 920 << "Size:: " << buffer_size;
912 *size_was_changed = (result == noErr); 921 *size_was_changed = (result == noErr);
913 DVLOG_IF(1, result == noErr) << "IO buffer size changed to: " << buffer_size; 922 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. 923 // Store the currently used (after a change) I/O buffer frame size.
915 *io_buffer_frame_size = buffer_size; 924 *io_buffer_frame_size = buffer_size;
916 925
917 return (result == noErr); 926 return (result == noErr);
918 } 927 }
919 928
929 #if !defined(NDEBUG)
930 void AudioManagerMac::PrintOutputBufferSizes() {
931 for (auto* stream : output_streams_) {
932 DVLOG(1) << "[id=0x" << std::hex << stream->device_id() << "] " << std::dec
933 << "requested: " << stream->requested_buffer_size() << ", "
934 << "actual: " << stream->actual_buffer_size();
935 }
936 }
937 #endif // !defined(NDEBUG)
938
939 bool AudioManagerMac::IncreaseIOBufferSizeIfPossible(AudioDeviceID device_id) {
940 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
941 DVLOG(1) << "IncreaseIOBufferSizeIfPossible(id=0x" << std::hex << device_id
942 << ")";
943
944 // Scan all active output streams using the specified |device_id|. Store the
945 // actual I/O buffer size once and find the minimum requested buffer size.
946 // In addition, store a reference to first output stream using |device_id|.
947 size_t actual_size = 0;
948 AUHALStream* output_stream = nullptr;
949 size_t min_requested_size = std::numeric_limits<std::size_t>::max();
950 for (auto* stream : output_streams_) {
951 if (stream->device_id() == device_id) {
952 if (output_stream == nullptr) {
953 // All active output streams uses the same actual I/O buffer size given
o1ka 2016/04/27 09:00:38 nit: uses->use
henrika (OOO until Aug 14) 2016/04/27 12:12:30 Done.
954 // a unique device ID. Hence, it is sufficient to store one value once.
o1ka 2016/04/27 09:00:38 nit: "one value" -> "the value"
henrika (OOO until Aug 14) 2016/04/27 12:12:30 Done.
955 actual_size = stream->actual_buffer_size();
956 // Also store a reference to the first stream using the specified ID.
957 output_stream = stream;
o1ka 2016/04/27 09:00:38 nit: all you need is audio_unit, so you can probab
henrika (OOO until Aug 14) 2016/04/27 12:12:31 I can't really see any benefit by doing that.
o1ka 2016/04/27 13:24:40 Clearer intentions of what you really need?
henrika (OOO until Aug 14) 2016/04/27 13:36:43 I would like to keep it as is if possible. More si
o1ka 2016/04/27 15:04:31 You don't need to check for null, you can just che
henrika (OOO until Aug 14) 2016/04/28 11:28:44 Your word is my law ;-) Changed.
958 }
959 if (stream->requested_buffer_size() < min_requested_size)
960 min_requested_size = stream->requested_buffer_size();
961 DVLOG(1) << "requested:" << stream->requested_buffer_size()
962 << " actual: " << actual_size;
963 }
964 }
965
966 if (output_stream == nullptr) {
967 DVLOG(1) << "No action since there is no active stream for given device id";
968 return false;
969 }
970
971 // It is only possible to revert to a larger buffer size if the lowest
972 // requested is not in use. Example: if the actual I/O buffer size is 256 and
973 // at least one output stream has asked for 256 as its buffer size, we can't
974 // start using a larger I/O buffer size.
975 if (min_requested_size == actual_size) {
o1ka 2016/04/27 09:00:38 add DCHECK_GE(min_requested_size, actual_size)?
henrika (OOO until Aug 14) 2016/04/27 12:12:30 Sorry but where do you want me to add that check?
o1ka 2016/04/27 13:24:40 Right above this line. Makes sense?
henrika (OOO until Aug 14) 2016/04/27 13:36:43 OK, above makes sense. I figured you meant here af
o1ka 2016/04/27 15:04:31 Acknowledged.
976 DVLOG(1) << "No action since lowest possible size is already in use: "
977 << actual_size;
978 return false;
979 }
980
981 // It should now be safe to increase the I/O buffer size to a new (higher)
982 // value using the |min_requested_size|. Doing so will save system resources.
983 // All active output streams with the same |device_id| are affected by this
984 // change but it is only required to apply the change to one of the streams.
985 const size_t increased_io_buffer_frame_size = min_requested_size;
o1ka 2016/04/27 09:00:38 const size_t& Actually, I think min_requested_size
henrika (OOO until Aug 14) 2016/04/27 12:12:31 Done.
986 DVLOG(1) << "increased_io_buffer_frame_size: "
987 << increased_io_buffer_frame_size;
988 bool size_was_changed = false;
989 size_t io_buffer_frame_size = 0;
990 bool result = MaybeChangeBufferSize(device_id, output_stream->audio_unit(), 0,
991 increased_io_buffer_frame_size,
992 &size_was_changed, &io_buffer_frame_size);
993 DCHECK_EQ(io_buffer_frame_size, increased_io_buffer_frame_size);
o1ka 2016/04/27 09:00:38 DCHECK size_was_changed as well?
henrika (OOO until Aug 14) 2016/04/27 12:12:30 Actually, Yes. I could not do it earlier but now w
994
995 return result;
996 }
997
998 bool AudioManagerMac::AudioDeviceIsUsedForInput(AudioDeviceID device_id) {
999 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
1000 if (!basic_input_streams_.empty()) {
1001 // For Audio Queues and in the default case (Mac OS X), the audio comes
1002 // from the system’s default audio input device as set by a user in System
1003 // Preferences.
1004 AudioDeviceID default_id;
1005 GetDefaultDevice(&default_id, true);
1006 if (default_id == device_id)
1007 return true;
1008 }
1009
1010 // Each low latency streams has its own device ID.
1011 for (auto* stream : low_latency_input_streams_) {
1012 if (stream->device_id() == device_id)
1013 return true;
1014 }
1015 return false;
1016 }
1017
920 void AudioManagerMac::ReleaseOutputStream(AudioOutputStream* stream) { 1018 void AudioManagerMac::ReleaseOutputStream(AudioOutputStream* stream) {
1019 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
1020 const AudioDeviceID id = static_cast<AUHALStream*>(stream)->device_id();
1021 DVLOG(1) << "Closing down output stream with id=0x" << std::hex << id;
1022
1023 // Start by closing down the specified output stream.
921 output_streams_.remove(static_cast<AUHALStream*>(stream)); 1024 output_streams_.remove(static_cast<AUHALStream*>(stream));
1025 #if !defined(NDEBUG)
1026 PrintOutputBufferSizes();
1027 #endif // !defined(NDEBUG)
922 AudioManagerBase::ReleaseOutputStream(stream); 1028 AudioManagerBase::ReleaseOutputStream(stream);
1029
1030 // Prevent attempt to alter buffer size if the released stream was the last
1031 // output stream.
1032 if (output_streams_.empty())
1033 return;
1034
1035 if (!AudioDeviceIsUsedForInput(id)) {
1036 // The current audio device is not used for input. See if it is possible to
1037 // increase the IO buffer size (saves power) given the remaining output
1038 // audio streams and their buffer size requirements.
1039 IncreaseIOBufferSizeIfPossible(id);
1040 }
923 } 1041 }
924 1042
925 void AudioManagerMac::ReleaseInputStream(AudioInputStream* stream) { 1043 void AudioManagerMac::ReleaseInputStream(AudioInputStream* stream) {
1044 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
926 auto stream_it = std::find(basic_input_streams_.begin(), 1045 auto stream_it = std::find(basic_input_streams_.begin(),
927 basic_input_streams_.end(), 1046 basic_input_streams_.end(),
928 stream); 1047 stream);
929 if (stream_it == basic_input_streams_.end()) 1048 if (stream_it == basic_input_streams_.end())
930 low_latency_input_streams_.remove(static_cast<AUAudioInputStream*>(stream)); 1049 low_latency_input_streams_.remove(static_cast<AUAudioInputStream*>(stream));
931 else 1050 else
932 basic_input_streams_.erase(stream_it); 1051 basic_input_streams_.erase(stream_it);
933 1052
934 AudioManagerBase::ReleaseInputStream(stream); 1053 AudioManagerBase::ReleaseInputStream(stream);
935 } 1054 }
936 1055
937 ScopedAudioManagerPtr CreateAudioManager( 1056 ScopedAudioManagerPtr CreateAudioManager(
938 scoped_refptr<base::SingleThreadTaskRunner> task_runner, 1057 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
939 scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner, 1058 scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner,
940 AudioLogFactory* audio_log_factory) { 1059 AudioLogFactory* audio_log_factory) {
941 return ScopedAudioManagerPtr( 1060 return ScopedAudioManagerPtr(
942 new AudioManagerMac(std::move(task_runner), std::move(worker_task_runner), 1061 new AudioManagerMac(std::move(task_runner), std::move(worker_task_runner),
943 audio_log_factory)); 1062 audio_log_factory));
944 } 1063 }
945 1064
946 } // namespace media 1065 } // namespace media
OLDNEW
« media/audio/mac/audio_auhal_mac.cc ('K') | « media/audio/mac/audio_manager_mac.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698