OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 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/pepper/pepper_media_stream_audio_track_host.h" | 5 #include "content/renderer/pepper/pepper_media_stream_audio_track_host.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/location.h" | 10 #include "base/location.h" |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
58 } | 58 } |
59 | 59 |
60 } // namespace | 60 } // namespace |
61 | 61 |
62 namespace content { | 62 namespace content { |
63 | 63 |
64 PepperMediaStreamAudioTrackHost::AudioSink::AudioSink( | 64 PepperMediaStreamAudioTrackHost::AudioSink::AudioSink( |
65 PepperMediaStreamAudioTrackHost* host) | 65 PepperMediaStreamAudioTrackHost* host) |
66 : host_(host), | 66 : host_(host), |
67 buffer_data_size_(0), | 67 buffer_data_size_(0), |
68 init_buffers_count_(0), | |
68 main_message_loop_proxy_(base::MessageLoopProxy::current()), | 69 main_message_loop_proxy_(base::MessageLoopProxy::current()), |
69 weak_factory_(this), | 70 weak_factory_(this), |
70 number_of_buffers_(kDefaultNumberOfBuffers), | 71 number_of_buffers_(kDefaultNumberOfBuffers), |
71 bytes_per_second_(0) {} | 72 bytes_per_second_(0) {} |
72 | 73 |
73 PepperMediaStreamAudioTrackHost::AudioSink::~AudioSink() { | 74 PepperMediaStreamAudioTrackHost::AudioSink::~AudioSink() { |
74 DCHECK_EQ(main_message_loop_proxy_, base::MessageLoopProxy::current()); | 75 DCHECK_EQ(main_message_loop_proxy_, base::MessageLoopProxy::current()); |
75 } | 76 } |
76 | 77 |
77 void PepperMediaStreamAudioTrackHost::AudioSink::EnqueueBuffer(int32_t index) { | 78 void PepperMediaStreamAudioTrackHost::AudioSink::EnqueueBuffer(int32_t index) { |
(...skipping 18 matching lines...) Expand all Loading... | |
96 } | 97 } |
97 | 98 |
98 void PepperMediaStreamAudioTrackHost::AudioSink::SetFormatOnMainThread( | 99 void PepperMediaStreamAudioTrackHost::AudioSink::SetFormatOnMainThread( |
99 int bytes_per_second) { | 100 int bytes_per_second) { |
100 bytes_per_second_ = bytes_per_second; | 101 bytes_per_second_ = bytes_per_second; |
101 InitBuffers(); | 102 InitBuffers(); |
102 } | 103 } |
103 | 104 |
104 void PepperMediaStreamAudioTrackHost::AudioSink::InitBuffers() { | 105 void PepperMediaStreamAudioTrackHost::AudioSink::InitBuffers() { |
105 DCHECK_EQ(main_message_loop_proxy_, base::MessageLoopProxy::current()); | 106 DCHECK_EQ(main_message_loop_proxy_, base::MessageLoopProxy::current()); |
107 { | |
108 base::AutoLock lock(lock_); | |
109 // Clear |buffers_|, so the audio thread will drop all incoming audio data. | |
110 buffers_.clear(); | |
111 init_buffers_count_++; | |
112 } | |
106 // The size is slightly bigger than necessary, because 8 extra bytes are | 113 // The size is slightly bigger than necessary, because 8 extra bytes are |
107 // added into the struct. Also see |MediaStreamBuffer|. | 114 // added into the struct. Also see |MediaStreamBuffer|. |
108 base::CheckedNumeric<int32_t> buffer_size = bytes_per_second_; | 115 base::CheckedNumeric<int32_t> buffer_size = bytes_per_second_; |
109 buffer_size *= kMaxDuration; | 116 buffer_size *= kMaxDuration; |
110 buffer_size /= base::Time::kMillisecondsPerSecond; | 117 buffer_size /= base::Time::kMillisecondsPerSecond; |
111 buffer_size += sizeof(ppapi::MediaStreamBuffer::Audio); | 118 buffer_size += sizeof(ppapi::MediaStreamBuffer::Audio); |
119 | |
120 // We don't need hold |lock_| during |host->InitBuffers()| call, because | |
dmichael (off chromium)
2014/07/24 16:42:56
need +to+ hold
Peng
2014/07/25 15:25:31
Done.
| |
121 // we just cleared |buffers_| , so the audio thread will drop all incoming | |
122 // audio data, and not use buffers in |host_|. | |
112 bool result = host_->InitBuffers(number_of_buffers_, | 123 bool result = host_->InitBuffers(number_of_buffers_, |
113 buffer_size.ValueOrDie(), | 124 buffer_size.ValueOrDie(), |
114 kRead); | 125 kRead); |
115 // TODO(penghuang): Send PP_ERROR_NOMEMORY to plugin. | 126 // TODO(penghuang): Send PP_ERROR_NOMEMORY to plugin. |
116 CHECK(result); | 127 CHECK(result); |
128 | |
129 // Fill the |buffers_|, so the audio thread can continue receiving audio data. | |
117 base::AutoLock lock(lock_); | 130 base::AutoLock lock(lock_); |
118 buffers_.clear(); | |
119 for (int32_t i = 0; i < number_of_buffers_; ++i) { | 131 for (int32_t i = 0; i < number_of_buffers_; ++i) { |
120 int32_t index = host_->buffer_manager()->DequeueBuffer(); | 132 int32_t index = host_->buffer_manager()->DequeueBuffer(); |
121 DCHECK_GE(index, 0); | 133 DCHECK_GE(index, 0); |
122 buffers_.push_back(index); | 134 buffers_.push_back(index); |
123 } | 135 } |
124 } | 136 } |
125 | 137 |
126 void PepperMediaStreamAudioTrackHost::AudioSink:: | 138 void PepperMediaStreamAudioTrackHost::AudioSink:: |
127 SendEnqueueBufferMessageOnMainThread(int32_t index) { | 139 SendEnqueueBufferMessageOnMainThread(int32_t index, |
140 int32_t init_buffers_count) { | |
128 DCHECK_EQ(main_message_loop_proxy_, base::MessageLoopProxy::current()); | 141 DCHECK_EQ(main_message_loop_proxy_, base::MessageLoopProxy::current()); |
129 host_->SendEnqueueBufferMessageToPlugin(index); | 142 // If |InitBuffers()| is called after this task being posted from the audio |
143 // thread, the buffer should become invalid already. We should ignore it. | |
144 // And because only the main thread modifies the |init_buffers_count_|, | |
145 // so we don't need lock |lock_| here (main thread). | |
Anand Mistry (off Chromium)
2014/07/25 00:42:54
Although I'll agree this is a benign read, I think
Peng
2014/07/25 15:25:31
I think rwlock is better for this case, but I can
dmichael (off chromium)
2014/07/28 19:30:43
I don't think TSAN will flag it; I think it's fine
| |
146 if (init_buffers_count == init_buffers_count_) | |
147 host_->SendEnqueueBufferMessageToPlugin(index); | |
130 } | 148 } |
131 | 149 |
132 void PepperMediaStreamAudioTrackHost::AudioSink::OnData(const int16* audio_data, | 150 void PepperMediaStreamAudioTrackHost::AudioSink::OnData(const int16* audio_data, |
133 int sample_rate, | 151 int sample_rate, |
134 int number_of_channels, | 152 int number_of_channels, |
135 int number_of_frames) { | 153 int number_of_frames) { |
136 DCHECK(audio_thread_checker_.CalledOnValidThread()); | 154 DCHECK(audio_thread_checker_.CalledOnValidThread()); |
137 DCHECK(audio_data); | 155 DCHECK(audio_data); |
138 DCHECK_EQ(sample_rate, audio_params_.sample_rate()); | 156 DCHECK_EQ(sample_rate, audio_params_.sample_rate()); |
139 DCHECK_EQ(number_of_channels, audio_params_.channels()); | 157 DCHECK_EQ(number_of_channels, audio_params_.channels()); |
140 DCHECK_EQ(number_of_frames, audio_params_.frames_per_buffer()); | 158 DCHECK_EQ(number_of_frames, audio_params_.frames_per_buffer()); |
141 int32_t index = -1; | |
142 { | |
143 base::AutoLock lock(lock_); | |
144 if (!buffers_.empty()) { | |
145 index = buffers_.front(); | |
146 buffers_.pop_front(); | |
147 } | |
148 } | |
149 | 159 |
150 if (index != -1) { | 160 base::AutoLock lock(lock_); |
161 if (!buffers_.empty()) { | |
162 int index = buffers_.front(); | |
163 buffers_.pop_front(); | |
151 // TODO(penghuang): support re-sampling, etc. | 164 // TODO(penghuang): support re-sampling, etc. |
152 ppapi::MediaStreamBuffer::Audio* buffer = | 165 ppapi::MediaStreamBuffer::Audio* buffer = |
153 &(host_->buffer_manager()->GetBufferPointer(index)->audio); | 166 &(host_->buffer_manager()->GetBufferPointer(index)->audio); |
154 buffer->header.size = host_->buffer_manager()->buffer_size(); | 167 buffer->header.size = host_->buffer_manager()->buffer_size(); |
155 buffer->header.type = ppapi::MediaStreamBuffer::TYPE_AUDIO; | 168 buffer->header.type = ppapi::MediaStreamBuffer::TYPE_AUDIO; |
156 buffer->timestamp = timestamp_.InMillisecondsF(); | 169 buffer->timestamp = timestamp_.InMillisecondsF(); |
157 buffer->sample_rate = static_cast<PP_AudioBuffer_SampleRate>(sample_rate); | 170 buffer->sample_rate = static_cast<PP_AudioBuffer_SampleRate>(sample_rate); |
158 buffer->number_of_channels = number_of_channels; | 171 buffer->number_of_channels = number_of_channels; |
159 buffer->number_of_samples = number_of_channels * number_of_frames; | 172 buffer->number_of_samples = number_of_channels * number_of_frames; |
160 buffer->data_size = buffer_data_size_; | 173 buffer->data_size = buffer_data_size_; |
161 memcpy(buffer->data, audio_data, buffer_data_size_); | 174 memcpy(buffer->data, audio_data, buffer_data_size_); |
162 | 175 |
163 main_message_loop_proxy_->PostTask( | 176 main_message_loop_proxy_->PostTask( |
164 FROM_HERE, | 177 FROM_HERE, |
165 base::Bind(&AudioSink::SendEnqueueBufferMessageOnMainThread, | 178 base::Bind(&AudioSink::SendEnqueueBufferMessageOnMainThread, |
166 weak_factory_.GetWeakPtr(), | 179 weak_factory_.GetWeakPtr(), |
167 index)); | 180 index, |
181 init_buffers_count_)); | |
168 } | 182 } |
169 timestamp_ += buffer_duration_; | 183 timestamp_ += buffer_duration_; |
170 } | 184 } |
171 | 185 |
172 void PepperMediaStreamAudioTrackHost::AudioSink::OnSetFormat( | 186 void PepperMediaStreamAudioTrackHost::AudioSink::OnSetFormat( |
173 const AudioParameters& params) { | 187 const AudioParameters& params) { |
174 DCHECK(params.IsValid()); | 188 DCHECK(params.IsValid()); |
175 DCHECK_LE(params.GetBufferDuration().InMilliseconds(), kMaxDuration); | 189 DCHECK_LE(params.GetBufferDuration().InMilliseconds(), kMaxDuration); |
176 DCHECK_EQ(params.bits_per_sample(), 16); | 190 DCHECK_EQ(params.bits_per_sample(), 16); |
177 DCHECK_NE(GetPPSampleRate(params.sample_rate()), | 191 DCHECK_NE(GetPPSampleRate(params.sample_rate()), |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
256 } | 270 } |
257 | 271 |
258 void PepperMediaStreamAudioTrackHost::DidConnectPendingHostToResource() { | 272 void PepperMediaStreamAudioTrackHost::DidConnectPendingHostToResource() { |
259 if (!connected_) { | 273 if (!connected_) { |
260 MediaStreamAudioSink::AddToAudioTrack(&audio_sink_, track_); | 274 MediaStreamAudioSink::AddToAudioTrack(&audio_sink_, track_); |
261 connected_ = true; | 275 connected_ = true; |
262 } | 276 } |
263 } | 277 } |
264 | 278 |
265 } // namespace content | 279 } // namespace content |
OLD | NEW |