• 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 "api/audio_codecs/opus/audio_encoder_multi_channel_opus.h"
12 
13 #include "test/gmock.h"
14 
15 namespace webrtc {
16 using ::testing::NiceMock;
17 using ::testing::Return;
18 
19 namespace {
20 constexpr int kOpusPayloadType = 120;
21 }  // namespace
22 
TEST(AudioEncoderMultiOpusTest,CheckConfigValidity)23 TEST(AudioEncoderMultiOpusTest, CheckConfigValidity) {
24   {
25     const SdpAudioFormat sdp_format("multiopus", 48000, 2,
26                                     {{"channel_mapping", "3,0"},
27                                      {"coupled_streams", "1"},
28                                      {"num_streams", "2"}});
29     const absl::optional<AudioEncoderMultiChannelOpus::Config> encoder_config =
30         AudioEncoderMultiChannelOpus::SdpToConfig(sdp_format);
31     ASSERT_TRUE(encoder_config.has_value());
32 
33     // Maps input channel 0 to coded channel 3, which doesn't exist.
34     EXPECT_FALSE(encoder_config->IsOk());
35   }
36 
37   {
38     const SdpAudioFormat sdp_format("multiopus", 48000, 2,
39                                     {{"channel_mapping", "0"},
40                                      {"coupled_streams", "1"},
41                                      {"num_streams", "2"}});
42     const absl::optional<AudioEncoderMultiChannelOpus::Config> encoder_config =
43         AudioEncoderMultiChannelOpus::SdpToConfig(sdp_format);
44     ASSERT_TRUE(encoder_config.has_value());
45 
46     // The mapping is too short.
47     EXPECT_FALSE(encoder_config->IsOk());
48   }
49   {
50     const SdpAudioFormat sdp_format("multiopus", 48000, 3,
51                                     {{"channel_mapping", "0,0,0"},
52                                      {"coupled_streams", "0"},
53                                      {"num_streams", "1"}});
54     const absl::optional<AudioEncoderMultiChannelOpus::Config> encoder_config =
55         AudioEncoderMultiChannelOpus::SdpToConfig(sdp_format);
56     ASSERT_TRUE(encoder_config.has_value());
57 
58     // Coded channel 0 comes from both input channels 0, 1 and 2.
59     EXPECT_FALSE(encoder_config->IsOk());
60   }
61   {
62     const SdpAudioFormat sdp_format("multiopus", 48000, 3,
63                                     {{"channel_mapping", "0,255,255"},
64                                      {"coupled_streams", "0"},
65                                      {"num_streams", "1"}});
66     const absl::optional<AudioEncoderMultiChannelOpus::Config> encoder_config =
67         AudioEncoderMultiChannelOpus::SdpToConfig(sdp_format);
68     ASSERT_TRUE(encoder_config.has_value());
69 
70     // This is fine, because channels 1, 2 are set to be ignored.
71     EXPECT_TRUE(encoder_config->IsOk());
72   }
73   {
74     const SdpAudioFormat sdp_format("multiopus", 48000, 3,
75                                     {{"channel_mapping", "0,255,255"},
76                                      {"coupled_streams", "0"},
77                                      {"num_streams", "2"}});
78     const absl::optional<AudioEncoderMultiChannelOpus::Config> encoder_config =
79         AudioEncoderMultiChannelOpus::SdpToConfig(sdp_format);
80     ASSERT_TRUE(encoder_config.has_value());
81 
82     // This is NOT fine, because channels nothing says how coded channel 1
83     // should be coded.
84     EXPECT_FALSE(encoder_config->IsOk());
85   }
86 }
87 
TEST(AudioEncoderMultiOpusTest,ConfigValuesAreParsedCorrectly)88 TEST(AudioEncoderMultiOpusTest, ConfigValuesAreParsedCorrectly) {
89   SdpAudioFormat sdp_format({"multiopus",
90                              48000,
91                              6,
92                              {{"minptime", "10"},
93                               {"useinbandfec", "1"},
94                               {"channel_mapping", "0,4,1,2,3,5"},
95                               {"num_streams", "4"},
96                               {"coupled_streams", "2"}}});
97   const absl::optional<AudioEncoderMultiChannelOpus::Config> encoder_config =
98       AudioEncoderMultiChannelOpus::SdpToConfig(sdp_format);
99   ASSERT_TRUE(encoder_config.has_value());
100 
101   EXPECT_EQ(encoder_config->coupled_streams, 2);
102   EXPECT_EQ(encoder_config->num_streams, 4);
103   EXPECT_THAT(
104       encoder_config->channel_mapping,
105       testing::ContainerEq(std::vector<unsigned char>({0, 4, 1, 2, 3, 5})));
106 }
107 
TEST(AudioEncoderMultiOpusTest,CreateFromValidOrInvalidConfig)108 TEST(AudioEncoderMultiOpusTest, CreateFromValidOrInvalidConfig) {
109   {
110     const SdpAudioFormat sdp_format("multiopus", 48000, 3,
111                                     {{"channel_mapping", "0,255,255"},
112                                      {"coupled_streams", "0"},
113                                      {"num_streams", "2"}});
114     const absl::optional<AudioEncoderMultiChannelOpus::Config> encoder_config =
115         AudioEncoderMultiChannelOpus::SdpToConfig(sdp_format);
116     ASSERT_TRUE(encoder_config.has_value());
117 
118     // Invalid config from the ConfigValidity test. It's not allowed by our
119     // checks, but Opus is more forgiving.
120     EXPECT_FALSE(encoder_config->IsOk());
121 
122     const std::unique_ptr<AudioEncoder> opus_encoder =
123         AudioEncoderMultiChannelOpus::MakeAudioEncoder(*encoder_config,
124                                                        kOpusPayloadType);
125 
126     // Shouldn't be possible (but shouldn't result in a crash) to create an
127     // Encoder from an invalid config.
128     EXPECT_FALSE(opus_encoder);
129   }
130   {
131     const SdpAudioFormat sdp_format("multiopus", 48000, 3,
132                                     {{"channel_mapping", "1,255,0"},
133                                      {"coupled_streams", "1"},
134                                      {"num_streams", "1"}});
135     const absl::optional<AudioEncoderMultiChannelOpus::Config> encoder_config =
136         AudioEncoderMultiChannelOpus::SdpToConfig(sdp_format);
137     ASSERT_TRUE(encoder_config.has_value());
138 
139     EXPECT_THAT(encoder_config->channel_mapping,
140                 testing::ContainerEq(std::vector<unsigned char>({1, 255, 0})));
141 
142     EXPECT_TRUE(encoder_config->IsOk());
143 
144     const std::unique_ptr<AudioEncoder> opus_encoder =
145         AudioEncoderMultiChannelOpus::MakeAudioEncoder(*encoder_config,
146                                                        kOpusPayloadType);
147 
148     // Creating an encoder from a valid config should work.
149     EXPECT_TRUE(opus_encoder);
150   }
151 }
152 
TEST(AudioEncoderMultiOpusTest,AdvertisedCodecsCanBeCreated)153 TEST(AudioEncoderMultiOpusTest, AdvertisedCodecsCanBeCreated) {
154   std::vector<AudioCodecSpec> specs;
155   AudioEncoderMultiChannelOpus::AppendSupportedEncoders(&specs);
156 
157   EXPECT_FALSE(specs.empty());
158 
159   for (const AudioCodecSpec& spec : specs) {
160     const absl::optional<AudioEncoderMultiChannelOpus::Config> encoder_config =
161         AudioEncoderMultiChannelOpus::SdpToConfig(spec.format);
162     ASSERT_TRUE(encoder_config.has_value());
163 
164     const std::unique_ptr<AudioEncoder> opus_encoder =
165         AudioEncoderMultiChannelOpus::MakeAudioEncoder(*encoder_config,
166                                                        kOpusPayloadType);
167 
168     EXPECT_TRUE(opus_encoder);
169   }
170 }
171 
172 }  // namespace webrtc
173