Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(499)

Side by Side Diff: chrome/renderer/media/cast_rtp_stream.cc

Issue 187493002: Cast: Resample input audio to the configured sample rate (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/renderer/media/DEPS ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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 }
OLDNEW
« no previous file with comments | « chrome/renderer/media/DEPS ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698