| 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 |