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

Side by Side Diff: media/base/audio_renderer_mixer.cc

Issue 2067863003: Mixing audio with different latency requirements (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: UMA fix, unit tests and compile error fixes on some platforms, review comments addressed Created 4 years, 5 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/base/audio_renderer_mixer.h" 5 #include "media/base/audio_renderer_mixer.h"
6 6
7 #include <cmath> 7 #include <cmath>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/bind_helpers.h" 10 #include "base/bind_helpers.h"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/memory/ptr_util.h" 12 #include "base/memory/ptr_util.h"
13 #include "base/metrics/histogram_macros.h"
13 14
14 namespace media { 15 namespace media {
15 16
16 enum { kPauseDelaySeconds = 10 }; 17 enum { kPauseDelaySeconds = 10 };
17 18
19 // Tracks the maximum value of a counter and logs it into a UMA histogram upon
20 // the destruciton. NOT thread-safe, make sure it is used under lock.
o1ka 2016/06/29 10:12:08 Fix the comment
o1ka 2016/06/29 13:57:31 Done.
21 class AudioRendererMixer::UMAMaxValueTracker {
22 public:
23 UMAMaxValueTracker(const UmaLogCallback& log_callback)
24 : log_callback_(log_callback), count_(0), max_count_(0) {}
25
26 ~UMAMaxValueTracker() {}
27
28 // Increments the counter, updates the maximum.
29 void Increment() {
30 ++count_;
31 if (max_count_ < count_) {
32 max_count_ = count_;
33 log_callback_.Run(max_count_);
34 }
35 }
36
37 // Decrements the counter.
38 void Decrement() { --count_; }
Henrik Grunell 2016/06/29 12:20:54 DCHECK greater than 0 before decrease?
o1ka 2016/06/29 13:57:31 Done.
39
40 private:
41 const UmaLogCallback log_callback_;
42 int count_;
43 int max_count_;
44 DISALLOW_COPY_AND_ASSIGN(UMAMaxValueTracker);
45 };
46
18 AudioRendererMixer::AudioRendererMixer(const AudioParameters& output_params, 47 AudioRendererMixer::AudioRendererMixer(const AudioParameters& output_params,
19 scoped_refptr<AudioRendererSink> sink) 48 scoped_refptr<AudioRendererSink> sink,
49 const UmaLogCallback& log_callback)
20 : output_params_(output_params), 50 : output_params_(output_params),
21 audio_sink_(std::move(sink)), 51 audio_sink_(std::move(sink)),
22 master_converter_(output_params, output_params, true), 52 master_converter_(output_params, output_params, true),
23 pause_delay_(base::TimeDelta::FromSeconds(kPauseDelaySeconds)), 53 pause_delay_(base::TimeDelta::FromSeconds(kPauseDelaySeconds)),
24 last_play_time_(base::TimeTicks::Now()), 54 last_play_time_(base::TimeTicks::Now()),
25 // Initialize |playing_| to true since Start() results in an auto-play. 55 // Initialize |playing_| to true since Start() results in an auto-play.
26 playing_(true) { 56 playing_(true),
57 input_count_tracker_(new UMAMaxValueTracker(log_callback)) {
27 DCHECK(audio_sink_); 58 DCHECK(audio_sink_);
28 audio_sink_->Initialize(output_params, this); 59 audio_sink_->Initialize(output_params, this);
29 audio_sink_->Start(); 60 audio_sink_->Start();
30 } 61 }
31 62
32 AudioRendererMixer::~AudioRendererMixer() { 63 AudioRendererMixer::~AudioRendererMixer() {
33 // AudioRendererSink must be stopped before mixer is destructed. 64 // AudioRendererSink must be stopped before mixer is destructed.
34 audio_sink_->Stop(); 65 audio_sink_->Stop();
35 66
36 // Ensure that all mixer inputs have removed themselves prior to destruction. 67 // Ensure that all mixer inputs have removed themselves prior to destruction.
(...skipping 26 matching lines...) Expand all
63 // size requests, disabling FIFO. 94 // size requests, disabling FIFO.
64 new LoopbackAudioConverter( 95 new LoopbackAudioConverter(
65 input_params, output_params_, true)))); 96 input_params, output_params_, true))));
66 converter = result.first; 97 converter = result.first;
67 98
68 // Add newly-created resampler as an input to the master mixer. 99 // Add newly-created resampler as an input to the master mixer.
69 master_converter_.AddInput(converter->second.get()); 100 master_converter_.AddInput(converter->second.get());
70 } 101 }
71 converter->second->AddInput(input); 102 converter->second->AddInput(input);
72 } 103 }
104
105 input_count_tracker_->Increment();
73 } 106 }
74 107
75 void AudioRendererMixer::RemoveMixerInput( 108 void AudioRendererMixer::RemoveMixerInput(
76 const AudioParameters& input_params, 109 const AudioParameters& input_params,
77 AudioConverter::InputCallback* input) { 110 AudioConverter::InputCallback* input) {
78 base::AutoLock auto_lock(lock_); 111 base::AutoLock auto_lock(lock_);
79 112
80 int input_sample_rate = input_params.sample_rate(); 113 int input_sample_rate = input_params.sample_rate();
81 if (is_master_sample_rate(input_sample_rate)) { 114 if (is_master_sample_rate(input_sample_rate)) {
82 master_converter_.RemoveInput(input); 115 master_converter_.RemoveInput(input);
83 } else { 116 } else {
84 AudioConvertersMap::iterator converter = 117 AudioConvertersMap::iterator converter =
85 converters_.find(input_sample_rate); 118 converters_.find(input_sample_rate);
86 DCHECK(converter != converters_.end()); 119 DCHECK(converter != converters_.end());
87 converter->second->RemoveInput(input); 120 converter->second->RemoveInput(input);
88 if (converter->second->empty()) { 121 if (converter->second->empty()) {
89 // Remove converter when it's empty. 122 // Remove converter when it's empty.
90 master_converter_.RemoveInput(converter->second.get()); 123 master_converter_.RemoveInput(converter->second.get());
91 converters_.erase(converter); 124 converters_.erase(converter);
92 } 125 }
93 } 126 }
127
128 input_count_tracker_->Decrement();
94 } 129 }
95 130
96 void AudioRendererMixer::AddErrorCallback(const base::Closure& error_cb) { 131 void AudioRendererMixer::AddErrorCallback(const base::Closure& error_cb) {
97 base::AutoLock auto_lock(lock_); 132 base::AutoLock auto_lock(lock_);
98 error_callbacks_.push_back(error_cb); 133 error_callbacks_.push_back(error_cb);
99 } 134 }
100 135
101 void AudioRendererMixer::RemoveErrorCallback(const base::Closure& error_cb) { 136 void AudioRendererMixer::RemoveErrorCallback(const base::Closure& error_cb) {
102 base::AutoLock auto_lock(lock_); 137 base::AutoLock auto_lock(lock_);
103 for (ErrorCallbackList::iterator it = error_callbacks_.begin(); 138 for (ErrorCallbackList::iterator it = error_callbacks_.begin();
(...skipping 11 matching lines...) Expand all
115 150
116 OutputDeviceInfo AudioRendererMixer::GetOutputDeviceInfo() { 151 OutputDeviceInfo AudioRendererMixer::GetOutputDeviceInfo() {
117 DVLOG(1) << __FUNCTION__; 152 DVLOG(1) << __FUNCTION__;
118 return audio_sink_->GetOutputDeviceInfo(); 153 return audio_sink_->GetOutputDeviceInfo();
119 } 154 }
120 155
121 bool AudioRendererMixer::CurrentThreadIsRenderingThread() { 156 bool AudioRendererMixer::CurrentThreadIsRenderingThread() {
122 return audio_sink_->CurrentThreadIsRenderingThread(); 157 return audio_sink_->CurrentThreadIsRenderingThread();
123 } 158 }
124 159
160 void AudioRendererMixer::LogLifetimeUmaStats() {
161 base::AutoLock auto_lock(lock_);
162 input_count_tracker_.reset();
163 };
164
125 int AudioRendererMixer::Render(AudioBus* audio_bus, 165 int AudioRendererMixer::Render(AudioBus* audio_bus,
126 uint32_t frames_delayed, 166 uint32_t frames_delayed,
127 uint32_t frames_skipped) { 167 uint32_t frames_skipped) {
128 base::AutoLock auto_lock(lock_); 168 base::AutoLock auto_lock(lock_);
129 169
130 // If there are no mixer inputs and we haven't seen one for a while, pause the 170 // If there are no mixer inputs and we haven't seen one for a while, pause the
131 // sink to avoid wasting resources when media elements are present but remain 171 // sink to avoid wasting resources when media elements are present but remain
132 // in the pause state. 172 // in the pause state.
133 const base::TimeTicks now = base::TimeTicks::Now(); 173 const base::TimeTicks now = base::TimeTicks::Now();
134 if (!master_converter_.empty()) { 174 if (!master_converter_.empty()) {
135 last_play_time_ = now; 175 last_play_time_ = now;
136 } else if (now - last_play_time_ >= pause_delay_ && playing_) { 176 } else if (now - last_play_time_ >= pause_delay_ && playing_) {
137 audio_sink_->Pause(); 177 audio_sink_->Pause();
138 playing_ = false; 178 playing_ = false;
139 } 179 }
140 180
141 master_converter_.ConvertWithDelay(frames_delayed, audio_bus); 181 master_converter_.ConvertWithDelay(frames_delayed, audio_bus);
142 return audio_bus->frames(); 182 return audio_bus->frames();
143 } 183 }
144 184
145 void AudioRendererMixer::OnRenderError() { 185 void AudioRendererMixer::OnRenderError() {
146 // Call each mixer input and signal an error. 186 // Call each mixer input and signal an error.
147 base::AutoLock auto_lock(lock_); 187 base::AutoLock auto_lock(lock_);
148 for (const auto& cb : error_callbacks_) 188 for (const auto& cb : error_callbacks_)
149 cb.Run(); 189 cb.Run();
150 } 190 }
151 191
152 } // namespace media 192 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698