1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "third_party/blink/renderer/platform/mediastream/media_stream_audio_track.h"
6
7 #include <utility>
8
9 #include "base/check_op.h"
10 #include "base/strings/stringprintf.h"
11 #include "media/base/audio_bus.h"
12 #include "third_party/blink/public/platform/modules/mediastream/web_media_stream_audio_sink.h"
13 #include "third_party/blink/public/platform/modules/mediastream/web_media_stream_source.h"
14 #include "third_party/blink/public/platform/modules/webrtc/webrtc_logging.h"
15 #include "third_party/blink/renderer/platform/mediastream/media_stream_component.h"
16 #include "third_party/blink/renderer/platform/mediastream/media_stream_source.h"
17
18 namespace blink {
19
20 namespace {
21
SendLogMessage(const std::string & message)22 void SendLogMessage(const std::string& message) {
23 blink::WebRtcLogMessage("MSAT::" + message);
24 }
25
26 } // namespace
27
MediaStreamAudioTrack(bool is_local_track)28 MediaStreamAudioTrack::MediaStreamAudioTrack(bool is_local_track)
29 : MediaStreamTrackPlatform(is_local_track), is_enabled_(1) {
30 SendLogMessage(
31 base::StringPrintf("MediaStreamAudioTrack([this=%p] {is_local_track=%s})",
32 this, (is_local_track ? "true" : "false")));
33 }
34
~MediaStreamAudioTrack()35 MediaStreamAudioTrack::~MediaStreamAudioTrack() {
36 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
37 SendLogMessage(base::StringPrintf("~MediaStreamAudioTrack([this=%p])", this));
38 Stop();
39 }
40
41 // static
From(const MediaStreamComponent * component)42 MediaStreamAudioTrack* MediaStreamAudioTrack::From(
43 const MediaStreamComponent* component) {
44 if (!component ||
45 component->Source()->GetType() != MediaStreamSource::kTypeAudio) {
46 return nullptr;
47 }
48 return static_cast<MediaStreamAudioTrack*>(component->GetPlatformTrack());
49 }
50
AddSink(WebMediaStreamAudioSink * sink)51 void MediaStreamAudioTrack::AddSink(WebMediaStreamAudioSink* sink) {
52 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
53 SendLogMessage(base::StringPrintf("AddSink([this=%p])", this));
54
55 // If the track has already stopped, just notify the sink of this fact without
56 // adding it.
57 if (stop_callback_.is_null()) {
58 sink->OnReadyStateChanged(WebMediaStreamSource::kReadyStateEnded);
59 return;
60 }
61
62 deliverer_.AddConsumer(sink);
63 sink->OnEnabledChanged(!!base::subtle::NoBarrier_Load(&is_enabled_));
64 }
65
RemoveSink(WebMediaStreamAudioSink * sink)66 void MediaStreamAudioTrack::RemoveSink(WebMediaStreamAudioSink* sink) {
67 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
68 SendLogMessage(base::StringPrintf("RemoveSink([this=%p])", this));
69 deliverer_.RemoveConsumer(sink);
70 }
71
GetOutputFormat() const72 media::AudioParameters MediaStreamAudioTrack::GetOutputFormat() const {
73 return deliverer_.GetAudioParameters();
74 }
75
SetEnabled(bool enabled)76 void MediaStreamAudioTrack::SetEnabled(bool enabled) {
77 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
78 SendLogMessage(base::StringPrintf("SetEnabled([this=%p] {enabled=%s})", this,
79 (enabled ? "true" : "false")));
80
81 const bool previously_enabled =
82 !!base::subtle::NoBarrier_AtomicExchange(&is_enabled_, enabled ? 1 : 0);
83 if (enabled == previously_enabled)
84 return;
85
86 Vector<WebMediaStreamAudioSink*> sinks_to_notify;
87 deliverer_.GetConsumerList(&sinks_to_notify);
88 for (WebMediaStreamAudioSink* sink : sinks_to_notify)
89 sink->OnEnabledChanged(enabled);
90 }
91
SetContentHint(WebMediaStreamTrack::ContentHintType content_hint)92 void MediaStreamAudioTrack::SetContentHint(
93 WebMediaStreamTrack::ContentHintType content_hint) {
94 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
95
96 Vector<WebMediaStreamAudioSink*> sinks_to_notify;
97 deliverer_.GetConsumerList(&sinks_to_notify);
98 for (WebMediaStreamAudioSink* sink : sinks_to_notify)
99 sink->OnContentHintChanged(content_hint);
100 }
101
GetClassIdentifier() const102 void* MediaStreamAudioTrack::GetClassIdentifier() const {
103 return nullptr;
104 }
105
Start(base::OnceClosure stop_callback)106 void MediaStreamAudioTrack::Start(base::OnceClosure stop_callback) {
107 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
108 DCHECK(!stop_callback.is_null());
109 DCHECK(stop_callback_.is_null());
110 SendLogMessage(base::StringPrintf("Start([this=%p])", this));
111 stop_callback_ = std::move(stop_callback);
112 }
113
StopAndNotify(base::OnceClosure callback)114 void MediaStreamAudioTrack::StopAndNotify(base::OnceClosure callback) {
115 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
116 SendLogMessage(base::StringPrintf("StopAndNotify([this=%p])", this));
117
118 if (!stop_callback_.is_null())
119 std::move(stop_callback_).Run();
120
121 Vector<WebMediaStreamAudioSink*> sinks_to_end;
122 deliverer_.GetConsumerList(&sinks_to_end);
123 for (WebMediaStreamAudioSink* sink : sinks_to_end) {
124 deliverer_.RemoveConsumer(sink);
125 sink->OnReadyStateChanged(WebMediaStreamSource::kReadyStateEnded);
126 }
127
128 if (callback)
129 std::move(callback).Run();
130 weak_factory_.InvalidateWeakPtrs();
131 }
132
OnSetFormat(const media::AudioParameters & params)133 void MediaStreamAudioTrack::OnSetFormat(const media::AudioParameters& params) {
134 SendLogMessage(base::StringPrintf("OnSetFormat([this=%p] {params: [%s]})",
135 this,
136 params.AsHumanReadableString().c_str()));
137 deliverer_.OnSetFormat(params);
138 }
139
OnData(const media::AudioBus & audio_bus,base::TimeTicks reference_time)140 void MediaStreamAudioTrack::OnData(const media::AudioBus& audio_bus,
141 base::TimeTicks reference_time) {
142 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("mediastream"),
143 "MediaStreamAudioTrack::OnData");
144
145 if (!received_audio_callback_) {
146 // Add log message with unique this pointer id to mark the audio track as
147 // alive at the first data callback.
148 SendLogMessage(base::StringPrintf(
149 "OnData([this=%p] => (audio track is alive))", this));
150 received_audio_callback_ = true;
151 }
152
153 // Note: Using NoBarrier_Load because the timing of when the audio thread sees
154 // a changed |is_enabled_| value can be relaxed.
155 const bool deliver_data = !!base::subtle::NoBarrier_Load(&is_enabled_);
156
157 if (deliver_data) {
158 deliverer_.OnData(audio_bus, reference_time);
159 } else {
160 // The W3C spec requires silent audio to flow while a track is disabled.
161 if (!silent_bus_ || silent_bus_->channels() != audio_bus.channels() ||
162 silent_bus_->frames() != audio_bus.frames()) {
163 silent_bus_ =
164 media::AudioBus::Create(audio_bus.channels(), audio_bus.frames());
165 silent_bus_->Zero();
166 }
167 deliverer_.OnData(*silent_bus_, reference_time);
168 }
169 }
170
171 } // namespace blink
172