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

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: nits 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
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
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
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 }
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