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

Side by Side Diff: media/cast/sender/audio_encoder.cc

Issue 545593002: [Cast] Track audio queued in encoder; account for it in ShouldDropNextFrame(). (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase + MERGE (post-hubbe's refactoring changes) Created 6 years, 3 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
« no previous file with comments | « media/cast/sender/audio_encoder.h ('k') | media/cast/sender/audio_encoder_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 "media/cast/sender/audio_encoder.h" 5 #include "media/cast/sender/audio_encoder.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/bind_helpers.h" 10 #include "base/bind_helpers.h"
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
49 int sampling_rate, 49 int sampling_rate,
50 const FrameEncodedCallback& callback) 50 const FrameEncodedCallback& callback)
51 : cast_environment_(cast_environment), 51 : cast_environment_(cast_environment),
52 codec_(codec), 52 codec_(codec),
53 num_channels_(num_channels), 53 num_channels_(num_channels),
54 samples_per_frame_(sampling_rate / kFramesPerSecond), 54 samples_per_frame_(sampling_rate / kFramesPerSecond),
55 callback_(callback), 55 callback_(callback),
56 cast_initialization_status_(STATUS_AUDIO_UNINITIALIZED), 56 cast_initialization_status_(STATUS_AUDIO_UNINITIALIZED),
57 buffer_fill_end_(0), 57 buffer_fill_end_(0),
58 frame_id_(0), 58 frame_id_(0),
59 frame_rtp_timestamp_(0) { 59 frame_rtp_timestamp_(0),
60 samples_dropped_from_buffer_(0) {
60 // Support for max sampling rate of 48KHz, 2 channels, 100 ms duration. 61 // Support for max sampling rate of 48KHz, 2 channels, 100 ms duration.
61 const int kMaxSamplesTimesChannelsPerFrame = 48 * 2 * 100; 62 const int kMaxSamplesTimesChannelsPerFrame = 48 * 2 * 100;
62 if (num_channels_ <= 0 || samples_per_frame_ <= 0 || 63 if (num_channels_ <= 0 || samples_per_frame_ <= 0 ||
63 sampling_rate % kFramesPerSecond != 0 || 64 sampling_rate % kFramesPerSecond != 0 ||
64 samples_per_frame_ * num_channels_ > kMaxSamplesTimesChannelsPerFrame) { 65 samples_per_frame_ * num_channels_ > kMaxSamplesTimesChannelsPerFrame) {
65 cast_initialization_status_ = STATUS_INVALID_AUDIO_CONFIGURATION; 66 cast_initialization_status_ = STATUS_INVALID_AUDIO_CONFIGURATION;
66 } 67 }
67 } 68 }
68 69
69 CastInitializationStatus InitializationResult() const { 70 CastInitializationStatus InitializationResult() const {
70 return cast_initialization_status_; 71 return cast_initialization_status_;
71 } 72 }
72 73
74 int samples_per_frame() const {
75 return samples_per_frame_;
76 }
77
73 void EncodeAudio(scoped_ptr<AudioBus> audio_bus, 78 void EncodeAudio(scoped_ptr<AudioBus> audio_bus,
74 const base::TimeTicks& recorded_time) { 79 const base::TimeTicks& recorded_time) {
75 DCHECK_EQ(cast_initialization_status_, STATUS_AUDIO_INITIALIZED); 80 DCHECK_EQ(cast_initialization_status_, STATUS_AUDIO_INITIALIZED);
76 DCHECK(!recorded_time.is_null()); 81 DCHECK(!recorded_time.is_null());
77 82
78 // Determine whether |recorded_time| is consistent with the amount of audio 83 // Determine whether |recorded_time| is consistent with the amount of audio
79 // data having been processed in the past. Resolve the underrun problem by 84 // data having been processed in the past. Resolve the underrun problem by
80 // dropping data from the internal buffer and skipping ahead the next 85 // dropping data from the internal buffer and skipping ahead the next
81 // frame's RTP timestamp by the estimated number of frames missed. On the 86 // frame's RTP timestamp by the estimated number of frames missed. On the
82 // other hand, don't attempt to resolve overruns: A receiver should 87 // other hand, don't attempt to resolve overruns: A receiver should
83 // gracefully deal with an excess of audio data. 88 // gracefully deal with an excess of audio data.
84 const base::TimeDelta frame_duration = 89 const base::TimeDelta frame_duration =
85 base::TimeDelta::FromMilliseconds(kFrameDurationMillis); 90 base::TimeDelta::FromMilliseconds(kFrameDurationMillis);
86 base::TimeDelta buffer_fill_duration = 91 base::TimeDelta buffer_fill_duration =
87 buffer_fill_end_ * frame_duration / samples_per_frame_; 92 buffer_fill_end_ * frame_duration / samples_per_frame_;
88 if (!frame_capture_time_.is_null()) { 93 if (!frame_capture_time_.is_null()) {
89 const base::TimeDelta amount_ahead_by = 94 const base::TimeDelta amount_ahead_by =
90 recorded_time - (frame_capture_time_ + buffer_fill_duration); 95 recorded_time - (frame_capture_time_ + buffer_fill_duration);
91 if (amount_ahead_by > 96 if (amount_ahead_by >
92 base::TimeDelta::FromMilliseconds(kUnderrunThresholdMillis)) { 97 base::TimeDelta::FromMilliseconds(kUnderrunThresholdMillis)) {
98 samples_dropped_from_buffer_ += buffer_fill_end_;
93 buffer_fill_end_ = 0; 99 buffer_fill_end_ = 0;
94 buffer_fill_duration = base::TimeDelta(); 100 buffer_fill_duration = base::TimeDelta();
95 const int64 num_frames_missed = amount_ahead_by / 101 const int64 num_frames_missed = amount_ahead_by /
96 base::TimeDelta::FromMilliseconds(kFrameDurationMillis); 102 base::TimeDelta::FromMilliseconds(kFrameDurationMillis);
97 frame_rtp_timestamp_ += 103 frame_rtp_timestamp_ +=
98 static_cast<uint32>(num_frames_missed * samples_per_frame_); 104 static_cast<uint32>(num_frames_missed * samples_per_frame_);
99 DVLOG(1) << "Skipping RTP timestamp ahead to account for " 105 DVLOG(1) << "Skipping RTP timestamp ahead to account for "
100 << num_frames_missed * samples_per_frame_ 106 << num_frames_missed * samples_per_frame_
101 << " samples' worth of underrun."; 107 << " samples' worth of underrun.";
102 } 108 }
(...skipping 19 matching lines...) Expand all
122 audio_frame->dependency = EncodedFrame::KEY; 128 audio_frame->dependency = EncodedFrame::KEY;
123 audio_frame->frame_id = frame_id_; 129 audio_frame->frame_id = frame_id_;
124 audio_frame->referenced_frame_id = frame_id_; 130 audio_frame->referenced_frame_id = frame_id_;
125 audio_frame->rtp_timestamp = frame_rtp_timestamp_; 131 audio_frame->rtp_timestamp = frame_rtp_timestamp_;
126 audio_frame->reference_time = frame_capture_time_; 132 audio_frame->reference_time = frame_capture_time_;
127 133
128 if (EncodeFromFilledBuffer(&audio_frame->data)) { 134 if (EncodeFromFilledBuffer(&audio_frame->data)) {
129 cast_environment_->PostTask( 135 cast_environment_->PostTask(
130 CastEnvironment::MAIN, 136 CastEnvironment::MAIN,
131 FROM_HERE, 137 FROM_HERE,
132 base::Bind(callback_, base::Passed(&audio_frame))); 138 base::Bind(callback_,
139 base::Passed(&audio_frame),
140 samples_dropped_from_buffer_));
141 samples_dropped_from_buffer_ = 0;
133 } 142 }
134 143
135 // Reset the internal buffer, frame ID, and timestamps for the next frame. 144 // Reset the internal buffer, frame ID, and timestamps for the next frame.
136 buffer_fill_end_ = 0; 145 buffer_fill_end_ = 0;
137 ++frame_id_; 146 ++frame_id_;
138 frame_rtp_timestamp_ += samples_per_frame_; 147 frame_rtp_timestamp_ += samples_per_frame_;
139 frame_capture_time_ += frame_duration; 148 frame_capture_time_ += frame_duration;
140 } 149 }
141 } 150 }
142 151
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
175 // timestamp values are allowed to overflow and roll around past zero. 184 // timestamp values are allowed to overflow and roll around past zero.
176 uint32 frame_rtp_timestamp_; 185 uint32 frame_rtp_timestamp_;
177 186
178 // The local system time associated with the start of the next frame of 187 // The local system time associated with the start of the next frame of
179 // encoded audio. This value is passed on to a receiver as a reference clock 188 // encoded audio. This value is passed on to a receiver as a reference clock
180 // timestamp for the purposes of synchronizing audio and video. Its 189 // timestamp for the purposes of synchronizing audio and video. Its
181 // progression is expected to drift relative to the elapsed time implied by 190 // progression is expected to drift relative to the elapsed time implied by
182 // the RTP timestamps. 191 // the RTP timestamps.
183 base::TimeTicks frame_capture_time_; 192 base::TimeTicks frame_capture_time_;
184 193
194 // Set to non-zero to indicate the next output frame skipped over audio
195 // samples in order to recover from an input underrun.
196 int samples_dropped_from_buffer_;
197
185 DISALLOW_COPY_AND_ASSIGN(ImplBase); 198 DISALLOW_COPY_AND_ASSIGN(ImplBase);
186 }; 199 };
187 200
188 class AudioEncoder::OpusImpl : public AudioEncoder::ImplBase { 201 class AudioEncoder::OpusImpl : public AudioEncoder::ImplBase {
189 public: 202 public:
190 OpusImpl(const scoped_refptr<CastEnvironment>& cast_environment, 203 OpusImpl(const scoped_refptr<CastEnvironment>& cast_environment,
191 int num_channels, 204 int num_channels,
192 int sampling_rate, 205 int sampling_rate,
193 int bitrate, 206 int bitrate,
194 const FrameEncodedCallback& callback) 207 const FrameEncodedCallback& callback)
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
358 AudioEncoder::~AudioEncoder() {} 371 AudioEncoder::~AudioEncoder() {}
359 372
360 CastInitializationStatus AudioEncoder::InitializationResult() const { 373 CastInitializationStatus AudioEncoder::InitializationResult() const {
361 DCHECK(insert_thread_checker_.CalledOnValidThread()); 374 DCHECK(insert_thread_checker_.CalledOnValidThread());
362 if (impl_.get()) { 375 if (impl_.get()) {
363 return impl_->InitializationResult(); 376 return impl_->InitializationResult();
364 } 377 }
365 return STATUS_UNSUPPORTED_AUDIO_CODEC; 378 return STATUS_UNSUPPORTED_AUDIO_CODEC;
366 } 379 }
367 380
381 int AudioEncoder::GetSamplesPerFrame() const {
382 DCHECK(insert_thread_checker_.CalledOnValidThread());
383 if (InitializationResult() != STATUS_AUDIO_INITIALIZED) {
384 NOTREACHED();
385 return std::numeric_limits<int>::max();
386 }
387 return impl_->samples_per_frame();
388 }
389
368 void AudioEncoder::InsertAudio(scoped_ptr<AudioBus> audio_bus, 390 void AudioEncoder::InsertAudio(scoped_ptr<AudioBus> audio_bus,
369 const base::TimeTicks& recorded_time) { 391 const base::TimeTicks& recorded_time) {
370 DCHECK(insert_thread_checker_.CalledOnValidThread()); 392 DCHECK(insert_thread_checker_.CalledOnValidThread());
371 DCHECK(audio_bus.get()); 393 DCHECK(audio_bus.get());
372 if (!impl_.get()) { 394 if (InitializationResult() != STATUS_AUDIO_INITIALIZED) {
373 NOTREACHED(); 395 NOTREACHED();
374 return; 396 return;
375 } 397 }
376 cast_environment_->PostTask(CastEnvironment::AUDIO, 398 cast_environment_->PostTask(CastEnvironment::AUDIO,
377 FROM_HERE, 399 FROM_HERE,
378 base::Bind(&AudioEncoder::ImplBase::EncodeAudio, 400 base::Bind(&AudioEncoder::ImplBase::EncodeAudio,
379 impl_, 401 impl_,
380 base::Passed(&audio_bus), 402 base::Passed(&audio_bus),
381 recorded_time)); 403 recorded_time));
382 } 404 }
383 405
384 } // namespace cast 406 } // namespace cast
385 } // namespace media 407 } // namespace media
OLDNEW
« no previous file with comments | « media/cast/sender/audio_encoder.h ('k') | media/cast/sender/audio_encoder_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698