• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "modules/audio_coding/codecs/opus/audio_decoder_multi_channel_opus_impl.h"
12 
13 #include <algorithm>
14 #include <memory>
15 #include <string>
16 #include <utility>
17 #include <vector>
18 
19 #include "absl/memory/memory.h"
20 #include "modules/audio_coding/codecs/opus/audio_coder_opus_common.h"
21 #include "rtc_base/string_to_number.h"
22 
23 namespace webrtc {
24 
25 std::unique_ptr<AudioDecoderMultiChannelOpusImpl>
MakeAudioDecoder(AudioDecoderMultiChannelOpusConfig config)26 AudioDecoderMultiChannelOpusImpl::MakeAudioDecoder(
27     AudioDecoderMultiChannelOpusConfig config) {
28   if (!config.IsOk()) {
29     RTC_DCHECK_NOTREACHED();
30     return nullptr;
31   }
32   // Fill the pointer with a working decoder through the C interface. This
33   // allocates memory.
34   OpusDecInst* dec_state = nullptr;
35   const int error = WebRtcOpus_MultistreamDecoderCreate(
36       &dec_state, config.num_channels, config.num_streams,
37       config.coupled_streams, config.channel_mapping.data());
38   if (error != 0) {
39     return nullptr;
40   }
41 
42   // Pass the ownership to DecoderImpl. Not using 'make_unique' because the
43   // c-tor is private.
44   return std::unique_ptr<AudioDecoderMultiChannelOpusImpl>(
45       new AudioDecoderMultiChannelOpusImpl(dec_state, config));
46 }
47 
AudioDecoderMultiChannelOpusImpl(OpusDecInst * dec_state,AudioDecoderMultiChannelOpusConfig config)48 AudioDecoderMultiChannelOpusImpl::AudioDecoderMultiChannelOpusImpl(
49     OpusDecInst* dec_state,
50     AudioDecoderMultiChannelOpusConfig config)
51     : dec_state_(dec_state), config_(config) {
52   RTC_DCHECK(dec_state);
53   WebRtcOpus_DecoderInit(dec_state_);
54 }
55 
~AudioDecoderMultiChannelOpusImpl()56 AudioDecoderMultiChannelOpusImpl::~AudioDecoderMultiChannelOpusImpl() {
57   WebRtcOpus_DecoderFree(dec_state_);
58 }
59 
60 absl::optional<AudioDecoderMultiChannelOpusConfig>
SdpToConfig(const SdpAudioFormat & format)61 AudioDecoderMultiChannelOpusImpl::SdpToConfig(const SdpAudioFormat& format) {
62   AudioDecoderMultiChannelOpusConfig config;
63   config.num_channels = format.num_channels;
64   auto num_streams = GetFormatParameter<int>(format, "num_streams");
65   if (!num_streams.has_value()) {
66     return absl::nullopt;
67   }
68   config.num_streams = *num_streams;
69 
70   auto coupled_streams = GetFormatParameter<int>(format, "coupled_streams");
71   if (!coupled_streams.has_value()) {
72     return absl::nullopt;
73   }
74   config.coupled_streams = *coupled_streams;
75 
76   auto channel_mapping =
77       GetFormatParameter<std::vector<unsigned char>>(format, "channel_mapping");
78   if (!channel_mapping.has_value()) {
79     return absl::nullopt;
80   }
81   config.channel_mapping = *channel_mapping;
82   if (!config.IsOk()) {
83     return absl::nullopt;
84   }
85   return config;
86 }
87 
88 std::vector<AudioDecoder::ParseResult>
ParsePayload(rtc::Buffer && payload,uint32_t timestamp)89 AudioDecoderMultiChannelOpusImpl::ParsePayload(rtc::Buffer&& payload,
90                                                uint32_t timestamp) {
91   std::vector<ParseResult> results;
92 
93   if (PacketHasFec(payload.data(), payload.size())) {
94     const int duration =
95         PacketDurationRedundant(payload.data(), payload.size());
96     RTC_DCHECK_GE(duration, 0);
97     rtc::Buffer payload_copy(payload.data(), payload.size());
98     std::unique_ptr<EncodedAudioFrame> fec_frame(
99         new OpusFrame(this, std::move(payload_copy), false));
100     results.emplace_back(timestamp - duration, 1, std::move(fec_frame));
101   }
102   std::unique_ptr<EncodedAudioFrame> frame(
103       new OpusFrame(this, std::move(payload), true));
104   results.emplace_back(timestamp, 0, std::move(frame));
105   return results;
106 }
107 
DecodeInternal(const uint8_t * encoded,size_t encoded_len,int sample_rate_hz,int16_t * decoded,SpeechType * speech_type)108 int AudioDecoderMultiChannelOpusImpl::DecodeInternal(const uint8_t* encoded,
109                                                      size_t encoded_len,
110                                                      int sample_rate_hz,
111                                                      int16_t* decoded,
112                                                      SpeechType* speech_type) {
113   RTC_DCHECK_EQ(sample_rate_hz, 48000);
114   int16_t temp_type = 1;  // Default is speech.
115   int ret =
116       WebRtcOpus_Decode(dec_state_, encoded, encoded_len, decoded, &temp_type);
117   if (ret > 0)
118     ret *= static_cast<int>(
119         config_.num_channels);  // Return total number of samples.
120   *speech_type = ConvertSpeechType(temp_type);
121   return ret;
122 }
123 
DecodeRedundantInternal(const uint8_t * encoded,size_t encoded_len,int sample_rate_hz,int16_t * decoded,SpeechType * speech_type)124 int AudioDecoderMultiChannelOpusImpl::DecodeRedundantInternal(
125     const uint8_t* encoded,
126     size_t encoded_len,
127     int sample_rate_hz,
128     int16_t* decoded,
129     SpeechType* speech_type) {
130   if (!PacketHasFec(encoded, encoded_len)) {
131     // This packet is a RED packet.
132     return DecodeInternal(encoded, encoded_len, sample_rate_hz, decoded,
133                           speech_type);
134   }
135 
136   RTC_DCHECK_EQ(sample_rate_hz, 48000);
137   int16_t temp_type = 1;  // Default is speech.
138   int ret = WebRtcOpus_DecodeFec(dec_state_, encoded, encoded_len, decoded,
139                                  &temp_type);
140   if (ret > 0)
141     ret *= static_cast<int>(
142         config_.num_channels);  // Return total number of samples.
143   *speech_type = ConvertSpeechType(temp_type);
144   return ret;
145 }
146 
Reset()147 void AudioDecoderMultiChannelOpusImpl::Reset() {
148   WebRtcOpus_DecoderInit(dec_state_);
149 }
150 
PacketDuration(const uint8_t * encoded,size_t encoded_len) const151 int AudioDecoderMultiChannelOpusImpl::PacketDuration(const uint8_t* encoded,
152                                                      size_t encoded_len) const {
153   return WebRtcOpus_DurationEst(dec_state_, encoded, encoded_len);
154 }
155 
PacketDurationRedundant(const uint8_t * encoded,size_t encoded_len) const156 int AudioDecoderMultiChannelOpusImpl::PacketDurationRedundant(
157     const uint8_t* encoded,
158     size_t encoded_len) const {
159   if (!PacketHasFec(encoded, encoded_len)) {
160     // This packet is a RED packet.
161     return PacketDuration(encoded, encoded_len);
162   }
163 
164   return WebRtcOpus_FecDurationEst(encoded, encoded_len, 48000);
165 }
166 
PacketHasFec(const uint8_t * encoded,size_t encoded_len) const167 bool AudioDecoderMultiChannelOpusImpl::PacketHasFec(const uint8_t* encoded,
168                                                     size_t encoded_len) const {
169   int fec;
170   fec = WebRtcOpus_PacketHasFec(encoded, encoded_len);
171   return (fec == 1);
172 }
173 
SampleRateHz() const174 int AudioDecoderMultiChannelOpusImpl::SampleRateHz() const {
175   return 48000;
176 }
177 
Channels() const178 size_t AudioDecoderMultiChannelOpusImpl::Channels() const {
179   return config_.num_channels;
180 }
181 
182 }  // namespace webrtc
183