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 | |
215 // Resampler will then call ProvideData() below to fetch data from | |
216 // |input_data_|. | |
217 resampler_->Resample(output_bus->frames(), output_bus.get()); | |
DaleCurtis
2014/03/06 20:57:16
While this guarantees all input data is consumed i
| |
218 input_data_ = NULL; | |
219 input_frames_ = 0; | |
200 | 220 |
201 // TODO(hclam): Pass in the accurate capture time to have good | 221 // TODO(hclam): Pass in the accurate capture time to have good |
202 // audio / video sync. | 222 // audio / video sync. |
203 | 223 |
204 // TODO(hclam): We shouldn't hop through the render thread. | 224 // TODO(hclam): We shouldn't hop through the render thread. |
205 // Bounce the call from the real-time audio thread to the render thread. | 225 // 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. | 226 // Needed since frame_input_ can be changed runtime by the render thread. |
207 media::AudioBus* const audio_bus_ptr = audio_bus.get(); | 227 media::AudioBus* const output_bus_ptr = output_bus.get(); |
208 render_thread_task_runner_->PostTask( | 228 render_thread_task_runner_->PostTask( |
209 FROM_HERE, | 229 FROM_HERE, |
210 base::Bind(&CastAudioSink::SendAudio, | 230 base::Bind(&CastAudioSink::SendAudio, |
211 weak_factory_.GetWeakPtr(), | 231 weak_factory_.GetWeakPtr(), |
212 audio_bus_ptr, | 232 output_bus_ptr, |
213 base::TimeTicks::Now(), | 233 base::TimeTicks::Now(), |
214 base::Bind(&DeleteAudioBus, base::Passed(&audio_bus)))); | 234 base::Bind(&DeleteAudioBus, base::Passed(&output_bus)))); |
215 } | 235 } |
216 | 236 |
217 void SendAudio(const media::AudioBus* audio_bus_ptr, | 237 void SendAudio(const media::AudioBus* audio_bus, |
218 const base::TimeTicks& recorded_time, | 238 const base::TimeTicks& recorded_time, |
219 const base::Closure& done_callback) { | 239 const base::Closure& done_callback) { |
220 DCHECK(render_thread_task_runner_->BelongsToCurrentThread()); | 240 DCHECK(render_thread_task_runner_->BelongsToCurrentThread()); |
221 DCHECK(frame_input_); | 241 DCHECK(frame_input_); |
222 frame_input_->InsertAudio(audio_bus_ptr, recorded_time, done_callback); | 242 frame_input_->InsertAudio(audio_bus, recorded_time, done_callback); |
223 } | 243 } |
224 | 244 |
225 // Called on real-time audio thread. | 245 // Called on real-time audio thread. |
226 virtual void OnSetFormat(const media::AudioParameters& params) OVERRIDE { | 246 virtual void OnSetFormat(const media::AudioParameters& params) OVERRIDE { |
227 NOTIMPLEMENTED(); | 247 resampler_.reset(new media::MultiChannelResampler( |
248 output_channels_, | |
249 static_cast<double>(params.sample_rate()) / output_sample_rate_, | |
250 params.frames_per_buffer(), | |
251 base::Bind(&CastAudioSink::ProvideData, base::Unretained(this)))); | |
252 input_bytes_per_frame_ = params.bits_per_sample() / 8; | |
DaleCurtis
2014/03/06 20:57:16
This is calculating bytes per channel, not bytes p
| |
228 } | 253 } |
229 | 254 |
230 // See CastVideoSink for details. | 255 // See CastVideoSink for details. |
231 void AddToTrack(const scoped_refptr<media::cast::FrameInput>& frame_input) { | 256 void AddToTrack(const scoped_refptr<media::cast::FrameInput>& frame_input) { |
232 DCHECK(render_thread_task_runner_->BelongsToCurrentThread()); | 257 DCHECK(render_thread_task_runner_->BelongsToCurrentThread()); |
233 frame_input_ = frame_input; | 258 frame_input_ = frame_input; |
234 if (!sink_added_) { | 259 if (!sink_added_) { |
235 AddToAudioTrack(this, track_); | 260 AddToAudioTrack(this, track_); |
236 sink_added_ = true; | 261 sink_added_ = true; |
237 } | 262 } |
238 } | 263 } |
239 | 264 |
265 void ProvideData(int frame_delay, media::AudioBus* output_bus) { | |
266 DCHECK_EQ(input_frames_, output_bus->frames()); | |
267 output_bus->FromInterleaved(input_data_, input_frames_, | |
268 input_bytes_per_frame_); | |
269 } | |
270 | |
240 private: | 271 private: |
241 blink::WebMediaStreamTrack track_; | 272 blink::WebMediaStreamTrack track_; |
242 scoped_refptr<media::cast::FrameInput> frame_input_; | 273 scoped_refptr<media::cast::FrameInput> frame_input_; |
243 bool sink_added_; | 274 bool sink_added_; |
244 CastRtpStream::ErrorCallback error_callback_; | 275 CastRtpStream::ErrorCallback error_callback_; |
245 base::WeakPtrFactory<CastAudioSink> weak_factory_; | 276 base::WeakPtrFactory<CastAudioSink> weak_factory_; |
246 scoped_refptr<base::SingleThreadTaskRunner> render_thread_task_runner_; | 277 scoped_refptr<base::SingleThreadTaskRunner> render_thread_task_runner_; |
247 | 278 |
279 scoped_ptr<media::MultiChannelResampler> resampler_; | |
280 const int output_channels_; | |
281 const int output_sample_rate_; | |
282 const void* input_data_; | |
283 int input_frames_; | |
284 int input_bytes_per_frame_; | |
285 | |
248 DISALLOW_COPY_AND_ASSIGN(CastAudioSink); | 286 DISALLOW_COPY_AND_ASSIGN(CastAudioSink); |
249 }; | 287 }; |
250 | 288 |
251 CastRtpParams::CastRtpParams(const CastRtpPayloadParams& payload_params) | 289 CastRtpParams::CastRtpParams(const CastRtpPayloadParams& payload_params) |
252 : payload(payload_params) {} | 290 : payload(payload_params) {} |
253 | 291 |
254 CastCodecSpecificParams::CastCodecSpecificParams() {} | 292 CastCodecSpecificParams::CastCodecSpecificParams() {} |
255 | 293 |
256 CastCodecSpecificParams::~CastCodecSpecificParams() {} | 294 CastCodecSpecificParams::~CastCodecSpecificParams() {} |
257 | 295 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
302 const ErrorCallback& error_callback) { | 340 const ErrorCallback& error_callback) { |
303 stop_callback_ = stop_callback; | 341 stop_callback_ = stop_callback; |
304 error_callback_ = error_callback; | 342 error_callback_ = error_callback; |
305 | 343 |
306 if (IsAudio()) { | 344 if (IsAudio()) { |
307 AudioSenderConfig config; | 345 AudioSenderConfig config; |
308 if (!ToAudioSenderConfig(params, &config)) { | 346 if (!ToAudioSenderConfig(params, &config)) { |
309 DidEncounterError("Invalid parameters for audio."); | 347 DidEncounterError("Invalid parameters for audio."); |
310 return; | 348 return; |
311 } | 349 } |
350 | |
312 // In case of error we have to go through DidEncounterError() to stop | 351 // In case of error we have to go through DidEncounterError() to stop |
313 // the streaming after reporting the error. | 352 // the streaming after reporting the error. |
314 audio_sink_.reset(new CastAudioSink( | 353 audio_sink_.reset(new CastAudioSink( |
315 track_, | 354 track_, |
316 media::BindToCurrentLoop(base::Bind(&CastRtpStream::DidEncounterError, | 355 media::BindToCurrentLoop(base::Bind(&CastRtpStream::DidEncounterError, |
317 weak_factory_.GetWeakPtr())))); | 356 weak_factory_.GetWeakPtr())), |
357 params.payload.channels, | |
358 params.payload.clock_rate)); | |
318 cast_session_->StartAudio( | 359 cast_session_->StartAudio( |
319 config, | 360 config, |
320 base::Bind(&CastAudioSink::AddToTrack, | 361 base::Bind(&CastAudioSink::AddToTrack, |
321 audio_sink_->AsWeakPtr())); | 362 audio_sink_->AsWeakPtr())); |
322 start_callback.Run(); | 363 start_callback.Run(); |
323 } else { | 364 } else { |
324 VideoSenderConfig config; | 365 VideoSenderConfig config; |
325 if (!ToVideoSenderConfig(params, &config)) { | 366 if (!ToVideoSenderConfig(params, &config)) { |
326 DidEncounterError("Invalid parameters for video."); | 367 DidEncounterError("Invalid parameters for video."); |
327 return; | 368 return; |
(...skipping 27 matching lines...) Expand all Loading... | |
355 } | 396 } |
356 | 397 |
357 bool CastRtpStream::IsAudio() const { | 398 bool CastRtpStream::IsAudio() const { |
358 return track_.source().type() == blink::WebMediaStreamSource::TypeAudio; | 399 return track_.source().type() == blink::WebMediaStreamSource::TypeAudio; |
359 } | 400 } |
360 | 401 |
361 void CastRtpStream::DidEncounterError(const std::string& message) { | 402 void CastRtpStream::DidEncounterError(const std::string& message) { |
362 error_callback_.Run(message); | 403 error_callback_.Run(message); |
363 Stop(); | 404 Stop(); |
364 } | 405 } |
OLD | NEW |