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

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

Issue 1973503003: (Relanding) 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: added comment Created 4 years, 7 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
« no previous file with comments | « media/audio/mac/audio_manager_mac.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 <vector>
8 10
9 #include "base/bind.h" 11 #include "base/bind.h"
10 #include "base/command_line.h" 12 #include "base/command_line.h"
11 #include "base/mac/mac_logging.h" 13 #include "base/mac/mac_logging.h"
12 #include "base/mac/scoped_cftyperef.h" 14 #include "base/mac/scoped_cftyperef.h"
13 #include "base/macros.h" 15 #include "base/macros.h"
14 #include "base/memory/free_deleter.h" 16 #include "base/memory/free_deleter.h"
15 #include "base/power_monitor/power_monitor.h" 17 #include "base/power_monitor/power_monitor.h"
16 #include "base/power_monitor/power_observer.h" 18 #include "base/power_monitor/power_observer.h"
17 #include "base/strings/sys_string_conversions.h" 19 #include "base/strings/sys_string_conversions.h"
(...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after
474 } 476 }
475 477
476 void AudioManagerMac::GetAudioOutputDeviceNames( 478 void AudioManagerMac::GetAudioOutputDeviceNames(
477 media::AudioDeviceNames* device_names) { 479 media::AudioDeviceNames* device_names) {
478 DCHECK(device_names->empty()); 480 DCHECK(device_names->empty());
479 GetAudioDeviceInfo(false, device_names); 481 GetAudioDeviceInfo(false, device_names);
480 } 482 }
481 483
482 AudioParameters AudioManagerMac::GetInputStreamParameters( 484 AudioParameters AudioManagerMac::GetInputStreamParameters(
483 const std::string& device_id) { 485 const std::string& device_id) {
486 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
484 AudioDeviceID device = GetAudioDeviceIdByUId(true, device_id); 487 AudioDeviceID device = GetAudioDeviceIdByUId(true, device_id);
485 if (device == kAudioObjectUnknown) { 488 if (device == kAudioObjectUnknown) {
486 DLOG(ERROR) << "Invalid device " << device_id; 489 DLOG(ERROR) << "Invalid device " << device_id;
487 return AudioParameters( 490 return AudioParameters(
488 AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, 491 AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO,
489 kFallbackSampleRate, 16, ChooseBufferSize(true, kFallbackSampleRate)); 492 kFallbackSampleRate, 16, ChooseBufferSize(true, kFallbackSampleRate));
490 } 493 }
491 494
492 int channels = 0; 495 int channels = 0;
493 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; 496 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
589 if (default_device == *iter) 592 if (default_device == *iter)
590 return *iter; 593 return *iter;
591 } 594 }
592 595
593 // Failed to figure out which is the matching device, return an empty string. 596 // Failed to figure out which is the matching device, return an empty string.
594 return std::string(); 597 return std::string();
595 } 598 }
596 599
597 AudioOutputStream* AudioManagerMac::MakeLinearOutputStream( 600 AudioOutputStream* AudioManagerMac::MakeLinearOutputStream(
598 const AudioParameters& params) { 601 const AudioParameters& params) {
602 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
599 return MakeLowLatencyOutputStream(params, std::string()); 603 return MakeLowLatencyOutputStream(params, std::string());
600 } 604 }
601 605
602 AudioOutputStream* AudioManagerMac::MakeLowLatencyOutputStream( 606 AudioOutputStream* AudioManagerMac::MakeLowLatencyOutputStream(
603 const AudioParameters& params, 607 const AudioParameters& params,
604 const std::string& device_id) { 608 const std::string& device_id) {
609 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
605 bool device_listener_first_init = false; 610 bool device_listener_first_init = false;
606 // Lazily create the audio device listener on the first stream creation, 611 // Lazily create the audio device listener on the first stream creation,
607 // even if getting an audio device fails. Otherwise, if we have 0 audio 612 // even if getting an audio device fails. Otherwise, if we have 0 audio
608 // devices, the listener will never be initialized, and new valid devices 613 // devices, the listener will never be initialized, and new valid devices
609 // will never be detected. 614 // will never be detected.
610 if (!output_device_listener_) { 615 if (!output_device_listener_) {
611 // NOTE: Use BindToCurrentLoop() to ensure the callback is always PostTask'd 616 // NOTE: Use BindToCurrentLoop() to ensure the callback is always PostTask'd
612 // even if OSX calls us on the right thread. Some CoreAudio drivers will 617 // even if OSX calls us on the right thread. Some CoreAudio drivers will
613 // fire the callbacks during stream creation, leading to re-entrancy issues 618 // fire the callbacks during stream creation, leading to re-entrancy issues
614 // otherwise. See http://crbug.com/349604 619 // otherwise. See http://crbug.com/349604
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
663 return std::string(); 668 return std::string();
664 669
665 std::string ret(base::SysCFStringRefToUTF8(device_uid)); 670 std::string ret(base::SysCFStringRefToUTF8(device_uid));
666 CFRelease(device_uid); 671 CFRelease(device_uid);
667 672
668 return ret; 673 return ret;
669 } 674 }
670 675
671 AudioInputStream* AudioManagerMac::MakeLinearInputStream( 676 AudioInputStream* AudioManagerMac::MakeLinearInputStream(
672 const AudioParameters& params, const std::string& device_id) { 677 const AudioParameters& params, const std::string& device_id) {
678 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
673 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); 679 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
674 AudioInputStream* stream = new PCMQueueInAudioInputStream(this, params); 680 AudioInputStream* stream = new PCMQueueInAudioInputStream(this, params);
675 basic_input_streams_.push_back(stream); 681 basic_input_streams_.push_back(stream);
676 return stream; 682 return stream;
677 } 683 }
678 684
679 AudioInputStream* AudioManagerMac::MakeLowLatencyInputStream( 685 AudioInputStream* AudioManagerMac::MakeLowLatencyInputStream(
680 const AudioParameters& params, const std::string& device_id) { 686 const AudioParameters& params, const std::string& device_id) {
687 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
681 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); 688 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
682 // Gets the AudioDeviceID that refers to the AudioInputDevice with the device 689 // Gets the AudioDeviceID that refers to the AudioInputDevice with the device
683 // unique id. This AudioDeviceID is used to set the device for Audio Unit. 690 // unique id. This AudioDeviceID is used to set the device for Audio Unit.
684 AudioDeviceID audio_device_id = GetAudioDeviceIdByUId(true, device_id); 691 AudioDeviceID audio_device_id = GetAudioDeviceIdByUId(true, device_id);
685 AUAudioInputStream* stream = NULL; 692 AUAudioInputStream* stream = NULL;
686 if (audio_device_id != kAudioObjectUnknown) { 693 if (audio_device_id != kAudioObjectUnknown) {
687 stream = new AUAudioInputStream(this, params, audio_device_id); 694 stream = new AUAudioInputStream(this, params, audio_device_id);
688 low_latency_input_streams_.push_back(stream); 695 low_latency_input_streams_.push_back(stream);
689 } 696 }
690 697
691 return stream; 698 return stream;
692 } 699 }
693 700
694 AudioParameters AudioManagerMac::GetPreferredOutputStreamParameters( 701 AudioParameters AudioManagerMac::GetPreferredOutputStreamParameters(
695 const std::string& output_device_id, 702 const std::string& output_device_id,
696 const AudioParameters& input_params) { 703 const AudioParameters& input_params) {
704 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
697 const AudioDeviceID device = GetAudioDeviceIdByUId(false, output_device_id); 705 const AudioDeviceID device = GetAudioDeviceIdByUId(false, output_device_id);
698 if (device == kAudioObjectUnknown) { 706 if (device == kAudioObjectUnknown) {
699 DLOG(ERROR) << "Invalid output device " << output_device_id; 707 DLOG(ERROR) << "Invalid output device " << output_device_id;
700 return input_params.IsValid() ? input_params : AudioParameters( 708 return input_params.IsValid() ? input_params : AudioParameters(
701 AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, 709 AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO,
702 kFallbackSampleRate, 16, ChooseBufferSize(false, kFallbackSampleRate)); 710 kFallbackSampleRate, 16, ChooseBufferSize(false, kFallbackSampleRate));
703 } 711 }
704 712
705 const bool has_valid_input_params = input_params.IsValid(); 713 const bool has_valid_input_params = input_params.IsValid();
706 const int hardware_sample_rate = HardwareSampleRateForDevice(device); 714 const int hardware_sample_rate = HardwareSampleRateForDevice(device);
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after
905 kAudioUnitScope_Global, 0, &buffer_size, 913 kAudioUnitScope_Global, 0, &buffer_size,
906 sizeof(buffer_size)); 914 sizeof(buffer_size));
907 OSSTATUS_DLOG_IF(ERROR, result != noErr, result) 915 OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
908 << "AudioUnitSetProperty(kAudioDevicePropertyBufferFrameSize) failed. " 916 << "AudioUnitSetProperty(kAudioDevicePropertyBufferFrameSize) failed. "
909 << "Size:: " << buffer_size; 917 << "Size:: " << buffer_size;
910 *size_was_changed = (result == noErr); 918 *size_was_changed = (result == noErr);
911 DVLOG_IF(1, result == noErr) << "IO buffer size changed to: " << buffer_size; 919 DVLOG_IF(1, result == noErr) << "IO buffer size changed to: " << buffer_size;
912 // Store the currently used (after a change) I/O buffer frame size. 920 // Store the currently used (after a change) I/O buffer frame size.
913 *io_buffer_frame_size = buffer_size; 921 *io_buffer_frame_size = buffer_size;
914 922
923 // If the size was changed, update the actual output buffer size used for the
924 // given device ID.
925 if (!is_input && (result == noErr)) {
926 output_io_buffer_size_map_[device_id] = buffer_size;
927 }
928
915 return (result == noErr); 929 return (result == noErr);
916 } 930 }
917 931
932 bool AudioManagerMac::IncreaseIOBufferSizeIfPossible(AudioDeviceID device_id) {
933 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
934 DVLOG(1) << "IncreaseIOBufferSizeIfPossible(id=0x" << std::hex << device_id
935 << ")";
936 // Start by storing the actual I/O buffer size. Then scan all active output
937 // streams using the specified |device_id| and find the minimum requested
938 // buffer size. In addition, store a reference to the audio unit of the first
939 // output stream using |device_id|.
940 DCHECK(!output_io_buffer_size_map_.empty());
941 // All active output streams use the same actual I/O buffer size given
942 // a unique device ID.
943 // TODO(henrika): it would also be possible to use AudioUnitGetProperty(...,
944 // kAudioDevicePropertyBufferFrameSize,...) instead of caching the actual
945 // buffer size but I have chosen to use the map instead to avoid possibly
946 // expensive Core Audio API calls and the risk of failure when asking while
947 // closing a stream.
948 const size_t& actual_size = output_io_buffer_size_map_[device_id];
949 AudioUnit audio_unit;
950 size_t min_requested_size = std::numeric_limits<std::size_t>::max();
951 for (auto* stream : output_streams_) {
952 if (stream->device_id() == device_id) {
953 if (min_requested_size == std::numeric_limits<std::size_t>::max()) {
954 // Store reference to the first audio unit using the specified ID.
955 audio_unit = stream->audio_unit();
956 }
957 if (stream->requested_buffer_size() < min_requested_size)
958 min_requested_size = stream->requested_buffer_size();
959 DVLOG(1) << "requested:" << stream->requested_buffer_size()
960 << " actual: " << actual_size;
961 }
962 }
963
964 if (min_requested_size == std::numeric_limits<std::size_t>::max()) {
965 DVLOG(1) << "No action since there is no active stream for given device id";
966 return false;
967 }
968
969 // It is only possible to revert to a larger buffer size if the lowest
970 // requested is not in use. Example: if the actual I/O buffer size is 256 and
971 // at least one output stream has asked for 256 as its buffer size, we can't
972 // start using a larger I/O buffer size.
973 DCHECK_GE(min_requested_size, actual_size);
974 if (min_requested_size == actual_size) {
975 DVLOG(1) << "No action since lowest possible size is already in use: "
976 << actual_size;
977 return false;
978 }
979
980 // It should now be safe to increase the I/O buffer size to a new (higher)
981 // value using the |min_requested_size|. Doing so will save system resources.
982 // All active output streams with the same |device_id| are affected by this
983 // change but it is only required to apply the change to one of the streams.
984 DVLOG(1) << "min_requested_size: " << min_requested_size;
985 bool size_was_changed = false;
986 size_t io_buffer_frame_size = 0;
987 bool result =
988 MaybeChangeBufferSize(device_id, audio_unit, 0, min_requested_size,
989 &size_was_changed, &io_buffer_frame_size);
990 DCHECK_EQ(io_buffer_frame_size, min_requested_size);
991 DCHECK(size_was_changed);
992 return result;
993 }
994
995 bool AudioManagerMac::AudioDeviceIsUsedForInput(AudioDeviceID device_id) {
996 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
997 if (!basic_input_streams_.empty()) {
998 // For Audio Queues and in the default case (Mac OS X), the audio comes
999 // from the system’s default audio input device as set by a user in System
1000 // Preferences.
1001 AudioDeviceID default_id;
1002 GetDefaultDevice(&default_id, true);
1003 if (default_id == device_id)
1004 return true;
1005 }
1006
1007 // Each low latency streams has its own device ID.
1008 for (auto* stream : low_latency_input_streams_) {
1009 if (stream->device_id() == device_id)
1010 return true;
1011 }
1012 return false;
1013 }
1014
918 void AudioManagerMac::ReleaseOutputStream(AudioOutputStream* stream) { 1015 void AudioManagerMac::ReleaseOutputStream(AudioOutputStream* stream) {
1016 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
919 output_streams_.remove(static_cast<AUHALStream*>(stream)); 1017 output_streams_.remove(static_cast<AUHALStream*>(stream));
920 AudioManagerBase::ReleaseOutputStream(stream); 1018 AudioManagerBase::ReleaseOutputStream(stream);
921 } 1019 }
922 1020
1021 void AudioManagerMac::ReleaseOutputStreamUsingRealDevice(
1022 AudioOutputStream* stream,
1023 AudioDeviceID device_id) {
1024 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
1025 DVLOG(1) << "Closing output stream with id=0x" << std::hex << device_id;
1026 DVLOG(1) << "requested_buffer_size: "
1027 << static_cast<AUHALStream*>(stream)->requested_buffer_size();
1028
1029 // Start by closing down the specified output stream.
1030 output_streams_.remove(static_cast<AUHALStream*>(stream));
1031 AudioManagerBase::ReleaseOutputStream(stream);
1032
1033 // Prevent attempt to alter buffer size if the released stream was the last
1034 // output stream.
1035 if (output_streams_.empty())
1036 return;
1037
1038 if (!AudioDeviceIsUsedForInput(device_id)) {
1039 // The current audio device is not used for input. See if it is possible to
1040 // increase the IO buffer size (saves power) given the remaining output
1041 // audio streams and their buffer size requirements.
1042 IncreaseIOBufferSizeIfPossible(device_id);
1043 }
1044 }
1045
923 void AudioManagerMac::ReleaseInputStream(AudioInputStream* stream) { 1046 void AudioManagerMac::ReleaseInputStream(AudioInputStream* stream) {
1047 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
924 auto stream_it = std::find(basic_input_streams_.begin(), 1048 auto stream_it = std::find(basic_input_streams_.begin(),
925 basic_input_streams_.end(), 1049 basic_input_streams_.end(),
926 stream); 1050 stream);
927 if (stream_it == basic_input_streams_.end()) 1051 if (stream_it == basic_input_streams_.end())
928 low_latency_input_streams_.remove(static_cast<AUAudioInputStream*>(stream)); 1052 low_latency_input_streams_.remove(static_cast<AUAudioInputStream*>(stream));
929 else 1053 else
930 basic_input_streams_.erase(stream_it); 1054 basic_input_streams_.erase(stream_it);
931 1055
932 AudioManagerBase::ReleaseInputStream(stream); 1056 AudioManagerBase::ReleaseInputStream(stream);
933 } 1057 }
934 1058
935 ScopedAudioManagerPtr CreateAudioManager( 1059 ScopedAudioManagerPtr CreateAudioManager(
936 scoped_refptr<base::SingleThreadTaskRunner> task_runner, 1060 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
937 scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner, 1061 scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner,
938 AudioLogFactory* audio_log_factory) { 1062 AudioLogFactory* audio_log_factory) {
939 return ScopedAudioManagerPtr( 1063 return ScopedAudioManagerPtr(
940 new AudioManagerMac(std::move(task_runner), std::move(worker_task_runner), 1064 new AudioManagerMac(std::move(task_runner), std::move(worker_task_runner),
941 audio_log_factory)); 1065 audio_log_factory));
942 } 1066 }
943 1067
944 } // namespace media 1068 } // namespace media
OLDNEW
« no previous file with comments | « 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