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

Side by Side Diff: content/renderer/media/audio_renderer_mixer_manager.cc

Issue 2067863003: Mixing audio with different latency requirements (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: mixing inputs of the same latency Created 4 years, 6 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 "content/renderer/media/audio_renderer_mixer_manager.h" 5 #include "content/renderer/media/audio_renderer_mixer_manager.h"
6 6
7 #include <algorithm>
7 #include <string> 8 #include <string>
8 9
9 #include "base/bind.h" 10 #include "base/bind.h"
10 #include "base/bind_helpers.h" 11 #include "base/bind_helpers.h"
11 #include "base/memory/ptr_util.h" 12 #include "base/memory/ptr_util.h"
12 #include "build/build_config.h" 13 #include "build/build_config.h"
13 #include "content/renderer/media/audio_renderer_sink_cache.h" 14 #include "content/renderer/media/audio_renderer_sink_cache.h"
14 #include "media/audio/audio_device_description.h" 15 #include "media/audio/audio_device_description.h"
15 #include "media/base/audio_hardware_config.h" 16 #include "media/base/audio_hardware_config.h"
16 #include "media/base/audio_renderer_mixer.h" 17 #include "media/base/audio_renderer_mixer.h"
17 #include "media/base/audio_renderer_mixer_input.h" 18 #include "media/base/audio_renderer_mixer_input.h"
18 19
20 namespace {
21 // calculate mixer output parameters based on input parameters and audio
22 // hardware configuration.
23 media::AudioParameters GetMixerOutputParams(
24 const media::AudioParameters& input_params,
25 const media::AudioParameters& hardware_params,
26 media::AudioLatency::LatencyType latency) {
27 int output_sample_rate = input_params.sample_rate();
28 bool valid_not_fake_hardware_params =
29 hardware_params.format() != media::AudioParameters::AUDIO_FAKE &&
30 hardware_params.IsValid();
31 int preferred_high_latency_output_bufffer_size = 0;
32
33 #if !defined(OS_CHROMEOS)
34 // On ChromeOS as well as when a fake device is used, we can rely on the
35 // playback device to handle resampling, so don't waste cycles on it here.
36 // On other systems if hardware parameters are valid and the device is not
37 // fake, resample to hadrware sample rate. Otherwise, pass the input one and
38 // let the browser side handle automatic fallback.
39 if (valid_not_fake_hardware_params) {
40 output_sample_rate = hardware_params.sample_rate();
41 preferred_high_latency_output_bufffer_size =
42 hardware_params.frames_per_buffer();
43 }
44 #endif
45
46 int output_buffer_size = input_params.frames_per_buffer();
o1ka 2016/06/23 16:36:15 Note that here we rely on the current situation wh
chcunningham 2016/06/27 23:12:24 You bring up an interesting point - now I'm confus
o1ka 2016/06/28 13:04:57 Unfortunately I did not let you know: I changed it
chcunningham 2016/06/28 18:43:49 Ack - my bad. This method looks good in the new PS
DaleCurtis 2016/06/28 21:44:07 I don't think it matters either way; the size is "
47
48 if (output_sample_rate != input_params.sample_rate()) {
chcunningham 2016/06/27 23:12:25 Why do we only go down this path when in/out sampl
49 // Adjust output buffer size according to the latency requirement.
50 switch (latency) {
51 case media::AudioLatency::LATENCY_EXACT_MS:
o1ka 2016/06/21 15:16:40 It's not used right now, but we'll need it for htt
52 // Keep the provided buffer duration.
53 output_buffer_size = input_params.GetBufferDuration().InMicroseconds() *
54 output_sample_rate /
55 base::Time::kMicrosecondsPerSecond;
56 break;
57 case media::AudioLatency::LATENCY_INTERACTIVE:
58 // WebAudio should provide correct callback size in frames; it does not
59 // depend on the sample rate.
60 DCHECK_EQ(output_buffer_size,
61 media::AudioLatency::GetInteractiveBufferSize(
o1ka 2016/06/21 15:16:41 Also not sure about this check, probably should be
chcunningham 2016/06/22 04:34:07 I think this would be wrong for android, where Get
o1ka 2016/06/23 16:36:15 Currently WebAudio sets the buffer size in AudioDe
chcunningham 2016/06/27 23:12:25 I think this gets at my comment on line 46 above -
o1ka 2016/06/28 13:04:57 Agreed.
62 hardware_params.frames_per_buffer()));
63 break;
64 case media::AudioLatency::LATENCY_RTC:
65 output_buffer_size = media::AudioLatency::GetRtcBufferSize(
66 output_sample_rate, valid_not_fake_hardware_params
67 ? hardware_params.frames_per_buffer()
68 : 0);
69 break;
70 case media::AudioLatency::LATENCY_PLAYBACK:
chcunningham 2016/06/22 04:34:07 Could you combine this case with the default? Woul
71 output_buffer_size = media::AudioLatency::GetHighLatencyBufferSize(
72 output_sample_rate, preferred_high_latency_output_bufffer_size);
73 break;
74 default:
75 DCHECK(false);
chcunningham 2016/06/22 04:34:07 If you don't combine with LATENCY_PLAYBACK, this s
o1ka 2016/06/23 16:36:15 I would prefer to not combine, because it may be t
chcunningham 2016/06/27 23:12:25 Sounds good.
76 }
77 }
78
79 // Force to 16-bit output for now since we know that works everywhere;
80 // ChromeOS does not support other bit depths.
81 return media::AudioParameters(input_params.format(),
82 input_params.channel_layout(),
83 output_sample_rate, 16, output_buffer_size);
84 }
85
86 } // namespace
87
19 namespace content { 88 namespace content {
20 89
21 AudioRendererMixerManager::AudioRendererMixerManager( 90 AudioRendererMixerManager::AudioRendererMixerManager(
22 std::unique_ptr<AudioRendererSinkCache> sink_cache) 91 std::unique_ptr<AudioRendererSinkCache> sink_cache)
23 : sink_cache_(std::move(sink_cache)) { 92 : sink_cache_(std::move(sink_cache)) {
24 DCHECK(sink_cache_); 93 DCHECK(sink_cache_);
25 } 94 }
26 95
27 AudioRendererMixerManager::~AudioRendererMixerManager() { 96 AudioRendererMixerManager::~AudioRendererMixerManager() {
28 // References to AudioRendererMixers may be owned by garbage collected 97 // References to AudioRendererMixers may be owned by garbage collected
29 // objects. During process shutdown they may be leaked, so, transitively, 98 // objects. During process shutdown they may be leaked, so, transitively,
30 // |mixers_| may leak (i.e., may be non-empty at this time) as well. 99 // |mixers_| may leak (i.e., may be non-empty at this time) as well.
31 } 100 }
32 101
33 // static 102 // static
34 std::unique_ptr<AudioRendererMixerManager> AudioRendererMixerManager::Create() { 103 std::unique_ptr<AudioRendererMixerManager> AudioRendererMixerManager::Create() {
35 return base::WrapUnique( 104 return base::WrapUnique(
36 new AudioRendererMixerManager(AudioRendererSinkCache::Create())); 105 new AudioRendererMixerManager(AudioRendererSinkCache::Create()));
37 } 106 }
38 107
39 media::AudioRendererMixerInput* AudioRendererMixerManager::CreateInput( 108 media::AudioRendererMixerInput* AudioRendererMixerManager::CreateInput(
40 int source_render_frame_id, 109 int source_render_frame_id,
41 int session_id, 110 int session_id,
42 const std::string& device_id, 111 const std::string& device_id,
43 const url::Origin& security_origin) { 112 const url::Origin& security_origin,
113 media::AudioLatency::LatencyType latency) {
chcunningham 2016/06/22 04:34:07 Has the spec settled on latency coming in through
o1ka 2016/06/23 16:36:15 Yes, it is passed in AudioContextOptions as a cons
chcunningham 2016/06/27 23:12:25 Acknowledged.
44 // AudioRendererMixerManager lives on the renderer thread and is destroyed on 114 // AudioRendererMixerManager lives on the renderer thread and is destroyed on
45 // renderer thread destruction, so it's safe to pass its pointer to a mixer 115 // renderer thread destruction, so it's safe to pass its pointer to a mixer
46 // input. 116 // input.
47 return new media::AudioRendererMixerInput( 117 return new media::AudioRendererMixerInput(
48 this, source_render_frame_id, 118 this, source_render_frame_id,
49 media::AudioDeviceDescription::UseSessionIdToSelectDevice(session_id, 119 media::AudioDeviceDescription::UseSessionIdToSelectDevice(session_id,
50 device_id) 120 device_id)
51 ? GetOutputDeviceInfo(source_render_frame_id, session_id, device_id, 121 ? GetOutputDeviceInfo(source_render_frame_id, session_id, device_id,
52 security_origin) 122 security_origin)
53 .device_id() 123 .device_id()
54 : device_id, 124 : device_id,
55 security_origin); 125 security_origin, latency);
56 } 126 }
57 127
58 media::AudioRendererMixer* AudioRendererMixerManager::GetMixer( 128 media::AudioRendererMixer* AudioRendererMixerManager::GetMixer(
59 int source_render_frame_id, 129 int source_render_frame_id,
60 const media::AudioParameters& params, 130 const media::AudioParameters& input_params,
131 media::AudioLatency::LatencyType latency,
61 const std::string& device_id, 132 const std::string& device_id,
62 const url::Origin& security_origin, 133 const url::Origin& security_origin,
63 media::OutputDeviceStatus* device_status) { 134 media::OutputDeviceStatus* device_status) {
64 // Effects are not passed through to output creation, so ensure none are set. 135 // Effects are not passed through to output creation, so ensure none are set.
65 DCHECK_EQ(params.effects(), media::AudioParameters::NO_EFFECTS); 136 DCHECK_EQ(input_params.effects(), media::AudioParameters::NO_EFFECTS);
66 137
67 const MixerKey key(source_render_frame_id, params, device_id, 138 const MixerKey key(source_render_frame_id, input_params, latency, device_id,
68 security_origin); 139 security_origin);
69 base::AutoLock auto_lock(mixers_lock_); 140 base::AutoLock auto_lock(mixers_lock_);
70 141
71 AudioRendererMixerMap::iterator it = mixers_.find(key); 142 AudioRendererMixerMap::iterator it = mixers_.find(key);
72 if (it != mixers_.end()) { 143 if (it != mixers_.end()) {
73 if (device_status) 144 if (device_status)
74 *device_status = media::OUTPUT_DEVICE_STATUS_OK; 145 *device_status = media::OUTPUT_DEVICE_STATUS_OK;
75 146
76 it->second.ref_count++; 147 it->second.ref_count++;
148 DVLOG(1) << "Reusing mixer: " << it->second.mixer;
77 return it->second.mixer; 149 return it->second.mixer;
78 } 150 }
79 151
80 scoped_refptr<media::AudioRendererSink> sink = 152 scoped_refptr<media::AudioRendererSink> sink =
81 sink_cache_->GetSink(source_render_frame_id, device_id, security_origin); 153 sink_cache_->GetSink(source_render_frame_id, device_id, security_origin);
82 154
83 const media::OutputDeviceInfo& device_info = sink->GetOutputDeviceInfo(); 155 const media::OutputDeviceInfo& device_info = sink->GetOutputDeviceInfo();
84 if (device_status) 156 if (device_status)
85 *device_status = device_info.device_status(); 157 *device_status = device_info.device_status();
86 if (device_info.device_status() != media::OUTPUT_DEVICE_STATUS_OK) { 158 if (device_info.device_status() != media::OUTPUT_DEVICE_STATUS_OK) {
87 sink_cache_->ReleaseSink(sink.get()); 159 sink_cache_->ReleaseSink(sink.get());
88 sink->Stop(); 160 sink->Stop();
89 return nullptr; 161 return nullptr;
90 } 162 }
91 163
92 // On ChromeOS as well as when a fake device is used, we can rely on the 164 const media::AudioParameters& mixer_output_params =
93 // playback device to handle resampling, so don't waste cycles on it here. 165 GetMixerOutputParams(input_params, device_info.output_params(), latency);
94 int sample_rate = params.sample_rate();
95 int buffer_size =
96 media::AudioHardwareConfig::GetHighLatencyBufferSize(sample_rate, 0);
97
98 #if !defined(OS_CHROMEOS)
99 const media::AudioParameters& hardware_params = device_info.output_params();
100
101 // If we have valid, non-fake hardware parameters, use them. Otherwise, pass
102 // on the input params and let the browser side handle automatic fallback.
103 if (hardware_params.format() != media::AudioParameters::AUDIO_FAKE &&
104 hardware_params.IsValid()) {
105 sample_rate = hardware_params.sample_rate();
106 buffer_size = media::AudioHardwareConfig::GetHighLatencyBufferSize(
107 sample_rate, hardware_params.frames_per_buffer());
108 }
109 #endif
110
111 // Create output parameters based on the audio hardware configuration for
112 // passing on to the output sink. Force to 16-bit output for now since we
113 // know that works everywhere; ChromeOS does not support other bit depths.
114 media::AudioParameters output_params(
115 media::AudioParameters::AUDIO_PCM_LOW_LATENCY, params.channel_layout(),
116 sample_rate, 16, buffer_size);
117 DCHECK(output_params.IsValid());
118
119 media::AudioRendererMixer* mixer = 166 media::AudioRendererMixer* mixer =
120 new media::AudioRendererMixer(output_params, sink); 167 new media::AudioRendererMixer(mixer_output_params, sink);
121 AudioRendererMixerReference mixer_reference = {mixer, 1, sink.get()}; 168 AudioRendererMixerReference mixer_reference = {mixer, 1, sink.get()};
122 mixers_[key] = mixer_reference; 169 mixers_[key] = mixer_reference;
170 DVLOG(1) << "GetMixer: mixer " << mixer << " latency " << latency
chcunningham 2016/06/22 04:34:07 nit: use __FUNCTION__. nit: can you format this l
o1ka 2016/06/23 16:36:15 Done.
171 << "\n input " << input_params.AsHumanReadableString() << "\noutput "
172 << mixer_output_params.AsHumanReadableString();
123 return mixer; 173 return mixer;
124 } 174 }
125 175
126 void AudioRendererMixerManager::ReturnMixer( 176 void AudioRendererMixerManager::ReturnMixer(
127 int source_render_frame_id, 177 const media::AudioRendererMixer* mixer) {
128 const media::AudioParameters& params,
129 const std::string& device_id,
130 const url::Origin& security_origin) {
131 const MixerKey key(source_render_frame_id, params, device_id,
132 security_origin);
133 base::AutoLock auto_lock(mixers_lock_); 178 base::AutoLock auto_lock(mixers_lock_);
134 179 AudioRendererMixerMap::iterator it = std::find_if(
135 AudioRendererMixerMap::iterator it = mixers_.find(key); 180 mixers_.begin(), mixers_.end(),
181 [mixer](const std::pair<MixerKey, AudioRendererMixerReference>& val) {
182 return val.second.mixer == mixer;
183 });
136 DCHECK(it != mixers_.end()); 184 DCHECK(it != mixers_.end());
137 185
138 // Only remove the mixer if AudioRendererMixerManager is the last owner. 186 // Only remove the mixer if AudioRendererMixerManager is the last owner.
139 it->second.ref_count--; 187 it->second.ref_count--;
140 if (it->second.ref_count == 0) { 188 if (it->second.ref_count == 0) {
141 // The mixer will be deleted now, so release the sink. 189 // The mixer will be deleted now, so release the sink.
142 sink_cache_->ReleaseSink(it->second.sink_ptr); 190 sink_cache_->ReleaseSink(it->second.sink_ptr);
143 delete it->second.mixer; 191 delete it->second.mixer;
144 mixers_.erase(it); 192 mixers_.erase(it);
145 } 193 }
146 } 194 }
147 195
148 media::OutputDeviceInfo AudioRendererMixerManager::GetOutputDeviceInfo( 196 media::OutputDeviceInfo AudioRendererMixerManager::GetOutputDeviceInfo(
149 int source_render_frame_id, 197 int source_render_frame_id,
150 int session_id, 198 int session_id,
151 const std::string& device_id, 199 const std::string& device_id,
152 const url::Origin& security_origin) { 200 const url::Origin& security_origin) {
153 return sink_cache_->GetSinkInfo(source_render_frame_id, session_id, device_id, 201 return sink_cache_->GetSinkInfo(source_render_frame_id, session_id, device_id,
154 security_origin); 202 security_origin);
155 } 203 }
156 204
157 AudioRendererMixerManager::MixerKey::MixerKey( 205 AudioRendererMixerManager::MixerKey::MixerKey(
158 int source_render_frame_id, 206 int source_render_frame_id,
159 const media::AudioParameters& params, 207 const media::AudioParameters& params,
208 media::AudioLatency::LatencyType latency,
160 const std::string& device_id, 209 const std::string& device_id,
161 const url::Origin& security_origin) 210 const url::Origin& security_origin)
162 : source_render_frame_id(source_render_frame_id), 211 : source_render_frame_id(source_render_frame_id),
163 params(params), 212 params(params),
213 latency(latency),
164 device_id(device_id), 214 device_id(device_id),
165 security_origin(security_origin) {} 215 security_origin(security_origin) {}
166 216
167 AudioRendererMixerManager::MixerKey::MixerKey(const MixerKey& other) = default; 217 AudioRendererMixerManager::MixerKey::MixerKey(const MixerKey& other) = default;
168 218
169 } // namespace content 219 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698