OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "chrome/renderer/media/cast_rtp_stream.h" | 5 #include "chrome/renderer/media/cast_rtp_stream.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/memory/weak_ptr.h" | 9 #include "base/memory/weak_ptr.h" |
10 #include "chrome/renderer/media/cast_session.h" | 10 #include "chrome/renderer/media/cast_session.h" |
11 #include "chrome/renderer/media/cast_udp_transport.h" | 11 #include "chrome/renderer/media/cast_udp_transport.h" |
12 #include "content/public/renderer/media_stream_audio_sink.h" | 12 #include "content/public/renderer/media_stream_audio_sink.h" |
13 #include "content/public/renderer/media_stream_video_sink.h" | 13 #include "content/public/renderer/media_stream_video_sink.h" |
14 #include "content/public/renderer/render_thread.h" | 14 #include "content/public/renderer/render_thread.h" |
15 #include "media/audio/audio_parameters.h" | |
15 #include "media/base/audio_bus.h" | 16 #include "media/base/audio_bus.h" |
16 #include "media/base/bind_to_current_loop.h" | 17 #include "media/base/bind_to_current_loop.h" |
18 #include "media/base/multi_channel_resampler.h" | |
17 #include "media/cast/cast_config.h" | 19 #include "media/cast/cast_config.h" |
18 #include "media/cast/cast_defines.h" | 20 #include "media/cast/cast_defines.h" |
19 #include "media/cast/cast_sender.h" | 21 #include "media/cast/cast_sender.h" |
20 #include "media/cast/transport/cast_transport_config.h" | 22 #include "media/cast/transport/cast_transport_config.h" |
21 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h" | 23 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h" |
22 | 24 |
23 using media::cast::AudioSenderConfig; | 25 using media::cast::AudioSenderConfig; |
24 using media::cast::VideoSenderConfig; | 26 using media::cast::VideoSenderConfig; |
25 | 27 |
26 namespace { | 28 namespace { |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
167 // Receives audio data from a MediaStreamTrack. Data is submitted to | 169 // Receives audio data from a MediaStreamTrack. Data is submitted to |
168 // media::cast::FrameInput. | 170 // media::cast::FrameInput. |
169 // | 171 // |
170 // Threading: Audio frames are received on the real-time audio thread. | 172 // Threading: Audio frames are received on the real-time audio thread. |
171 class CastAudioSink : public base::SupportsWeakPtr<CastAudioSink>, | 173 class CastAudioSink : public base::SupportsWeakPtr<CastAudioSink>, |
172 public content::MediaStreamAudioSink { | 174 public content::MediaStreamAudioSink { |
173 public: | 175 public: |
174 // |track| provides data for this sink. | 176 // |track| provides data for this sink. |
175 // |error_callback| is called if audio formats don't match. | 177 // |error_callback| is called if audio formats don't match. |
176 CastAudioSink(const blink::WebMediaStreamTrack& track, | 178 CastAudioSink(const blink::WebMediaStreamTrack& track, |
177 const CastRtpStream::ErrorCallback& error_callback) | 179 const CastRtpStream::ErrorCallback& error_callback, |
180 int output_channels, | |
181 int output_sample_rate) | |
178 : track_(track), | 182 : track_(track), |
179 sink_added_(false), | 183 sink_added_(false), |
180 error_callback_(error_callback), | 184 error_callback_(error_callback), |
181 weak_factory_(this), | 185 weak_factory_(this), |
182 render_thread_task_runner_(content::RenderThread::Get() | 186 render_thread_task_runner_(content::RenderThread::Get() |
183 ->GetMessageLoop() | 187 ->GetMessageLoop() |
184 ->message_loop_proxy()) {} | 188 ->message_loop_proxy()), |
189 output_channels_(output_channels), | |
190 output_sample_rate_(output_sample_rate), | |
191 input_data_(NULL), | |
192 input_frames_(0), | |
193 input_bytes_per_frame_(0) {} | |
185 | 194 |
186 virtual ~CastAudioSink() { | 195 virtual ~CastAudioSink() { |
187 if (sink_added_) | 196 if (sink_added_) |
188 RemoveFromAudioTrack(this, track_); | 197 RemoveFromAudioTrack(this, track_); |
189 } | 198 } |
190 | 199 |
191 // Called on real-time audio thread. | 200 // Called on real-time audio thread. |
192 // content::MediaStreamAudioSink implementation. | 201 // content::MediaStreamAudioSink implementation. |
193 virtual void OnData(const int16* audio_data, | 202 virtual void OnData(const int16* audio_data, |
194 int sample_rate, | 203 int sample_rate, |
195 int number_of_channels, | 204 int number_of_channels, |
196 int number_of_frames) OVERRIDE { | 205 int number_of_frames) OVERRIDE { |
197 scoped_ptr<media::AudioBus> audio_bus( | 206 input_data_ = audio_data; |
198 media::AudioBus::Create(number_of_channels, number_of_frames)); | 207 input_frames_ = number_of_frames; |
199 audio_bus->FromInterleaved(audio_data, number_of_frames, 2); | 208 |
209 DCHECK_EQ(number_of_channels, output_channels_); | |
210 scoped_ptr<media::AudioBus> output_bus( | |
211 media::AudioBus::Create( | |
212 output_channels_, | |
213 output_sample_rate_ * number_of_frames / sample_rate)); | |
214 resampler_->Resample(output_bus->frames(), output_bus.get()); | |
miu
2014/03/05 20:59:00
nit: Add a comment that the resampler will invoke
Alpha Left Google
2014/03/06 00:14:56
Done.
| |
215 input_data_ = NULL; | |
216 input_frames_ = 0; | |
200 | 217 |
201 // TODO(hclam): Pass in the accurate capture time to have good | 218 // TODO(hclam): Pass in the accurate capture time to have good |
202 // audio / video sync. | 219 // audio / video sync. |
203 | 220 |
204 // TODO(hclam): We shouldn't hop through the render thread. | 221 // TODO(hclam): We shouldn't hop through the render thread. |
205 // Bounce the call from the real-time audio thread to the render thread. | 222 // Bounce the call from the real-time audio thread to the render thread. |
206 // Needed since frame_input_ can be changed runtime by the render thread. | 223 // Needed since frame_input_ can be changed runtime by the render thread. |
207 media::AudioBus* const audio_bus_ptr = audio_bus.get(); | 224 media::AudioBus* const output_bus_ptr = output_bus.get(); |
208 render_thread_task_runner_->PostTask( | 225 render_thread_task_runner_->PostTask( |
209 FROM_HERE, | 226 FROM_HERE, |
210 base::Bind(&CastAudioSink::SendAudio, | 227 base::Bind(&CastAudioSink::SendAudio, |
211 weak_factory_.GetWeakPtr(), | 228 weak_factory_.GetWeakPtr(), |
212 audio_bus_ptr, | 229 output_bus_ptr, |
213 base::TimeTicks::Now(), | 230 base::TimeTicks::Now(), |
214 base::Bind(&DeleteAudioBus, base::Passed(&audio_bus)))); | 231 base::Bind(&DeleteAudioBus, base::Passed(&output_bus)))); |
215 } | 232 } |
216 | 233 |
217 void SendAudio(const media::AudioBus* audio_bus_ptr, | 234 void SendAudio(const media::AudioBus* audio_bus, |
218 const base::TimeTicks& recorded_time, | 235 const base::TimeTicks& recorded_time, |
219 const base::Closure& done_callback) { | 236 const base::Closure& done_callback) { |
220 DCHECK(render_thread_task_runner_->BelongsToCurrentThread()); | 237 DCHECK(render_thread_task_runner_->BelongsToCurrentThread()); |
221 DCHECK(frame_input_); | 238 DCHECK(frame_input_); |
222 frame_input_->InsertAudio(audio_bus_ptr, recorded_time, done_callback); | 239 frame_input_->InsertAudio(audio_bus, recorded_time, done_callback); |
223 } | 240 } |
224 | 241 |
225 // Called on real-time audio thread. | 242 // Called on real-time audio thread. |
226 virtual void OnSetFormat(const media::AudioParameters& params) OVERRIDE { | 243 virtual void OnSetFormat(const media::AudioParameters& params) OVERRIDE { |
227 NOTIMPLEMENTED(); | 244 resampler_.reset(new media::MultiChannelResampler( |
245 output_channels_, | |
246 static_cast<double>(params.sample_rate()) / output_sample_rate_, | |
247 params.frames_per_buffer(), | |
248 base::Bind(&CastAudioSink::ProvideData, base::Unretained(this)))); | |
249 input_bytes_per_frame_ = params.bits_per_sample() / 8; | |
228 } | 250 } |
229 | 251 |
230 // See CastVideoSink for details. | 252 // See CastVideoSink for details. |
231 void AddToTrack(const scoped_refptr<media::cast::FrameInput>& frame_input) { | 253 void AddToTrack(const scoped_refptr<media::cast::FrameInput>& frame_input) { |
232 DCHECK(render_thread_task_runner_->BelongsToCurrentThread()); | 254 DCHECK(render_thread_task_runner_->BelongsToCurrentThread()); |
233 frame_input_ = frame_input; | 255 frame_input_ = frame_input; |
234 if (!sink_added_) { | 256 if (!sink_added_) { |
235 AddToAudioTrack(this, track_); | 257 AddToAudioTrack(this, track_); |
236 sink_added_ = true; | 258 sink_added_ = true; |
237 } | 259 } |
238 } | 260 } |
239 | 261 |
262 void ProvideData(int frame_delay, media::AudioBus* output_bus) { | |
263 DCHECK_EQ(input_frames_, output_bus->frames()); | |
264 output_bus->FromInterleaved(input_data_, input_frames_, | |
265 input_bytes_per_frame_); | |
266 } | |
267 | |
240 private: | 268 private: |
241 blink::WebMediaStreamTrack track_; | 269 blink::WebMediaStreamTrack track_; |
242 scoped_refptr<media::cast::FrameInput> frame_input_; | 270 scoped_refptr<media::cast::FrameInput> frame_input_; |
243 bool sink_added_; | 271 bool sink_added_; |
244 CastRtpStream::ErrorCallback error_callback_; | 272 CastRtpStream::ErrorCallback error_callback_; |
245 base::WeakPtrFactory<CastAudioSink> weak_factory_; | 273 base::WeakPtrFactory<CastAudioSink> weak_factory_; |
246 scoped_refptr<base::SingleThreadTaskRunner> render_thread_task_runner_; | 274 scoped_refptr<base::SingleThreadTaskRunner> render_thread_task_runner_; |
247 | 275 |
276 scoped_ptr<media::MultiChannelResampler> resampler_; | |
277 int output_channels_; | |
miu
2014/03/05 20:59:00
nit: The two output_xxx_ members should be const.
Alpha Left Google
2014/03/06 00:14:56
Done.
| |
278 int output_sample_rate_; | |
279 const void* input_data_; | |
280 int input_frames_; | |
281 int input_bytes_per_frame_; | |
282 | |
248 DISALLOW_COPY_AND_ASSIGN(CastAudioSink); | 283 DISALLOW_COPY_AND_ASSIGN(CastAudioSink); |
249 }; | 284 }; |
250 | 285 |
251 CastRtpParams::CastRtpParams(const CastRtpPayloadParams& payload_params) | 286 CastRtpParams::CastRtpParams(const CastRtpPayloadParams& payload_params) |
252 : payload(payload_params) {} | 287 : payload(payload_params) {} |
253 | 288 |
254 CastCodecSpecificParams::CastCodecSpecificParams() {} | 289 CastCodecSpecificParams::CastCodecSpecificParams() {} |
255 | 290 |
256 CastCodecSpecificParams::~CastCodecSpecificParams() {} | 291 CastCodecSpecificParams::~CastCodecSpecificParams() {} |
257 | 292 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
302 const ErrorCallback& error_callback) { | 337 const ErrorCallback& error_callback) { |
303 stop_callback_ = stop_callback; | 338 stop_callback_ = stop_callback; |
304 error_callback_ = error_callback; | 339 error_callback_ = error_callback; |
305 | 340 |
306 if (IsAudio()) { | 341 if (IsAudio()) { |
307 AudioSenderConfig config; | 342 AudioSenderConfig config; |
308 if (!ToAudioSenderConfig(params, &config)) { | 343 if (!ToAudioSenderConfig(params, &config)) { |
309 DidEncounterError("Invalid parameters for audio."); | 344 DidEncounterError("Invalid parameters for audio."); |
310 return; | 345 return; |
311 } | 346 } |
347 | |
312 // In case of error we have to go through DidEncounterError() to stop | 348 // In case of error we have to go through DidEncounterError() to stop |
313 // the streaming after reporting the error. | 349 // the streaming after reporting the error. |
314 audio_sink_.reset(new CastAudioSink( | 350 audio_sink_.reset(new CastAudioSink( |
315 track_, | 351 track_, |
316 media::BindToCurrentLoop(base::Bind(&CastRtpStream::DidEncounterError, | 352 media::BindToCurrentLoop(base::Bind(&CastRtpStream::DidEncounterError, |
317 weak_factory_.GetWeakPtr())))); | 353 weak_factory_.GetWeakPtr())), |
354 params.payload.channels, | |
355 params.payload.clock_rate)); | |
318 cast_session_->StartAudio( | 356 cast_session_->StartAudio( |
319 config, | 357 config, |
320 base::Bind(&CastAudioSink::AddToTrack, | 358 base::Bind(&CastAudioSink::AddToTrack, |
321 audio_sink_->AsWeakPtr())); | 359 audio_sink_->AsWeakPtr())); |
322 start_callback.Run(); | 360 start_callback.Run(); |
323 } else { | 361 } else { |
324 VideoSenderConfig config; | 362 VideoSenderConfig config; |
325 if (!ToVideoSenderConfig(params, &config)) { | 363 if (!ToVideoSenderConfig(params, &config)) { |
326 DidEncounterError("Invalid parameters for video."); | 364 DidEncounterError("Invalid parameters for video."); |
327 return; | 365 return; |
(...skipping 27 matching lines...) Expand all Loading... | |
355 } | 393 } |
356 | 394 |
357 bool CastRtpStream::IsAudio() const { | 395 bool CastRtpStream::IsAudio() const { |
358 return track_.source().type() == blink::WebMediaStreamSource::TypeAudio; | 396 return track_.source().type() == blink::WebMediaStreamSource::TypeAudio; |
359 } | 397 } |
360 | 398 |
361 void CastRtpStream::DidEncounterError(const std::string& message) { | 399 void CastRtpStream::DidEncounterError(const std::string& message) { |
362 error_callback_.Run(message); | 400 error_callback_.Run(message); |
363 Stop(); | 401 Stop(); |
364 } | 402 } |
OLD | NEW |