| 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_receiver/audio_decoder.h" |
| 6 |
| 7 #include "base/bind.h" |
| 8 #include "base/bind_helpers.h" |
| 9 #include "base/location.h" |
| 5 #include "base/logging.h" | 10 #include "base/logging.h" |
| 6 #include "media/cast/audio_receiver/audio_decoder.h" | 11 #include "base/memory/ref_counted.h" |
| 7 | 12 #include "base/stl_util.h" |
| 8 #include "third_party/webrtc/modules/audio_coding/main/interface/audio_coding_mo
dule.h" | 13 #include "base/sys_byteorder.h" |
| 9 #include "third_party/webrtc/modules/interface/module_common_types.h" | 14 #include "media/cast/cast_defines.h" |
| 15 #include "third_party/opus/src/include/opus.h" |
| 10 | 16 |
| 11 namespace media { | 17 namespace media { |
| 12 namespace cast { | 18 namespace cast { |
| 13 | 19 |
| 14 AudioDecoder::AudioDecoder(scoped_refptr<CastEnvironment> cast_environment, | 20 // Base class that handles the common problem of detecting dropped frames, and |
| 15 const AudioReceiverConfig& audio_config, | 21 // then invoking the Decode() method implemented by the subclasses to convert |
| 16 RtpPayloadFeedback* incoming_payload_feedback) | 22 // the encoded payload data into usable audio data. |
| 17 : cast_environment_(cast_environment), | 23 class AudioDecoder::ImplBase |
| 18 audio_decoder_(webrtc::AudioCodingModule::Create(0)), | 24 : public base::RefCountedThreadSafe<AudioDecoder::ImplBase> { |
| 19 cast_message_builder_(cast_environment->Clock(), | 25 public: |
| 20 incoming_payload_feedback, | 26 ImplBase(const scoped_refptr<CastEnvironment>& cast_environment, |
| 21 &frame_id_map_, | 27 transport::AudioCodec codec, |
| 22 audio_config.incoming_ssrc, | 28 int num_channels, |
| 23 true, | 29 int sampling_rate) |
| 24 0), | 30 : cast_environment_(cast_environment), |
| 25 have_received_packets_(false), | 31 codec_(codec), |
| 26 last_played_out_timestamp_(0) { | 32 num_channels_(num_channels), |
| 27 audio_decoder_->InitializeReceiver(); | 33 cast_initialization_status_(STATUS_AUDIO_UNINITIALIZED), |
| 28 | 34 seen_first_frame_(false) { |
| 29 webrtc::CodecInst receive_codec; | 35 if (num_channels_ <= 0 || sampling_rate <= 0 || sampling_rate % 100 != 0) |
| 36 cast_initialization_status_ = STATUS_INVALID_AUDIO_CONFIGURATION; |
| 37 } |
| 38 |
| 39 CastInitializationStatus InitializationResult() const { |
| 40 return cast_initialization_status_; |
| 41 } |
| 42 |
| 43 void DecodeFrame(scoped_ptr<transport::EncodedAudioFrame> encoded_frame, |
| 44 const DecodeFrameCallback& callback) { |
| 45 DCHECK_EQ(cast_initialization_status_, STATUS_AUDIO_INITIALIZED); |
| 46 |
| 47 scoped_ptr<AudioBus> decoded_audio; |
| 48 if (encoded_frame->codec != codec_) { |
| 49 NOTREACHED(); |
| 50 cast_environment_->PostTask(CastEnvironment::MAIN, |
| 51 FROM_HERE, |
| 52 base::Bind(callback, |
| 53 base::Passed(&decoded_audio), |
| 54 false)); |
| 55 } |
| 56 |
| 57 COMPILE_ASSERT(sizeof(encoded_frame->frame_id) == sizeof(last_frame_id_), |
| 58 size_of_frame_id_types_do_not_match); |
| 59 bool is_continuous = true; |
| 60 if (seen_first_frame_) { |
| 61 const uint32 frames_ahead = encoded_frame->frame_id - last_frame_id_; |
| 62 if (frames_ahead > 1) { |
| 63 RecoverBecauseFramesWereDropped(); |
| 64 is_continuous = false; |
| 65 } |
| 66 } else { |
| 67 seen_first_frame_ = true; |
| 68 } |
| 69 last_frame_id_ = encoded_frame->frame_id; |
| 70 |
| 71 decoded_audio = Decode( |
| 72 reinterpret_cast<uint8*>(string_as_array(&encoded_frame->data)), |
| 73 static_cast<int>(encoded_frame->data.size())); |
| 74 cast_environment_->PostTask(CastEnvironment::MAIN, |
| 75 FROM_HERE, |
| 76 base::Bind(callback, |
| 77 base::Passed(&decoded_audio), |
| 78 is_continuous)); |
| 79 } |
| 80 |
| 81 protected: |
| 82 friend class base::RefCountedThreadSafe<ImplBase>; |
| 83 virtual ~ImplBase() {} |
| 84 |
| 85 virtual void RecoverBecauseFramesWereDropped() {} |
| 86 |
| 87 // Note: Implementation of Decode() is allowed to mutate |data|. |
| 88 virtual scoped_ptr<AudioBus> Decode(uint8* data, int len) = 0; |
| 89 |
| 90 const scoped_refptr<CastEnvironment> cast_environment_; |
| 91 const transport::AudioCodec codec_; |
| 92 const int num_channels_; |
| 93 |
| 94 // Subclass' ctor is expected to set this to STATUS_AUDIO_INITIALIZED. |
| 95 CastInitializationStatus cast_initialization_status_; |
| 96 |
| 97 private: |
| 98 bool seen_first_frame_; |
| 99 uint32 last_frame_id_; |
| 100 |
| 101 DISALLOW_COPY_AND_ASSIGN(ImplBase); |
| 102 }; |
| 103 |
| 104 class AudioDecoder::OpusImpl : public AudioDecoder::ImplBase { |
| 105 public: |
| 106 OpusImpl(const scoped_refptr<CastEnvironment>& cast_environment, |
| 107 int num_channels, |
| 108 int sampling_rate) |
| 109 : ImplBase(cast_environment, |
| 110 transport::kOpus, |
| 111 num_channels, |
| 112 sampling_rate), |
| 113 decoder_memory_(new uint8[opus_decoder_get_size(num_channels)]), |
| 114 opus_decoder_(reinterpret_cast<OpusDecoder*>(decoder_memory_.get())), |
| 115 max_samples_per_frame_( |
| 116 kOpusMaxFrameDurationMillis * sampling_rate / 1000), |
| 117 buffer_(new float[max_samples_per_frame_ * num_channels]) { |
| 118 if (ImplBase::cast_initialization_status_ != STATUS_AUDIO_UNINITIALIZED) |
| 119 return; |
| 120 if (opus_decoder_init(opus_decoder_, sampling_rate, num_channels) != |
| 121 OPUS_OK) { |
| 122 ImplBase::cast_initialization_status_ = |
| 123 STATUS_INVALID_AUDIO_CONFIGURATION; |
| 124 return; |
| 125 } |
| 126 ImplBase::cast_initialization_status_ = STATUS_AUDIO_INITIALIZED; |
| 127 } |
| 128 |
| 129 private: |
| 130 virtual ~OpusImpl() {} |
| 131 |
| 132 virtual void RecoverBecauseFramesWereDropped() OVERRIDE { |
| 133 // Passing NULL for the input data notifies the decoder of frame loss. |
| 134 const opus_int32 result = |
| 135 opus_decode_float( |
| 136 opus_decoder_, NULL, 0, buffer_.get(), max_samples_per_frame_, 0); |
| 137 DCHECK_GE(result, 0); |
| 138 } |
| 139 |
| 140 virtual scoped_ptr<AudioBus> Decode(uint8* data, int len) OVERRIDE { |
| 141 scoped_ptr<AudioBus> audio_bus; |
| 142 const opus_int32 num_samples_decoded = opus_decode_float( |
| 143 opus_decoder_, data, len, buffer_.get(), max_samples_per_frame_, 0); |
| 144 if (num_samples_decoded <= 0) |
| 145 return audio_bus.Pass(); // Decode error. |
| 146 |
| 147 // Copy interleaved samples from |buffer_| into a new AudioBus (where |
| 148 // samples are stored in planar format, for each channel). |
| 149 audio_bus = AudioBus::Create(num_channels_, num_samples_decoded).Pass(); |
| 150 // TODO(miu): This should be moved into AudioBus::FromInterleaved(). |
| 151 for (int ch = 0; ch < num_channels_; ++ch) { |
| 152 const float* src = buffer_.get() + ch; |
| 153 const float* const src_end = src + num_samples_decoded * num_channels_; |
| 154 float* dest = audio_bus->channel(ch); |
| 155 for (; src < src_end; src += num_channels_, ++dest) |
| 156 *dest = *src; |
| 157 } |
| 158 return audio_bus.Pass(); |
| 159 } |
| 160 |
| 161 const scoped_ptr<uint8[]> decoder_memory_; |
| 162 OpusDecoder* const opus_decoder_; |
| 163 const int max_samples_per_frame_; |
| 164 const scoped_ptr<float[]> buffer_; |
| 165 |
| 166 // According to documentation in third_party/opus/src/include/opus.h, we must |
| 167 // provide enough space in |buffer_| to contain 120ms of samples. At 48 kHz, |
| 168 // then, that means 5760 samples times the number of channels. |
| 169 static const int kOpusMaxFrameDurationMillis = 120; |
| 170 |
| 171 DISALLOW_COPY_AND_ASSIGN(OpusImpl); |
| 172 }; |
| 173 |
| 174 class AudioDecoder::Pcm16Impl : public AudioDecoder::ImplBase { |
| 175 public: |
| 176 Pcm16Impl(const scoped_refptr<CastEnvironment>& cast_environment, |
| 177 int num_channels, |
| 178 int sampling_rate) |
| 179 : ImplBase(cast_environment, |
| 180 transport::kPcm16, |
| 181 num_channels, |
| 182 sampling_rate) { |
| 183 if (ImplBase::cast_initialization_status_ != STATUS_AUDIO_UNINITIALIZED) |
| 184 return; |
| 185 ImplBase::cast_initialization_status_ = STATUS_AUDIO_INITIALIZED; |
| 186 } |
| 187 |
| 188 private: |
| 189 virtual ~Pcm16Impl() {} |
| 190 |
| 191 virtual scoped_ptr<AudioBus> Decode(uint8* data, int len) OVERRIDE { |
| 192 scoped_ptr<AudioBus> audio_bus; |
| 193 const int num_samples = len / sizeof(int16) / num_channels_; |
| 194 if (num_samples <= 0) |
| 195 return audio_bus.Pass(); |
| 196 |
| 197 int16* const pcm_data = reinterpret_cast<int16*>(data); |
| 198 #if defined(ARCH_CPU_LITTLE_ENDIAN) |
| 199 // Convert endianness. |
| 200 const int num_elements = num_samples * num_channels_; |
| 201 for (int i = 0; i < num_elements; ++i) |
| 202 pcm_data[i] = static_cast<int16>(base::NetToHost16(pcm_data[i])); |
| 203 #endif |
| 204 audio_bus = AudioBus::Create(num_channels_, num_samples).Pass(); |
| 205 audio_bus->FromInterleaved(pcm_data, num_samples, sizeof(int16)); |
| 206 return audio_bus.Pass(); |
| 207 } |
| 208 |
| 209 DISALLOW_COPY_AND_ASSIGN(Pcm16Impl); |
| 210 }; |
| 211 |
| 212 AudioDecoder::AudioDecoder( |
| 213 const scoped_refptr<CastEnvironment>& cast_environment, |
| 214 const AudioReceiverConfig& audio_config) |
| 215 : cast_environment_(cast_environment) { |
| 30 switch (audio_config.codec) { | 216 switch (audio_config.codec) { |
| 217 case transport::kOpus: |
| 218 impl_ = new OpusImpl(cast_environment, |
| 219 audio_config.channels, |
| 220 audio_config.frequency); |
| 221 break; |
| 31 case transport::kPcm16: | 222 case transport::kPcm16: |
| 32 receive_codec.pltype = audio_config.rtp_payload_type; | 223 impl_ = new Pcm16Impl(cast_environment, |
| 33 strncpy(receive_codec.plname, "L16", 4); | 224 audio_config.channels, |
| 34 receive_codec.plfreq = audio_config.frequency; | 225 audio_config.frequency); |
| 35 receive_codec.pacsize = -1; | |
| 36 receive_codec.channels = audio_config.channels; | |
| 37 receive_codec.rate = -1; | |
| 38 break; | 226 break; |
| 39 case transport::kOpus: | 227 default: |
| 40 receive_codec.pltype = audio_config.rtp_payload_type; | 228 NOTREACHED() << "Unknown or unspecified codec."; |
| 41 strncpy(receive_codec.plname, "opus", 5); | |
| 42 receive_codec.plfreq = audio_config.frequency; | |
| 43 receive_codec.pacsize = -1; | |
| 44 receive_codec.channels = audio_config.channels; | |
| 45 receive_codec.rate = -1; | |
| 46 break; | 229 break; |
| 47 case transport::kExternalAudio: | 230 } |
| 48 NOTREACHED() << "Codec must be specified for audio decoder"; | |
| 49 break; | |
| 50 } | |
| 51 if (audio_decoder_->RegisterReceiveCodec(receive_codec) != 0) { | |
| 52 NOTREACHED() << "Failed to register receive codec"; | |
| 53 } | |
| 54 | |
| 55 audio_decoder_->SetMaximumPlayoutDelay(audio_config.rtp_max_delay_ms); | |
| 56 audio_decoder_->SetPlayoutMode(webrtc::streaming); | |
| 57 } | 231 } |
| 58 | 232 |
| 59 AudioDecoder::~AudioDecoder() {} | 233 AudioDecoder::~AudioDecoder() {} |
| 60 | 234 |
| 61 bool AudioDecoder::GetRawAudioFrame(int number_of_10ms_blocks, | 235 CastInitializationStatus AudioDecoder::InitializationResult() const { |
| 62 int desired_frequency, | 236 if (impl_) |
| 63 PcmAudioFrame* audio_frame, | 237 return impl_->InitializationResult(); |
| 64 uint32* rtp_timestamp) { | 238 return STATUS_UNSUPPORTED_AUDIO_CODEC; |
| 65 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::AUDIO)); | |
| 66 // We don't care about the race case where a packet arrives at the same time | |
| 67 // as this function in called. The data will be there the next time this | |
| 68 // function is called. | |
| 69 lock_.Acquire(); | |
| 70 // Get a local copy under lock. | |
| 71 bool have_received_packets = have_received_packets_; | |
| 72 lock_.Release(); | |
| 73 | |
| 74 if (!have_received_packets) | |
| 75 return false; | |
| 76 | |
| 77 audio_frame->samples.clear(); | |
| 78 | |
| 79 for (int i = 0; i < number_of_10ms_blocks; ++i) { | |
| 80 webrtc::AudioFrame webrtc_audio_frame; | |
| 81 if (0 != audio_decoder_->PlayoutData10Ms(desired_frequency, | |
| 82 &webrtc_audio_frame)) { | |
| 83 return false; | |
| 84 } | |
| 85 if (webrtc_audio_frame.speech_type_ == webrtc::AudioFrame::kPLCCNG || | |
| 86 webrtc_audio_frame.speech_type_ == webrtc::AudioFrame::kUndefined) { | |
| 87 // We are only interested in real decoded audio. | |
| 88 return false; | |
| 89 } | |
| 90 audio_frame->frequency = webrtc_audio_frame.sample_rate_hz_; | |
| 91 audio_frame->channels = webrtc_audio_frame.num_channels_; | |
| 92 | |
| 93 if (i == 0) { | |
| 94 // Use the timestamp from the first 10ms block. | |
| 95 if (0 != audio_decoder_->PlayoutTimestamp(rtp_timestamp)) { | |
| 96 return false; | |
| 97 } | |
| 98 lock_.Acquire(); | |
| 99 last_played_out_timestamp_ = *rtp_timestamp; | |
| 100 lock_.Release(); | |
| 101 } | |
| 102 int samples_per_10ms = webrtc_audio_frame.samples_per_channel_; | |
| 103 | |
| 104 audio_frame->samples.insert( | |
| 105 audio_frame->samples.end(), | |
| 106 &webrtc_audio_frame.data_[0], | |
| 107 &webrtc_audio_frame.data_[samples_per_10ms * audio_frame->channels]); | |
| 108 } | |
| 109 return true; | |
| 110 } | 239 } |
| 111 | 240 |
| 112 void AudioDecoder::IncomingParsedRtpPacket(const uint8* payload_data, | 241 void AudioDecoder::DecodeFrame( |
| 113 size_t payload_size, | 242 scoped_ptr<transport::EncodedAudioFrame> encoded_frame, |
| 114 const RtpCastHeader& rtp_header) { | 243 const DecodeFrameCallback& callback) { |
| 115 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 244 DCHECK(encoded_frame.get()); |
| 116 DCHECK_LE(payload_size, kMaxIpPacketSize); | 245 DCHECK(!callback.is_null()); |
| 117 audio_decoder_->IncomingPacket( | 246 if (!impl_ || impl_->InitializationResult() != STATUS_AUDIO_INITIALIZED) { |
| 118 payload_data, static_cast<int32>(payload_size), rtp_header.webrtc); | 247 callback.Run(make_scoped_ptr<AudioBus>(NULL), false); |
| 119 lock_.Acquire(); | |
| 120 have_received_packets_ = true; | |
| 121 uint32 last_played_out_timestamp = last_played_out_timestamp_; | |
| 122 lock_.Release(); | |
| 123 | |
| 124 PacketType packet_type = frame_id_map_.InsertPacket(rtp_header); | |
| 125 if (packet_type != kNewPacketCompletingFrame) | |
| 126 return; | 248 return; |
| 127 | 249 } |
| 128 cast_message_builder_.CompleteFrameReceived(rtp_header.frame_id, | 250 cast_environment_->PostTask(CastEnvironment::AUDIO, |
| 129 rtp_header.is_key_frame); | 251 FROM_HERE, |
| 130 | 252 base::Bind(&AudioDecoder::ImplBase::DecodeFrame, |
| 131 frame_id_rtp_timestamp_map_[rtp_header.frame_id] = | 253 impl_, |
| 132 rtp_header.webrtc.header.timestamp; | 254 base::Passed(&encoded_frame), |
| 133 | 255 callback)); |
| 134 if (last_played_out_timestamp == 0) | |
| 135 return; // Nothing is played out yet. | |
| 136 | |
| 137 uint32 latest_frame_id_to_remove = 0; | |
| 138 bool frame_to_remove = false; | |
| 139 | |
| 140 FrameIdRtpTimestampMap::iterator it = frame_id_rtp_timestamp_map_.begin(); | |
| 141 while (it != frame_id_rtp_timestamp_map_.end()) { | |
| 142 if (IsNewerRtpTimestamp(it->second, last_played_out_timestamp)) { | |
| 143 break; | |
| 144 } | |
| 145 frame_to_remove = true; | |
| 146 latest_frame_id_to_remove = it->first; | |
| 147 frame_id_rtp_timestamp_map_.erase(it); | |
| 148 it = frame_id_rtp_timestamp_map_.begin(); | |
| 149 } | |
| 150 if (!frame_to_remove) | |
| 151 return; | |
| 152 | |
| 153 frame_id_map_.RemoveOldFrames(latest_frame_id_to_remove); | |
| 154 } | 256 } |
| 155 | 257 |
| 156 bool AudioDecoder::TimeToSendNextCastMessage(base::TimeTicks* time_to_send) { | |
| 157 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | |
| 158 return cast_message_builder_.TimeToSendNextCastMessage(time_to_send); | |
| 159 } | |
| 160 | |
| 161 void AudioDecoder::SendCastMessage() { | |
| 162 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | |
| 163 cast_message_builder_.UpdateCastMessage(); | |
| 164 } | |
| 165 | |
| 166 } // namespace cast | 258 } // namespace cast |
| 167 } // namespace media | 259 } // namespace media |
| OLD | NEW |