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
32 // Maps input channel 0 to coded channel 3, which doesn't exist.
33 EXPECT_FALSE(encoder_config.has_value());
34 }
35
36 {
37 const SdpAudioFormat sdp_format("multiopus", 48000, 2,
38 {{"channel_mapping", "0"},
39 {"coupled_streams", "1"},
40 {"num_streams", "2"}});
41 const absl::optional<AudioEncoderMultiChannelOpus::Config> encoder_config =
42 AudioEncoderMultiChannelOpus::SdpToConfig(sdp_format);
43
44 // The mapping is too short.
45 EXPECT_FALSE(encoder_config.has_value());
46 }
47 {
48 const SdpAudioFormat sdp_format("multiopus", 48000, 3,
49 {{"channel_mapping", "0,0,0"},
50 {"coupled_streams", "0"},
51 {"num_streams", "1"}});
52 const absl::optional<AudioEncoderMultiChannelOpus::Config> encoder_config =
53 AudioEncoderMultiChannelOpus::SdpToConfig(sdp_format);
54
55 // Coded channel 0 comes from both input channels 0, 1 and 2.
56 EXPECT_FALSE(encoder_config.has_value());
57 }
58 {
59 const SdpAudioFormat sdp_format("multiopus", 48000, 3,
60 {{"channel_mapping", "0,255,255"},
61 {"coupled_streams", "0"},
62 {"num_streams", "1"}});
63 const absl::optional<AudioEncoderMultiChannelOpus::Config> encoder_config =
64 AudioEncoderMultiChannelOpus::SdpToConfig(sdp_format);
65 ASSERT_TRUE(encoder_config.has_value());
66
67 // This is fine, because channels 1, 2 are set to be ignored.
68 EXPECT_TRUE(encoder_config->IsOk());
69 }
70 {
71 const SdpAudioFormat sdp_format("multiopus", 48000, 3,
72 {{"channel_mapping", "0,255,255"},
73 {"coupled_streams", "0"},
74 {"num_streams", "2"}});
75 const absl::optional<AudioEncoderMultiChannelOpus::Config> encoder_config =
76 AudioEncoderMultiChannelOpus::SdpToConfig(sdp_format);
77
78 // This is NOT fine, because channels nothing says how coded channel 1
79 // should be coded.
80 EXPECT_FALSE(encoder_config.has_value());
81 }
82 }
83
TEST(AudioEncoderMultiOpusTest,ConfigValuesAreParsedCorrectly)84 TEST(AudioEncoderMultiOpusTest, ConfigValuesAreParsedCorrectly) {
85 SdpAudioFormat sdp_format({"multiopus",
86 48000,
87 6,
88 {{"minptime", "10"},
89 {"useinbandfec", "1"},
90 {"channel_mapping", "0,4,1,2,3,5"},
91 {"num_streams", "4"},
92 {"coupled_streams", "2"}}});
93 const absl::optional<AudioEncoderMultiChannelOpus::Config> encoder_config =
94 AudioEncoderMultiChannelOpus::SdpToConfig(sdp_format);
95 ASSERT_TRUE(encoder_config.has_value());
96
97 EXPECT_EQ(encoder_config->coupled_streams, 2);
98 EXPECT_EQ(encoder_config->num_streams, 4);
99 EXPECT_THAT(
100 encoder_config->channel_mapping,
101 testing::ContainerEq(std::vector<unsigned char>({0, 4, 1, 2, 3, 5})));
102 }
103
TEST(AudioEncoderMultiOpusTest,CreateFromValidConfig)104 TEST(AudioEncoderMultiOpusTest, CreateFromValidConfig) {
105 {
106 const SdpAudioFormat sdp_format("multiopus", 48000, 3,
107 {{"channel_mapping", "0,255,255"},
108 {"coupled_streams", "0"},
109 {"num_streams", "2"}});
110 const absl::optional<AudioEncoderMultiChannelOpus::Config> encoder_config =
111 AudioEncoderMultiChannelOpus::SdpToConfig(sdp_format);
112 ASSERT_FALSE(encoder_config.has_value());
113 }
114 {
115 const SdpAudioFormat sdp_format("multiopus", 48000, 3,
116 {{"channel_mapping", "1,255,0"},
117 {"coupled_streams", "1"},
118 {"num_streams", "1"}});
119 const absl::optional<AudioEncoderMultiChannelOpus::Config> encoder_config =
120 AudioEncoderMultiChannelOpus::SdpToConfig(sdp_format);
121 ASSERT_TRUE(encoder_config.has_value());
122
123 EXPECT_THAT(encoder_config->channel_mapping,
124 testing::ContainerEq(std::vector<unsigned char>({1, 255, 0})));
125
126 EXPECT_TRUE(encoder_config->IsOk());
127
128 const std::unique_ptr<AudioEncoder> opus_encoder =
129 AudioEncoderMultiChannelOpus::MakeAudioEncoder(*encoder_config,
130 kOpusPayloadType);
131
132 // Creating an encoder from a valid config should work.
133 EXPECT_TRUE(opus_encoder);
134 }
135 }
136
TEST(AudioEncoderMultiOpusTest,AdvertisedCodecsCanBeCreated)137 TEST(AudioEncoderMultiOpusTest, AdvertisedCodecsCanBeCreated) {
138 std::vector<AudioCodecSpec> specs;
139 AudioEncoderMultiChannelOpus::AppendSupportedEncoders(&specs);
140
141 EXPECT_FALSE(specs.empty());
142
143 for (const AudioCodecSpec& spec : specs) {
144 const absl::optional<AudioEncoderMultiChannelOpus::Config> encoder_config =
145 AudioEncoderMultiChannelOpus::SdpToConfig(spec.format);
146 ASSERT_TRUE(encoder_config.has_value());
147
148 const std::unique_ptr<AudioEncoder> opus_encoder =
149 AudioEncoderMultiChannelOpus::MakeAudioEncoder(*encoder_config,
150 kOpusPayloadType);
151
152 EXPECT_TRUE(opus_encoder);
153 }
154 }
155
156 } // namespace webrtc
157