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" |
17 #include "media/base/audio_fifo.h" | |
16 #include "media/base/bind_to_current_loop.h" | 18 #include "media/base/bind_to_current_loop.h" |
19 #include "media/base/multi_channel_resampler.h" | |
17 #include "media/cast/cast_config.h" | 20 #include "media/cast/cast_config.h" |
18 #include "media/cast/cast_defines.h" | 21 #include "media/cast/cast_defines.h" |
19 #include "media/cast/cast_sender.h" | 22 #include "media/cast/cast_sender.h" |
20 #include "media/cast/transport/cast_transport_config.h" | 23 #include "media/cast/transport/cast_transport_config.h" |
21 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h" | 24 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h" |
22 | 25 |
23 using media::cast::AudioSenderConfig; | 26 using media::cast::AudioSenderConfig; |
24 using media::cast::VideoSenderConfig; | 27 using media::cast::VideoSenderConfig; |
25 | 28 |
26 namespace { | 29 namespace { |
30 | |
27 const char kCodecNameOpus[] = "OPUS"; | 31 const char kCodecNameOpus[] = "OPUS"; |
28 const char kCodecNameVp8[] = "VP8"; | 32 const char kCodecNameVp8[] = "VP8"; |
29 | 33 |
34 // This constant defines the number of sets of audio data to buffer | |
35 // in the FIFO. If input audio and output data have different resampling | |
36 // rates then buffer is necessary to avoid audio glitches. | |
37 // See CastAudioSink::ResampleData() and CastAudioSink::OnSetFormat() | |
38 // for more defaults. | |
39 const int kBufferAudioData = 2; | |
40 | |
30 CastRtpPayloadParams DefaultOpusPayload() { | 41 CastRtpPayloadParams DefaultOpusPayload() { |
31 CastRtpPayloadParams payload; | 42 CastRtpPayloadParams payload; |
32 payload.ssrc = 1; | 43 payload.ssrc = 1; |
33 payload.feedback_ssrc = 1; | 44 payload.feedback_ssrc = 1; |
34 payload.payload_type = 127; | 45 payload.payload_type = 127; |
35 payload.codec_name = kCodecNameOpus; | 46 payload.codec_name = kCodecNameOpus; |
36 payload.clock_rate = 48000; | 47 payload.clock_rate = 48000; |
37 payload.channels = 2; | 48 payload.channels = 2; |
38 payload.min_bitrate = payload.max_bitrate = | 49 payload.min_bitrate = payload.max_bitrate = |
39 media::cast::kDefaultAudioEncoderBitrate; | 50 media::cast::kDefaultAudioEncoderBitrate; |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
167 // Receives audio data from a MediaStreamTrack. Data is submitted to | 178 // Receives audio data from a MediaStreamTrack. Data is submitted to |
168 // media::cast::FrameInput. | 179 // media::cast::FrameInput. |
169 // | 180 // |
170 // Threading: Audio frames are received on the real-time audio thread. | 181 // Threading: Audio frames are received on the real-time audio thread. |
171 class CastAudioSink : public base::SupportsWeakPtr<CastAudioSink>, | 182 class CastAudioSink : public base::SupportsWeakPtr<CastAudioSink>, |
172 public content::MediaStreamAudioSink { | 183 public content::MediaStreamAudioSink { |
173 public: | 184 public: |
174 // |track| provides data for this sink. | 185 // |track| provides data for this sink. |
175 // |error_callback| is called if audio formats don't match. | 186 // |error_callback| is called if audio formats don't match. |
176 CastAudioSink(const blink::WebMediaStreamTrack& track, | 187 CastAudioSink(const blink::WebMediaStreamTrack& track, |
177 const CastRtpStream::ErrorCallback& error_callback) | 188 const CastRtpStream::ErrorCallback& error_callback, |
189 int output_channels, | |
190 int output_sample_rate) | |
178 : track_(track), | 191 : track_(track), |
179 sink_added_(false), | 192 sink_added_(false), |
180 error_callback_(error_callback), | 193 error_callback_(error_callback), |
181 weak_factory_(this), | 194 weak_factory_(this), |
182 render_thread_task_runner_(content::RenderThread::Get() | 195 render_thread_task_runner_(content::RenderThread::Get() |
183 ->GetMessageLoop() | 196 ->GetMessageLoop() |
184 ->message_loop_proxy()) {} | 197 ->message_loop_proxy()), |
198 input_preroll_(0), | |
199 output_channels_(output_channels), | |
200 output_sample_rate_(output_sample_rate) {} | |
185 | 201 |
186 virtual ~CastAudioSink() { | 202 virtual ~CastAudioSink() { |
187 if (sink_added_) | 203 if (sink_added_) |
188 RemoveFromAudioTrack(this, track_); | 204 RemoveFromAudioTrack(this, track_); |
189 } | 205 } |
190 | 206 |
191 // Called on real-time audio thread. | 207 // Called on real-time audio thread. |
192 // content::MediaStreamAudioSink implementation. | 208 // content::MediaStreamAudioSink implementation. |
193 virtual void OnData(const int16* audio_data, | 209 virtual void OnData(const int16* audio_data, |
194 int sample_rate, | 210 int sample_rate, |
195 int number_of_channels, | 211 int number_of_channels, |
196 int number_of_frames) OVERRIDE { | 212 int number_of_frames) OVERRIDE { |
197 scoped_ptr<media::AudioBus> audio_bus( | 213 scoped_ptr<media::AudioBus> input_bus; |
198 media::AudioBus::Create(number_of_channels, number_of_frames)); | 214 if (resampler_) { |
199 audio_bus->FromInterleaved(audio_data, number_of_frames, 2); | 215 input_bus = ResampleData( |
216 audio_data, sample_rate, number_of_channels, number_of_frames); | |
217 if (!input_bus) | |
218 return; | |
219 } else { | |
220 input_bus = media::AudioBus::Create( | |
221 number_of_channels, number_of_frames).Pass(); | |
DaleCurtis
2014/03/07 19:16:42
No .Pass necessary.
| |
222 input_bus->FromInterleaved( | |
223 audio_data, number_of_frames, number_of_channels); | |
224 } | |
200 | 225 |
201 // TODO(hclam): Pass in the accurate capture time to have good | 226 // TODO(hclam): Pass in the accurate capture time to have good |
202 // audio / video sync. | 227 // audio / video sync. |
203 | 228 |
204 // TODO(hclam): We shouldn't hop through the render thread. | 229 // TODO(hclam): We shouldn't hop through the render thread. |
205 // Bounce the call from the real-time audio thread to the render thread. | 230 // 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. | 231 // Needed since frame_input_ can be changed runtime by the render thread. |
207 media::AudioBus* const audio_bus_ptr = audio_bus.get(); | 232 media::AudioBus* const input_bus_ptr = input_bus.get(); |
208 render_thread_task_runner_->PostTask( | 233 render_thread_task_runner_->PostTask( |
209 FROM_HERE, | 234 FROM_HERE, |
210 base::Bind(&CastAudioSink::SendAudio, | 235 base::Bind(&CastAudioSink::SendAudio, |
211 weak_factory_.GetWeakPtr(), | 236 weak_factory_.GetWeakPtr(), |
212 audio_bus_ptr, | 237 input_bus_ptr, |
213 base::TimeTicks::Now(), | 238 base::TimeTicks::Now(), |
214 base::Bind(&DeleteAudioBus, base::Passed(&audio_bus)))); | 239 base::Bind(&DeleteAudioBus, base::Passed(&input_bus)))); |
215 } | 240 } |
216 | 241 |
217 void SendAudio(const media::AudioBus* audio_bus_ptr, | 242 // Return a resampled audio data from input. This is called when the |
243 // input sample rate doesn't match the output. | |
244 // The flow of data is as follows: | |
245 // |audio_data| -> | |
246 // AudioFifo |fifo_| -> | |
247 // MultiChannelResampler |resampler|. | |
248 // | |
249 // The resampler pulls data out of the FIFO and resample the data in | |
250 // frequency domain. It might call |fifo_| for more than once. But no more | |
251 // than |kBufferAudioData| times. We preroll audio data into the FIFO to | |
252 // make sure there's enough data for resampling. | |
253 scoped_ptr<media::AudioBus> ResampleData( | |
254 const int16* audio_data, | |
255 int sample_rate, | |
256 int number_of_channels, | |
257 int number_of_frames) { | |
258 DCHECK_EQ(number_of_channels, output_channels_); | |
259 fifo_input_bus_->FromInterleaved( | |
260 audio_data, number_of_frames, number_of_channels); | |
261 fifo_->Push(fifo_input_bus_.get()); | |
262 | |
263 if (input_preroll_ < kBufferAudioData - 1) { | |
264 ++input_preroll_; | |
265 return scoped_ptr<media::AudioBus>(); | |
266 } | |
267 | |
268 scoped_ptr<media::AudioBus> output_bus( | |
269 media::AudioBus::Create( | |
270 output_channels_, | |
271 output_sample_rate_ * fifo_input_bus_->frames() / sample_rate)); | |
DaleCurtis
2014/03/07 19:16:42
This should be fine for the sample rates your usin
| |
272 | |
273 // Resampler will then call ProvideData() below to fetch data from | |
274 // |input_data_|. | |
275 resampler_->Resample(output_bus->frames(), output_bus.get()); | |
276 return output_bus.Pass(); | |
277 } | |
278 | |
279 void SendAudio(const media::AudioBus* audio_bus, | |
218 const base::TimeTicks& recorded_time, | 280 const base::TimeTicks& recorded_time, |
219 const base::Closure& done_callback) { | 281 const base::Closure& done_callback) { |
220 DCHECK(render_thread_task_runner_->BelongsToCurrentThread()); | 282 DCHECK(render_thread_task_runner_->BelongsToCurrentThread()); |
221 DCHECK(frame_input_); | 283 DCHECK(frame_input_); |
222 frame_input_->InsertAudio(audio_bus_ptr, recorded_time, done_callback); | 284 frame_input_->InsertAudio(audio_bus, recorded_time, done_callback); |
223 } | 285 } |
224 | 286 |
225 // Called on real-time audio thread. | 287 // Called on real-time audio thread. |
226 virtual void OnSetFormat(const media::AudioParameters& params) OVERRIDE { | 288 virtual void OnSetFormat(const media::AudioParameters& params) OVERRIDE { |
227 NOTIMPLEMENTED(); | 289 if (params.sample_rate() == output_sample_rate_) |
290 return; | |
291 fifo_.reset(new media::AudioFifo( | |
292 output_channels_, | |
293 kBufferAudioData * params.frames_per_buffer())); | |
294 fifo_input_bus_ = media::AudioBus::Create( | |
295 params.channels(), params.frames_per_buffer()).Pass(); | |
DaleCurtis
2014/03/07 19:16:42
No need for .Pass().
| |
296 resampler_.reset(new media::MultiChannelResampler( | |
297 output_channels_, | |
298 static_cast<double>(params.sample_rate()) / output_sample_rate_, | |
299 params.frames_per_buffer(), | |
300 base::Bind(&CastAudioSink::ProvideData, base::Unretained(this)))); | |
228 } | 301 } |
229 | 302 |
230 // See CastVideoSink for details. | 303 // See CastVideoSink for details. |
231 void AddToTrack(const scoped_refptr<media::cast::FrameInput>& frame_input) { | 304 void AddToTrack(const scoped_refptr<media::cast::FrameInput>& frame_input) { |
232 DCHECK(render_thread_task_runner_->BelongsToCurrentThread()); | 305 DCHECK(render_thread_task_runner_->BelongsToCurrentThread()); |
233 frame_input_ = frame_input; | 306 frame_input_ = frame_input; |
234 if (!sink_added_) { | 307 if (!sink_added_) { |
235 AddToAudioTrack(this, track_); | 308 AddToAudioTrack(this, track_); |
236 sink_added_ = true; | 309 sink_added_ = true; |
237 } | 310 } |
238 } | 311 } |
239 | 312 |
313 void ProvideData(int frame_delay, media::AudioBus* output_bus) { | |
314 fifo_->Consume(output_bus, 0, output_bus->frames()); | |
315 } | |
316 | |
240 private: | 317 private: |
241 blink::WebMediaStreamTrack track_; | 318 blink::WebMediaStreamTrack track_; |
242 scoped_refptr<media::cast::FrameInput> frame_input_; | 319 scoped_refptr<media::cast::FrameInput> frame_input_; |
243 bool sink_added_; | 320 bool sink_added_; |
244 CastRtpStream::ErrorCallback error_callback_; | 321 CastRtpStream::ErrorCallback error_callback_; |
245 base::WeakPtrFactory<CastAudioSink> weak_factory_; | 322 base::WeakPtrFactory<CastAudioSink> weak_factory_; |
246 scoped_refptr<base::SingleThreadTaskRunner> render_thread_task_runner_; | 323 scoped_refptr<base::SingleThreadTaskRunner> render_thread_task_runner_; |
247 | 324 |
325 scoped_ptr<media::MultiChannelResampler> resampler_; | |
326 scoped_ptr<media::AudioFifo> fifo_; | |
327 scoped_ptr<media::AudioBus> fifo_input_bus_; | |
328 int input_preroll_; | |
329 const int output_channels_; | |
330 const int output_sample_rate_; | |
331 | |
248 DISALLOW_COPY_AND_ASSIGN(CastAudioSink); | 332 DISALLOW_COPY_AND_ASSIGN(CastAudioSink); |
249 }; | 333 }; |
250 | 334 |
251 CastRtpParams::CastRtpParams(const CastRtpPayloadParams& payload_params) | 335 CastRtpParams::CastRtpParams(const CastRtpPayloadParams& payload_params) |
252 : payload(payload_params) {} | 336 : payload(payload_params) {} |
253 | 337 |
254 CastCodecSpecificParams::CastCodecSpecificParams() {} | 338 CastCodecSpecificParams::CastCodecSpecificParams() {} |
255 | 339 |
256 CastCodecSpecificParams::~CastCodecSpecificParams() {} | 340 CastCodecSpecificParams::~CastCodecSpecificParams() {} |
257 | 341 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
302 const ErrorCallback& error_callback) { | 386 const ErrorCallback& error_callback) { |
303 stop_callback_ = stop_callback; | 387 stop_callback_ = stop_callback; |
304 error_callback_ = error_callback; | 388 error_callback_ = error_callback; |
305 | 389 |
306 if (IsAudio()) { | 390 if (IsAudio()) { |
307 AudioSenderConfig config; | 391 AudioSenderConfig config; |
308 if (!ToAudioSenderConfig(params, &config)) { | 392 if (!ToAudioSenderConfig(params, &config)) { |
309 DidEncounterError("Invalid parameters for audio."); | 393 DidEncounterError("Invalid parameters for audio."); |
310 return; | 394 return; |
311 } | 395 } |
396 | |
312 // In case of error we have to go through DidEncounterError() to stop | 397 // In case of error we have to go through DidEncounterError() to stop |
313 // the streaming after reporting the error. | 398 // the streaming after reporting the error. |
314 audio_sink_.reset(new CastAudioSink( | 399 audio_sink_.reset(new CastAudioSink( |
315 track_, | 400 track_, |
316 media::BindToCurrentLoop(base::Bind(&CastRtpStream::DidEncounterError, | 401 media::BindToCurrentLoop(base::Bind(&CastRtpStream::DidEncounterError, |
317 weak_factory_.GetWeakPtr())))); | 402 weak_factory_.GetWeakPtr())), |
403 params.payload.channels, | |
404 params.payload.clock_rate)); | |
318 cast_session_->StartAudio( | 405 cast_session_->StartAudio( |
319 config, | 406 config, |
320 base::Bind(&CastAudioSink::AddToTrack, | 407 base::Bind(&CastAudioSink::AddToTrack, |
321 audio_sink_->AsWeakPtr())); | 408 audio_sink_->AsWeakPtr())); |
322 start_callback.Run(); | 409 start_callback.Run(); |
323 } else { | 410 } else { |
324 VideoSenderConfig config; | 411 VideoSenderConfig config; |
325 if (!ToVideoSenderConfig(params, &config)) { | 412 if (!ToVideoSenderConfig(params, &config)) { |
326 DidEncounterError("Invalid parameters for video."); | 413 DidEncounterError("Invalid parameters for video."); |
327 return; | 414 return; |
(...skipping 27 matching lines...) Expand all Loading... | |
355 } | 442 } |
356 | 443 |
357 bool CastRtpStream::IsAudio() const { | 444 bool CastRtpStream::IsAudio() const { |
358 return track_.source().type() == blink::WebMediaStreamSource::TypeAudio; | 445 return track_.source().type() == blink::WebMediaStreamSource::TypeAudio; |
359 } | 446 } |
360 | 447 |
361 void CastRtpStream::DidEncounterError(const std::string& message) { | 448 void CastRtpStream::DidEncounterError(const std::string& message) { |
362 error_callback_.Run(message); | 449 error_callback_.Run(message); |
363 Stop(); | 450 Stop(); |
364 } | 451 } |
OLD | NEW |