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 "media/cast/audio_sender/audio_encoder.h" | 5 #include "media/cast/audio_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 20 matching lines...) Expand all Loading... |
31 | 31 |
32 // Base class that handles the common problem of feeding one or more AudioBus' | 32 // Base class that handles the common problem of feeding one or more AudioBus' |
33 // data into a 10 ms buffer and then, once the buffer is full, encoding the | 33 // data into a 10 ms buffer and then, once the buffer is full, encoding the |
34 // signal and emitting an EncodedAudioFrame via the FrameEncodedCallback. | 34 // signal and emitting an EncodedAudioFrame via the FrameEncodedCallback. |
35 // | 35 // |
36 // Subclasses complete the implementation by handling the actual encoding | 36 // Subclasses complete the implementation by handling the actual encoding |
37 // details. | 37 // details. |
38 class AudioEncoder::ImplBase { | 38 class AudioEncoder::ImplBase { |
39 public: | 39 public: |
40 ImplBase(CastEnvironment* cast_environment, | 40 ImplBase(CastEnvironment* cast_environment, |
41 transport::AudioCodec codec, int num_channels, int sampling_rate, | 41 AudioCodec codec, int num_channels, int sampling_rate, |
42 const FrameEncodedCallback& callback) | 42 const FrameEncodedCallback& callback) |
43 : cast_environment_(cast_environment), | 43 : cast_environment_(cast_environment), |
44 codec_(codec), num_channels_(num_channels), | 44 codec_(codec), num_channels_(num_channels), |
45 samples_per_10ms_(sampling_rate / 100), | 45 samples_per_10ms_(sampling_rate / 100), |
46 callback_(callback), | 46 callback_(callback), |
47 buffer_fill_end_(0), | 47 buffer_fill_end_(0), |
48 frame_id_(0) { | 48 frame_id_(0) { |
49 CHECK_GT(num_channels_, 0); | 49 CHECK_GT(num_channels_, 0); |
50 CHECK_GT(samples_per_10ms_, 0); | 50 CHECK_GT(samples_per_10ms_, 0); |
51 CHECK_EQ(sampling_rate % 100, 0); | 51 CHECK_EQ(sampling_rate % 100, 0); |
52 CHECK_LE(samples_per_10ms_ * num_channels_, | 52 CHECK_LE(samples_per_10ms_ * num_channels_, |
53 transport::EncodedAudioFrame::kMaxNumberOfSamples); | 53 EncodedAudioFrame::kMaxNumberOfSamples); |
54 } | 54 } |
55 | 55 |
56 virtual ~ImplBase() {} | 56 virtual ~ImplBase() {} |
57 | 57 |
58 void EncodeAudio(const AudioBus* audio_bus, | 58 void EncodeAudio(const AudioBus* audio_bus, |
59 const base::TimeTicks& recorded_time, | 59 const base::TimeTicks& recorded_time, |
60 const base::Closure& done_callback) { | 60 const base::Closure& done_callback) { |
61 int src_pos = 0; | 61 int src_pos = 0; |
62 while (src_pos < audio_bus->frames()) { | 62 while (src_pos < audio_bus->frames()) { |
63 const int num_samples_to_xfer = | 63 const int num_samples_to_xfer = |
64 std::min(samples_per_10ms_ - buffer_fill_end_, | 64 std::min(samples_per_10ms_ - buffer_fill_end_, |
65 audio_bus->frames() - src_pos); | 65 audio_bus->frames() - src_pos); |
66 DCHECK_EQ(audio_bus->channels(), num_channels_); | 66 DCHECK_EQ(audio_bus->channels(), num_channels_); |
67 TransferSamplesIntoBuffer( | 67 TransferSamplesIntoBuffer( |
68 audio_bus, src_pos, buffer_fill_end_, num_samples_to_xfer); | 68 audio_bus, src_pos, buffer_fill_end_, num_samples_to_xfer); |
69 src_pos += num_samples_to_xfer; | 69 src_pos += num_samples_to_xfer; |
70 buffer_fill_end_ += num_samples_to_xfer; | 70 buffer_fill_end_ += num_samples_to_xfer; |
71 | 71 |
72 if (src_pos == audio_bus->frames()) { | 72 if (src_pos == audio_bus->frames()) { |
73 cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE, | 73 cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE, |
74 done_callback); | 74 done_callback); |
75 // Note: |audio_bus| is now invalid.. | 75 // Note: |audio_bus| is now invalid.. |
76 } | 76 } |
77 | 77 |
78 if (buffer_fill_end_ == samples_per_10ms_) { | 78 if (buffer_fill_end_ == samples_per_10ms_) { |
79 scoped_ptr<transport::EncodedAudioFrame> audio_frame( | 79 scoped_ptr<EncodedAudioFrame> audio_frame(new EncodedAudioFrame()); |
80 new transport::EncodedAudioFrame()); | |
81 audio_frame->codec = codec_; | 80 audio_frame->codec = codec_; |
82 audio_frame->frame_id = frame_id_++; | 81 audio_frame->frame_id = frame_id_++; |
83 audio_frame->samples = samples_per_10ms_; | 82 audio_frame->samples = samples_per_10ms_; |
84 if (EncodeFromFilledBuffer(&audio_frame->data)) { | 83 if (EncodeFromFilledBuffer(&audio_frame->data)) { |
85 // Compute an offset to determine the recorded time for the first | 84 // Compute an offset to determine the recorded time for the first |
86 // audio sample in the buffer. | 85 // audio sample in the buffer. |
87 const base::TimeDelta buffer_time_offset = | 86 const base::TimeDelta buffer_time_offset = |
88 (buffer_fill_end_ - src_pos) * | 87 (buffer_fill_end_ - src_pos) * |
89 base::TimeDelta::FromMilliseconds(10) / samples_per_10ms_; | 88 base::TimeDelta::FromMilliseconds(10) / samples_per_10ms_; |
90 // TODO(miu): Consider batching EncodedAudioFrames so we only post a | 89 // TODO(miu): Consider batching EncodedAudioFrames so we only post a |
91 // at most one task for each call to this method. | 90 // at most one task for each call to this method. |
92 cast_environment_->PostTask( | 91 cast_environment_->PostTask( |
93 CastEnvironment::MAIN, FROM_HERE, | 92 CastEnvironment::MAIN, FROM_HERE, |
94 base::Bind(callback_, base::Passed(&audio_frame), | 93 base::Bind(callback_, base::Passed(&audio_frame), |
95 recorded_time - buffer_time_offset)); | 94 recorded_time - buffer_time_offset)); |
96 } | 95 } |
97 buffer_fill_end_ = 0; | 96 buffer_fill_end_ = 0; |
98 } | 97 } |
99 } | 98 } |
100 } | 99 } |
101 | 100 |
102 protected: | 101 protected: |
103 virtual void TransferSamplesIntoBuffer(const AudioBus* audio_bus, | 102 virtual void TransferSamplesIntoBuffer(const AudioBus* audio_bus, |
104 int source_offset, | 103 int source_offset, |
105 int buffer_fill_offset, | 104 int buffer_fill_offset, |
106 int num_samples) = 0; | 105 int num_samples) = 0; |
107 virtual bool EncodeFromFilledBuffer(std::string* out) = 0; | 106 virtual bool EncodeFromFilledBuffer(std::string* out) = 0; |
108 | 107 |
109 CastEnvironment* const cast_environment_; | 108 CastEnvironment* const cast_environment_; |
110 const transport::AudioCodec codec_; | 109 const AudioCodec codec_; |
111 const int num_channels_; | 110 const int num_channels_; |
112 const int samples_per_10ms_; | 111 const int samples_per_10ms_; |
113 const FrameEncodedCallback callback_; | 112 const FrameEncodedCallback callback_; |
114 | 113 |
115 private: | 114 private: |
116 // In the case where a call to EncodeAudio() cannot completely fill the | 115 // In the case where a call to EncodeAudio() cannot completely fill the |
117 // buffer, this points to the position at which to populate data in a later | 116 // buffer, this points to the position at which to populate data in a later |
118 // call. | 117 // call. |
119 int buffer_fill_end_; | 118 int buffer_fill_end_; |
120 | 119 |
121 // A counter used to label EncodedAudioFrames. | 120 // A counter used to label EncodedAudioFrames. |
122 uint32 frame_id_; | 121 uint32 frame_id_; |
123 | 122 |
124 private: | 123 private: |
125 DISALLOW_COPY_AND_ASSIGN(ImplBase); | 124 DISALLOW_COPY_AND_ASSIGN(ImplBase); |
126 }; | 125 }; |
127 | 126 |
128 class AudioEncoder::OpusImpl : public AudioEncoder::ImplBase { | 127 class AudioEncoder::OpusImpl : public AudioEncoder::ImplBase { |
129 public: | 128 public: |
130 OpusImpl(CastEnvironment* cast_environment, | 129 OpusImpl(CastEnvironment* cast_environment, |
131 int num_channels, int sampling_rate, int bitrate, | 130 int num_channels, int sampling_rate, int bitrate, |
132 const FrameEncodedCallback& callback) | 131 const FrameEncodedCallback& callback) |
133 : ImplBase(cast_environment, transport::kOpus, num_channels, | 132 : ImplBase(cast_environment, kOpus, num_channels, sampling_rate, |
134 sampling_rate, callback), | 133 callback), |
135 encoder_memory_(new uint8[opus_encoder_get_size(num_channels)]), | 134 encoder_memory_(new uint8[opus_encoder_get_size(num_channels)]), |
136 opus_encoder_(reinterpret_cast<OpusEncoder*>(encoder_memory_.get())), | 135 opus_encoder_(reinterpret_cast<OpusEncoder*>(encoder_memory_.get())), |
137 buffer_(new float[num_channels * samples_per_10ms_]) { | 136 buffer_(new float[num_channels * samples_per_10ms_]) { |
138 CHECK_EQ(opus_encoder_init(opus_encoder_, sampling_rate, num_channels, | 137 CHECK_EQ(opus_encoder_init(opus_encoder_, sampling_rate, num_channels, |
139 OPUS_APPLICATION_AUDIO), | 138 OPUS_APPLICATION_AUDIO), |
140 OPUS_OK); | 139 OPUS_OK); |
141 if (bitrate <= 0) { | 140 if (bitrate <= 0) { |
142 // Note: As of 2013-10-31, the encoder in "auto bitrate" mode would use a | 141 // Note: As of 2013-10-31, the encoder in "auto bitrate" mode would use a |
143 // variable bitrate up to 102kbps for 2-channel, 48 kHz audio and a 10 ms | 142 // variable bitrate up to 102kbps for 2-channel, 48 kHz audio and a 10 ms |
144 // frame size. The opus library authors may, of course, adjust this in | 143 // frame size. The opus library authors may, of course, adjust this in |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
197 static const int kOpusMaxPayloadSize = 4000; | 196 static const int kOpusMaxPayloadSize = 4000; |
198 | 197 |
199 DISALLOW_COPY_AND_ASSIGN(OpusImpl); | 198 DISALLOW_COPY_AND_ASSIGN(OpusImpl); |
200 }; | 199 }; |
201 | 200 |
202 class AudioEncoder::Pcm16Impl : public AudioEncoder::ImplBase { | 201 class AudioEncoder::Pcm16Impl : public AudioEncoder::ImplBase { |
203 public: | 202 public: |
204 Pcm16Impl(CastEnvironment* cast_environment, | 203 Pcm16Impl(CastEnvironment* cast_environment, |
205 int num_channels, int sampling_rate, | 204 int num_channels, int sampling_rate, |
206 const FrameEncodedCallback& callback) | 205 const FrameEncodedCallback& callback) |
207 : ImplBase(cast_environment, transport::kPcm16, num_channels, | 206 : ImplBase(cast_environment, kPcm16, num_channels, sampling_rate, |
208 sampling_rate, callback), | 207 callback), |
209 buffer_(new int16[num_channels * samples_per_10ms_]) {} | 208 buffer_(new int16[num_channels * samples_per_10ms_]) {} |
210 | 209 |
211 virtual ~Pcm16Impl() {} | 210 virtual ~Pcm16Impl() {} |
212 | 211 |
213 private: | 212 private: |
214 virtual void TransferSamplesIntoBuffer(const AudioBus* audio_bus, | 213 virtual void TransferSamplesIntoBuffer(const AudioBus* audio_bus, |
215 int source_offset, | 214 int source_offset, |
216 int buffer_fill_offset, | 215 int buffer_fill_offset, |
217 int num_samples) OVERRIDE { | 216 int num_samples) OVERRIDE { |
218 audio_bus->ToInterleavedPartial( | 217 audio_bus->ToInterleavedPartial( |
(...skipping 21 matching lines...) Expand all Loading... |
240 AudioEncoder::AudioEncoder( | 239 AudioEncoder::AudioEncoder( |
241 const scoped_refptr<CastEnvironment>& cast_environment, | 240 const scoped_refptr<CastEnvironment>& cast_environment, |
242 const AudioSenderConfig& audio_config, | 241 const AudioSenderConfig& audio_config, |
243 const FrameEncodedCallback& frame_encoded_callback) | 242 const FrameEncodedCallback& frame_encoded_callback) |
244 : cast_environment_(cast_environment) { | 243 : cast_environment_(cast_environment) { |
245 // Note: It doesn't matter which thread constructs AudioEncoder, just so long | 244 // Note: It doesn't matter which thread constructs AudioEncoder, just so long |
246 // as all calls to InsertAudio() are by the same thread. | 245 // as all calls to InsertAudio() are by the same thread. |
247 insert_thread_checker_.DetachFromThread(); | 246 insert_thread_checker_.DetachFromThread(); |
248 | 247 |
249 switch (audio_config.codec) { | 248 switch (audio_config.codec) { |
250 case transport::kOpus: | 249 case kOpus: |
251 impl_.reset(new OpusImpl( | 250 impl_.reset(new OpusImpl( |
252 cast_environment, audio_config.channels, audio_config.frequency, | 251 cast_environment, audio_config.channels, audio_config.frequency, |
253 audio_config.bitrate, frame_encoded_callback)); | 252 audio_config.bitrate, frame_encoded_callback)); |
254 break; | 253 break; |
255 case transport::kPcm16: | 254 case kPcm16: |
256 impl_.reset(new Pcm16Impl( | 255 impl_.reset(new Pcm16Impl( |
257 cast_environment, audio_config.channels, audio_config.frequency, | 256 cast_environment, audio_config.channels, audio_config.frequency, |
258 frame_encoded_callback)); | 257 frame_encoded_callback)); |
259 break; | 258 break; |
260 default: | 259 default: |
261 NOTREACHED() << "Unsupported or unspecified codec for audio encoder"; | 260 NOTREACHED() << "Unsupported or unspecified codec for audio encoder"; |
262 break; | 261 break; |
263 } | 262 } |
264 } | 263 } |
265 | 264 |
(...skipping 20 matching lines...) Expand all Loading... |
286 const base::TimeTicks& recorded_time, | 285 const base::TimeTicks& recorded_time, |
287 const base::Closure& done_callback) { | 286 const base::Closure& done_callback) { |
288 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::AUDIO_ENCODER)); | 287 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::AUDIO_ENCODER)); |
289 impl_->EncodeAudio(audio_bus, recorded_time, done_callback); | 288 impl_->EncodeAudio(audio_bus, recorded_time, done_callback); |
290 cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE, | 289 cast_environment_->PostTask(CastEnvironment::MAIN, FROM_HERE, |
291 base::Bind(LogAudioEncodedEvent, cast_environment_, recorded_time)); | 290 base::Bind(LogAudioEncodedEvent, cast_environment_, recorded_time)); |
292 } | 291 } |
293 | 292 |
294 } // namespace cast | 293 } // namespace cast |
295 } // namespace media | 294 } // namespace media |
OLD | NEW |