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