OLD | NEW |
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/webaudio_capturer_source.h" | 5 #include "content/renderer/media/webaudio_media_stream_source.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "content/renderer/media/webrtc_local_audio_track.h" | |
11 | |
12 using media::AudioBus; | |
13 using media::AudioParameters; | |
14 using media::ChannelLayout; | |
15 using media::CHANNEL_LAYOUT_MONO; | |
16 using media::CHANNEL_LAYOUT_STEREO; | |
17 | 10 |
18 namespace content { | 11 namespace content { |
19 | 12 |
20 WebAudioCapturerSource::WebAudioCapturerSource( | 13 WebAudioMediaStreamSource::WebAudioMediaStreamSource( |
21 blink::WebMediaStreamSource* blink_source) | 14 blink::WebMediaStreamSource* blink_source) |
22 : track_(NULL), | 15 : MediaStreamAudioSource(false /* is_remote */), |
23 audio_format_changed_(false), | 16 is_registered_consumer_(false), |
24 fifo_(base::Bind(&WebAudioCapturerSource::DeliverRebufferedAudio, | 17 fifo_(base::Bind(&WebAudioMediaStreamSource::DeliverRebufferedAudio, |
25 base::Unretained(this))), | 18 base::Unretained(this))), |
26 blink_source_(*blink_source) { | 19 blink_source_(*blink_source) { |
27 DCHECK(blink_source); | 20 DVLOG(1) << "WebAudioMediaStreamSource::WebAudioMediaStreamSource()"; |
28 DCHECK(!blink_source_.isNull()); | |
29 DVLOG(1) << "WebAudioCapturerSource::WebAudioCapturerSource()"; | |
30 blink_source_.addAudioConsumer(this); | |
31 } | 21 } |
32 | 22 |
33 WebAudioCapturerSource::~WebAudioCapturerSource() { | 23 WebAudioMediaStreamSource::~WebAudioMediaStreamSource() { |
34 DCHECK(thread_checker_.CalledOnValidThread()); | 24 DVLOG(1) << "WebAudioMediaStreamSource::~WebAudioMediaStreamSource()"; |
35 DVLOG(1) << "WebAudioCapturerSource::~WebAudioCapturerSource()"; | 25 // Ensure the source is stopped. |
36 DeregisterFromBlinkSource(); | 26 MediaStreamAudioSource::StopSource(); |
37 } | 27 } |
38 | 28 |
39 void WebAudioCapturerSource::setFormat( | 29 void WebAudioMediaStreamSource::setFormat(size_t number_of_channels, |
40 size_t number_of_channels, float sample_rate) { | 30 float sample_rate) { |
41 DCHECK(thread_checker_.CalledOnValidThread()); | 31 DCHECK(thread_checker_.CalledOnValidThread()); |
42 DVLOG(1) << "WebAudioCapturerSource::setFormat(sample_rate=" | 32 VLOG(1) << "WebAudio media stream source changed format to: channels=" |
43 << sample_rate << ")"; | 33 << number_of_channels << ", sample_rate=" << sample_rate; |
44 | 34 |
45 // If the channel count is greater than 8, use discrete layout. However, | 35 // If the channel count is greater than 8, use discrete layout. However, |
46 // anything beyond 8 is ignored by the subsequent (WebRTC) audio pipeline. | 36 // anything beyond 8 is ignored by some audio tracks/sinks. |
47 ChannelLayout channel_layout = | 37 media::ChannelLayout channel_layout = |
48 number_of_channels > 8 ? media::CHANNEL_LAYOUT_DISCRETE | 38 number_of_channels > 8 ? media::CHANNEL_LAYOUT_DISCRETE |
49 : media::GuessChannelLayout(number_of_channels); | 39 : media::GuessChannelLayout(number_of_channels); |
50 | 40 |
51 base::AutoLock auto_lock(lock_); | 41 // Set the format used by this WebAudioMediaStreamSource. We are using 10ms |
| 42 // data as a buffer size since that is the native buffer size of WebRtc packet |
| 43 // running on. |
| 44 // |
| 45 // TODO(miu): Re-evaluate whether this is needed. For now (this refactoring), |
| 46 // I did not want to change behavior. http://crbug.com/577874 |
| 47 fifo_.Reset(sample_rate / 100); |
| 48 media::AudioParameters params(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, |
| 49 channel_layout, sample_rate, 16, |
| 50 fifo_.frames_per_buffer()); |
| 51 // Take care of the discrete channel layout case. |
| 52 params.set_channels_for_discrete(number_of_channels); |
| 53 MediaStreamAudioSource::SetFormat(params); |
52 | 54 |
53 // Set the format used by this WebAudioCapturerSource. We are using 10ms data | 55 if (!wrapper_bus_ || wrapper_bus_->channels() != params.channels()) |
54 // as buffer size since that is the native buffer size of WebRtc packet | 56 wrapper_bus_ = media::AudioBus::CreateWrapper(params.channels()); |
55 // running on. | |
56 fifo_.Reset(sample_rate / 100); | |
57 params_.Reset(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, | |
58 sample_rate, 16, fifo_.frames_per_buffer()); | |
59 | |
60 // Take care of the discrete channel layout case. | |
61 params_.set_channels_for_discrete(number_of_channels); | |
62 | |
63 audio_format_changed_ = true; | |
64 | |
65 if (!wrapper_bus_ || | |
66 wrapper_bus_->channels() != static_cast<int>(number_of_channels)) { | |
67 wrapper_bus_ = AudioBus::CreateWrapper(params_.channels()); | |
68 } | |
69 } | 57 } |
70 | 58 |
71 void WebAudioCapturerSource::Start(WebRtcLocalAudioTrack* track) { | 59 bool WebAudioMediaStreamSource::EnsureSourceIsStarted() { |
72 DCHECK(thread_checker_.CalledOnValidThread()); | 60 DCHECK(thread_checker_.CalledOnValidThread()); |
73 DCHECK(track); | 61 if (is_stopped_) |
74 base::AutoLock auto_lock(lock_); | 62 return false; |
75 track_ = track; | 63 if (is_registered_consumer_) |
| 64 return true; |
| 65 if (blink_source_.isNull() || !blink_source_.requiresAudioConsumer()) { |
| 66 StopSource(); |
| 67 return false; |
| 68 } |
| 69 VLOG(1) << "Starting WebAudio media stream source."; |
| 70 blink_source_.addAudioConsumer(this); |
| 71 is_registered_consumer_ = true; |
| 72 return true; |
76 } | 73 } |
77 | 74 |
78 void WebAudioCapturerSource::Stop() { | 75 void WebAudioMediaStreamSource::DoStopSource() { |
79 DCHECK(thread_checker_.CalledOnValidThread()); | 76 DCHECK(thread_checker_.CalledOnValidThread()); |
80 { | 77 if (is_stopped_) |
81 base::AutoLock auto_lock(lock_); | 78 return; |
82 track_ = NULL; | 79 if (is_registered_consumer_) { |
| 80 if (!blink_source_.isNull()) { |
| 81 blink_source_.removeAudioConsumer(this); |
| 82 blink_source_.reset(); |
| 83 is_registered_consumer_ = false; |
| 84 VLOG(1) << "Stopped WebAudio media stream source. Final audio " |
| 85 "parameters={" |
| 86 << GetAudioParameters().AsHumanReadableString() << "}."; |
| 87 } |
83 } | 88 } |
84 // DeregisterFromBlinkSource() should not be called while |lock_| is acquired, | 89 is_stopped_ = true; |
85 // as it could result in a deadlock. | |
86 DeregisterFromBlinkSource(); | |
87 } | 90 } |
88 | 91 |
89 void WebAudioCapturerSource::consumeAudio( | 92 void WebAudioMediaStreamSource::consumeAudio( |
90 const blink::WebVector<const float*>& audio_data, | 93 const blink::WebVector<const float*>& audio_data, |
91 size_t number_of_frames) { | 94 size_t number_of_frames) { |
92 // TODO(miu): Plumbing is needed to determine the actual capture timestamp | 95 // TODO(miu): Plumbing is needed to determine the actual capture timestamp |
93 // of the audio, instead of just snapshotting TimeTicks::Now(), for proper | 96 // of the audio, instead of just snapshotting TimeTicks::Now(), for proper |
94 // audio/video sync. http://crbug.com/335335 | 97 // audio/video sync. http://crbug.com/335335 |
95 current_reference_time_ = base::TimeTicks::Now(); | 98 current_reference_time_ = base::TimeTicks::Now(); |
96 | 99 |
97 base::AutoLock auto_lock(lock_); | |
98 if (!track_) | |
99 return; | |
100 | |
101 // Update the downstream client if the audio format has been changed. | |
102 if (audio_format_changed_) { | |
103 track_->OnSetFormat(params_); | |
104 audio_format_changed_ = false; | |
105 } | |
106 | |
107 wrapper_bus_->set_frames(number_of_frames); | 100 wrapper_bus_->set_frames(number_of_frames); |
108 DCHECK_EQ(params_.channels(), static_cast<int>(audio_data.size())); | 101 DCHECK_EQ(wrapper_bus_->channels(), static_cast<int>(audio_data.size())); |
109 for (size_t i = 0; i < audio_data.size(); ++i) | 102 for (size_t i = 0; i < audio_data.size(); ++i) |
110 wrapper_bus_->SetChannelData(i, const_cast<float*>(audio_data[i])); | 103 wrapper_bus_->SetChannelData(i, const_cast<float*>(audio_data[i])); |
111 | 104 |
112 // The following will result in zero, one, or multiple synchronous calls to | 105 // The following will result in zero, one, or multiple synchronous calls to |
113 // DeliverRebufferedAudio(). | 106 // DeliverRebufferedAudio(). |
114 fifo_.Push(*wrapper_bus_); | 107 fifo_.Push(*wrapper_bus_); |
115 } | 108 } |
116 | 109 |
117 void WebAudioCapturerSource::DeliverRebufferedAudio( | 110 void WebAudioMediaStreamSource::DeliverRebufferedAudio( |
118 const media::AudioBus& audio_bus, | 111 const media::AudioBus& audio_bus, |
119 int frame_delay) { | 112 int frame_delay) { |
120 lock_.AssertAcquired(); | |
121 const base::TimeTicks reference_time = | 113 const base::TimeTicks reference_time = |
122 current_reference_time_ + | 114 current_reference_time_ + |
123 base::TimeDelta::FromMicroseconds(frame_delay * | 115 base::TimeDelta::FromMicroseconds( |
124 base::Time::kMicrosecondsPerSecond / | 116 frame_delay * base::Time::kMicrosecondsPerSecond / |
125 params_.sample_rate()); | 117 MediaStreamAudioSource::GetAudioParameters().sample_rate()); |
126 track_->Capture(audio_bus, reference_time); | 118 MediaStreamAudioSource::DeliverDataToTracks(audio_bus, reference_time); |
127 } | |
128 | |
129 void WebAudioCapturerSource::DeregisterFromBlinkSource() { | |
130 if (!blink_source_.isNull()) { | |
131 blink_source_.removeAudioConsumer(this); | |
132 blink_source_.reset(); | |
133 } | |
134 } | 119 } |
135 | 120 |
136 } // namespace content | 121 } // namespace content |
OLD | NEW |