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