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

Side by Side Diff: content/renderer/media/webrtc/webrtc_audio_sink.cc

Issue 1834323002: MediaStream audio: Refactor 3 separate "glue" implementations into one. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: REBASE + Workaround to ensure MediaStreamAudioProcessor is destroyed on the main thread. 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
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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/webrtc/webrtc_local_audio_track_adapter.h" 5 #include "content/renderer/media/webrtc/webrtc_audio_sink.h"
6 6
7 #include <algorithm>
8 #include <limits>
9
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
7 #include "base/location.h" 12 #include "base/location.h"
8 #include "base/logging.h" 13 #include "base/logging.h"
9 #include "content/renderer/media/media_stream_audio_processor.h" 14 #include "base/message_loop/message_loop.h"
10 #include "content/renderer/media/webrtc/peer_connection_dependency_factory.h"
11 #include "content/renderer/media/webrtc/webrtc_audio_sink_adapter.h"
12 #include "content/renderer/media/webrtc_local_audio_track.h"
13 #include "content/renderer/render_thread_impl.h"
14 #include "third_party/webrtc/api/mediastreaminterface.h"
15 15
16 namespace content { 16 namespace content {
17 17
18 static const char kAudioTrackKind[] = "audio"; 18 WebRtcAudioSink::WebRtcAudioSink(
19
20 scoped_refptr<WebRtcLocalAudioTrackAdapter>
21 WebRtcLocalAudioTrackAdapter::Create(
22 const std::string& label, 19 const std::string& label,
23 webrtc::AudioSourceInterface* track_source) { 20 scoped_refptr<webrtc::AudioSourceInterface> track_source,
24 // TODO(tommi): Change this so that the signaling thread is one of the 21 scoped_refptr<base::SingleThreadTaskRunner> signaling_task_runner)
25 // parameters to this method. 22 : adapter_(new rtc::RefCountedObject<Adapter>(
26 scoped_refptr<base::SingleThreadTaskRunner> signaling_task_runner; 23 label, std::move(track_source), std::move(signaling_task_runner))),
27 RenderThreadImpl* current = RenderThreadImpl::current(); 24 fifo_(base::Bind(&WebRtcAudioSink::DeliverRebufferedAudio,
28 if (current) { 25 base::Unretained(this))) {
29 PeerConnectionDependencyFactory* pc_factory = 26 DVLOG(1) << "WebRtcAudioSink::WebRtcAudioSink()";
30 current->GetPeerConnectionDependencyFactory();
31 signaling_task_runner = pc_factory->GetWebRtcSignalingThread();
32 LOG_IF(ERROR, !signaling_task_runner) << "No signaling thread!";
33 } else {
34 LOG(WARNING) << "Assuming single-threaded operation for unit test.";
35 }
36
37 rtc::RefCountedObject<WebRtcLocalAudioTrackAdapter>* adapter =
38 new rtc::RefCountedObject<WebRtcLocalAudioTrackAdapter>(
39 label, track_source, std::move(signaling_task_runner));
40 return adapter;
41 } 27 }
42 28
43 WebRtcLocalAudioTrackAdapter::WebRtcLocalAudioTrackAdapter( 29 WebRtcAudioSink::~WebRtcAudioSink() {
30 DCHECK(thread_checker_.CalledOnValidThread());
31 DVLOG(1) << "WebRtcAudioSink::~WebRtcAudioSink()";
32 }
33
34 void WebRtcAudioSink::SetAudioProcessor(
35 scoped_refptr<MediaStreamAudioProcessor> processor) {
36 DCHECK(thread_checker_.CalledOnValidThread());
37 DCHECK(processor.get());
38 adapter_->set_processor(std::move(processor));
39 }
40
41 void WebRtcAudioSink::SetLevel(
42 scoped_refptr<MediaStreamAudioLevelCalculator::Level> level) {
43 DCHECK(thread_checker_.CalledOnValidThread());
44 DCHECK(level.get());
45 adapter_->set_level(std::move(level));
46 }
47
48 void WebRtcAudioSink::OnEnabledChanged(bool enabled) {
49 DCHECK(thread_checker_.CalledOnValidThread());
50 adapter_->signaling_task_runner()->PostTask(
51 FROM_HERE,
52 base::Bind(
53 base::IgnoreResult(&WebRtcAudioSink::Adapter::set_enabled),
54 adapter_, enabled));
55 }
56
57 void WebRtcAudioSink::OnData(const media::AudioBus& audio_bus,
58 base::TimeTicks estimated_capture_time) {
59 DCHECK(audio_thread_checker_.CalledOnValidThread());
60 // The following will result in zero, one, or multiple synchronous calls to
61 // DeliverRebufferedAudio().
62 fifo_.Push(audio_bus);
63 }
64
65 void WebRtcAudioSink::OnSetFormat(const media::AudioParameters& params) {
66 // On a format change, the thread delivering audio might have also changed.
67 audio_thread_checker_.DetachFromThread();
68 DCHECK(audio_thread_checker_.CalledOnValidThread());
69
70 DCHECK(params.IsValid());
71 params_ = params;
72 fifo_.Reset(params_.frames_per_buffer());
73 const int num_pcm16_data_elements =
74 params_.frames_per_buffer() * params_.channels();
75 interleaved_data_.reset(new int16_t[num_pcm16_data_elements]);
76 }
77
78 void WebRtcAudioSink::DeliverRebufferedAudio(const media::AudioBus& audio_bus,
79 int frame_delay) {
80 DCHECK(audio_thread_checker_.CalledOnValidThread());
81 DCHECK(params_.IsValid());
82
83 // TODO(miu): Why doesn't a WebRTC sink care about reference time passed to
84 // OnData(), and the |frame_delay| here? How is AV sync achieved otherwise?
85
86 // TODO(henrika): Remove this conversion once the interface in libjingle
87 // supports float vectors.
88 audio_bus.ToInterleaved(audio_bus.frames(),
89 sizeof(interleaved_data_[0]),
90 interleaved_data_.get());
91 adapter_->DeliverPCMToWebRtcSinks(interleaved_data_.get(),
92 params_.sample_rate(),
93 audio_bus.channels(),
94 audio_bus.frames());
95 }
96
97 namespace {
98 // TODO(miu): MediaStreamAudioProcessor destructor requires this nonsense.
99 void DereferenceOnMainThread(
100 const scoped_refptr<MediaStreamAudioProcessor>& processor) {}
101 } // namespace
102
103 WebRtcAudioSink::Adapter::Adapter(
44 const std::string& label, 104 const std::string& label,
45 webrtc::AudioSourceInterface* track_source, 105 scoped_refptr<webrtc::AudioSourceInterface> source,
46 scoped_refptr<base::SingleThreadTaskRunner> signaling_task_runner) 106 scoped_refptr<base::SingleThreadTaskRunner> signaling_task_runner)
47 : webrtc::MediaStreamTrack<webrtc::AudioTrackInterface>(label), 107 : webrtc::MediaStreamTrack<webrtc::AudioTrackInterface>(label),
48 owner_(NULL), 108 source_(std::move(source)),
49 track_source_(track_source), 109 signaling_task_runner_(std::move(signaling_task_runner)),
50 signaling_task_runner_(std::move(signaling_task_runner)) {} 110 main_task_runner_(base::MessageLoop::current()->task_runner()) {
51 111 DCHECK(signaling_task_runner_);
52 WebRtcLocalAudioTrackAdapter::~WebRtcLocalAudioTrackAdapter() {
53 } 112 }
54 113
55 void WebRtcLocalAudioTrackAdapter::Initialize(WebRtcLocalAudioTrack* owner) { 114 WebRtcAudioSink::Adapter::~Adapter() {
56 DCHECK(!owner_); 115 if (audio_processor_) {
57 DCHECK(owner); 116 main_task_runner_->PostTask(
58 owner_ = owner; 117 FROM_HERE,
118 base::Bind(&DereferenceOnMainThread, std::move(audio_processor_)));
119 }
59 } 120 }
60 121
61 void WebRtcLocalAudioTrackAdapter::SetAudioProcessor( 122 void WebRtcAudioSink::Adapter::DeliverPCMToWebRtcSinks(
62 scoped_refptr<MediaStreamAudioProcessor> processor) { 123 const int16_t* audio_data,
63 DCHECK(processor.get()); 124 int sample_rate,
64 DCHECK(!audio_processor_); 125 size_t number_of_channels,
65 audio_processor_ = std::move(processor); 126 size_t number_of_frames) {
127 base::AutoLock auto_lock(lock_);
128 for (webrtc::AudioTrackSinkInterface* sink : sinks_) {
129 sink->OnData(audio_data, sizeof(int16_t) * 8, sample_rate,
130 number_of_channels, number_of_frames);
131 }
66 } 132 }
67 133
68 void WebRtcLocalAudioTrackAdapter::SetLevel( 134 std::string WebRtcAudioSink::Adapter::kind() const {
69 scoped_refptr<MediaStreamAudioLevelCalculator::Level> level) { 135 return webrtc::MediaStreamTrackInterface::kAudioKind;
70 DCHECK(level.get());
71 DCHECK(!level_);
72 level_ = std::move(level);
73 } 136 }
74 137
75 std::string WebRtcLocalAudioTrackAdapter::kind() const { 138 bool WebRtcAudioSink::Adapter::set_enabled(bool enable) {
76 return kAudioTrackKind; 139 DCHECK(!signaling_task_runner_ ||
77 } 140 signaling_task_runner_->RunsTasksOnCurrentThread());
78
79 bool WebRtcLocalAudioTrackAdapter::set_enabled(bool enable) {
80 // If we're not called on the signaling thread, we need to post a task to
81 // change the state on the correct thread.
82 if (signaling_task_runner_ &&
83 !signaling_task_runner_->BelongsToCurrentThread()) {
84 signaling_task_runner_->PostTask(FROM_HERE,
85 base::Bind(
86 base::IgnoreResult(&WebRtcLocalAudioTrackAdapter::set_enabled),
87 this, enable));
88 return true;
89 }
90
91 return webrtc::MediaStreamTrack<webrtc::AudioTrackInterface>:: 141 return webrtc::MediaStreamTrack<webrtc::AudioTrackInterface>::
92 set_enabled(enable); 142 set_enabled(enable);
93 } 143 }
94 144
95 void WebRtcLocalAudioTrackAdapter::AddSink( 145 void WebRtcAudioSink::Adapter::AddSink(webrtc::AudioTrackSinkInterface* sink) {
146 DCHECK(!signaling_task_runner_ ||
147 signaling_task_runner_->RunsTasksOnCurrentThread());
148 DCHECK(sink);
149 base::AutoLock auto_lock(lock_);
150 DCHECK(std::find(sinks_.begin(), sinks_.end(), sink) == sinks_.end());
151 sinks_.push_back(sink);
152 }
153
154 void WebRtcAudioSink::Adapter::RemoveSink(
96 webrtc::AudioTrackSinkInterface* sink) { 155 webrtc::AudioTrackSinkInterface* sink) {
97 DCHECK(!signaling_task_runner_ || 156 DCHECK(!signaling_task_runner_ ||
98 signaling_task_runner_->RunsTasksOnCurrentThread()); 157 signaling_task_runner_->RunsTasksOnCurrentThread());
99 DCHECK(sink); 158 base::AutoLock auto_lock(lock_);
100 #ifndef NDEBUG 159 const auto it = std::find(sinks_.begin(), sinks_.end(), sink);
101 // Verify that |sink| has not been added. 160 if (it != sinks_.end())
102 for (ScopedVector<WebRtcAudioSinkAdapter>::const_iterator it = 161 sinks_.erase(it);
103 sink_adapters_.begin();
104 it != sink_adapters_.end(); ++it) {
105 DCHECK(!(*it)->IsEqual(sink));
106 }
107 #endif
108
109 std::unique_ptr<WebRtcAudioSinkAdapter> adapter(
110 new WebRtcAudioSinkAdapter(sink));
111 owner_->AddSink(adapter.get());
112 sink_adapters_.push_back(adapter.release());
113 } 162 }
114 163
115 void WebRtcLocalAudioTrackAdapter::RemoveSink( 164 bool WebRtcAudioSink::Adapter::GetSignalLevel(int* level) {
116 webrtc::AudioTrackSinkInterface* sink) {
117 DCHECK(!signaling_task_runner_ ||
118 signaling_task_runner_->RunsTasksOnCurrentThread());
119 DCHECK(sink);
120 for (ScopedVector<WebRtcAudioSinkAdapter>::iterator it =
121 sink_adapters_.begin();
122 it != sink_adapters_.end(); ++it) {
123 if ((*it)->IsEqual(sink)) {
124 owner_->RemoveSink(*it);
125 sink_adapters_.erase(it);
126 return;
127 }
128 }
129 }
130
131 bool WebRtcLocalAudioTrackAdapter::GetSignalLevel(int* level) {
132 DCHECK(!signaling_task_runner_ || 165 DCHECK(!signaling_task_runner_ ||
133 signaling_task_runner_->RunsTasksOnCurrentThread()); 166 signaling_task_runner_->RunsTasksOnCurrentThread());
134 167
135 // |level_| is only set once, so it's safe to read without first acquiring a 168 // |level_| is only set once, so it's safe to read without first acquiring a
136 // mutex. 169 // mutex.
137 if (!level_) 170 if (!level_)
138 return false; 171 return false;
139 const float signal_level = level_->GetCurrent(); 172 const float signal_level = level_->GetCurrent();
140 DCHECK_GE(signal_level, 0.0f); 173 DCHECK_GE(signal_level, 0.0f);
141 DCHECK_LE(signal_level, 1.0f); 174 DCHECK_LE(signal_level, 1.0f);
142 // Convert from float in range [0.0,1.0] to an int in range [0,32767]. 175 // Convert from float in range [0.0,1.0] to an int in range [0,32767].
143 *level = static_cast<int>(signal_level * std::numeric_limits<int16_t>::max() + 176 *level = static_cast<int>(signal_level * std::numeric_limits<int16_t>::max() +
144 0.5f /* rounding to nearest int */); 177 0.5f /* rounding to nearest int */);
145 return true; 178 return true;
146 } 179 }
147 180
148 rtc::scoped_refptr<webrtc::AudioProcessorInterface> 181 rtc::scoped_refptr<webrtc::AudioProcessorInterface>
149 WebRtcLocalAudioTrackAdapter::GetAudioProcessor() { 182 WebRtcAudioSink::Adapter::GetAudioProcessor() {
150 DCHECK(!signaling_task_runner_ || 183 DCHECK(!signaling_task_runner_ ||
151 signaling_task_runner_->RunsTasksOnCurrentThread()); 184 signaling_task_runner_->RunsTasksOnCurrentThread());
152 return audio_processor_.get(); 185 return audio_processor_.get();
153 } 186 }
154 187
155 webrtc::AudioSourceInterface* WebRtcLocalAudioTrackAdapter::GetSource() const { 188 webrtc::AudioSourceInterface* WebRtcAudioSink::Adapter::GetSource() const {
156 DCHECK(!signaling_task_runner_ || 189 DCHECK(!signaling_task_runner_ ||
157 signaling_task_runner_->RunsTasksOnCurrentThread()); 190 signaling_task_runner_->RunsTasksOnCurrentThread());
158 return track_source_; 191 return source_.get();
159 } 192 }
160 193
161 } // namespace content 194 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/media/webrtc/webrtc_audio_sink.h ('k') | content/renderer/media/webrtc/webrtc_audio_sink_adapter.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698