OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2004 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2004 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
(...skipping 19 matching lines...) Expand all Loading... | |
30 #include "webrtc/base/stringutils.h" | 30 #include "webrtc/base/stringutils.h" |
31 #include "webrtc/base/trace_event.h" | 31 #include "webrtc/base/trace_event.h" |
32 #include "webrtc/media/base/audiosource.h" | 32 #include "webrtc/media/base/audiosource.h" |
33 #include "webrtc/media/base/mediaconstants.h" | 33 #include "webrtc/media/base/mediaconstants.h" |
34 #include "webrtc/media/base/streamparams.h" | 34 #include "webrtc/media/base/streamparams.h" |
35 #include "webrtc/media/engine/payload_type_mapper.h" | 35 #include "webrtc/media/engine/payload_type_mapper.h" |
36 #include "webrtc/media/engine/webrtcmediaengine.h" | 36 #include "webrtc/media/engine/webrtcmediaengine.h" |
37 #include "webrtc/media/engine/webrtcvoe.h" | 37 #include "webrtc/media/engine/webrtcvoe.h" |
38 #include "webrtc/modules/audio_coding/acm2/rent_a_codec.h" | 38 #include "webrtc/modules/audio_coding/acm2/rent_a_codec.h" |
39 #include "webrtc/modules/audio_mixer/audio_mixer_impl.h" | 39 #include "webrtc/modules/audio_mixer/audio_mixer_impl.h" |
40 #include "webrtc/modules/audio_coding/codecs/builtin_audio_encoder_factory.h" | |
40 #include "webrtc/modules/audio_processing/include/audio_processing.h" | 41 #include "webrtc/modules/audio_processing/include/audio_processing.h" |
41 #include "webrtc/system_wrappers/include/field_trial.h" | 42 #include "webrtc/system_wrappers/include/field_trial.h" |
42 #include "webrtc/system_wrappers/include/trace.h" | 43 #include "webrtc/system_wrappers/include/trace.h" |
43 | 44 |
44 namespace cricket { | 45 namespace cricket { |
45 namespace { | 46 namespace { |
46 | 47 |
47 const int kDefaultTraceFilter = webrtc::kTraceNone | webrtc::kTraceTerseInfo | | 48 const int kDefaultTraceFilter = webrtc::kTraceNone | webrtc::kTraceTerseInfo | |
48 webrtc::kTraceWarning | webrtc::kTraceError | | 49 webrtc::kTraceWarning | webrtc::kTraceError | |
49 webrtc::kTraceCritical; | 50 webrtc::kTraceCritical; |
(...skipping 15 matching lines...) Expand all Loading... | |
65 constexpr int kNackRtpHistoryMs = 5000; | 66 constexpr int kNackRtpHistoryMs = 5000; |
66 | 67 |
67 // Check to verify that the define for the intelligibility enhancer is properly | 68 // Check to verify that the define for the intelligibility enhancer is properly |
68 // set. | 69 // set. |
69 #if !defined(WEBRTC_INTELLIGIBILITY_ENHANCER) || \ | 70 #if !defined(WEBRTC_INTELLIGIBILITY_ENHANCER) || \ |
70 (WEBRTC_INTELLIGIBILITY_ENHANCER != 0 && \ | 71 (WEBRTC_INTELLIGIBILITY_ENHANCER != 0 && \ |
71 WEBRTC_INTELLIGIBILITY_ENHANCER != 1) | 72 WEBRTC_INTELLIGIBILITY_ENHANCER != 1) |
72 #error "Set WEBRTC_INTELLIGIBILITY_ENHANCER to either 0 or 1" | 73 #error "Set WEBRTC_INTELLIGIBILITY_ENHANCER to either 0 or 1" |
73 #endif | 74 #endif |
74 | 75 |
75 // Codec parameters for Opus. | 76 // For SendSideBwe, Opus bitrate should be in the range between 6000 and 32000. |
the sun
2017/03/16 08:48:19
32000?
ossu
2017/03/20 18:19:48
Yup, seems so. I've just rearranged the code a bit
| |
76 // draft-spittka-payload-rtp-opus-03 | 77 const int kOpusMinBitrateBps = 6000; |
77 | |
78 // Recommended bitrates: | |
79 // 8-12 kb/s for NB speech, | |
80 // 16-20 kb/s for WB speech, | |
81 // 28-40 kb/s for FB speech, | |
82 // 48-64 kb/s for FB mono music, and | |
83 // 64-128 kb/s for FB stereo music. | |
84 // The current implementation applies the following values to mono signals, | |
85 // and multiplies them by 2 for stereo. | |
86 const int kOpusBitrateNbBps = 12000; | |
87 const int kOpusBitrateWbBps = 20000; | |
88 const int kOpusBitrateFbBps = 32000; | 78 const int kOpusBitrateFbBps = 32000; |
89 | 79 |
90 // Opus bitrate should be in the range between 6000 and 510000. | |
91 const int kOpusMinBitrateBps = 6000; | |
92 const int kOpusMaxBitrateBps = 510000; | |
93 | |
94 // iSAC bitrate should be <= 56000. | |
95 const int kIsacMaxBitrateBps = 56000; | |
96 | |
97 // Default audio dscp value. | 80 // Default audio dscp value. |
98 // See http://tools.ietf.org/html/rfc2474 for details. | 81 // See http://tools.ietf.org/html/rfc2474 for details. |
99 // See also http://tools.ietf.org/html/draft-jennings-rtcweb-qos-00 | 82 // See also http://tools.ietf.org/html/draft-jennings-rtcweb-qos-00 |
100 const rtc::DiffServCodePoint kAudioDscpValue = rtc::DSCP_EF; | 83 const rtc::DiffServCodePoint kAudioDscpValue = rtc::DSCP_EF; |
101 | 84 |
102 // Constants from voice_engine_defines.h. | 85 // Constants from voice_engine_defines.h. |
103 const int kMinTelephoneEventCode = 0; // RFC4733 (Section 2.3.1) | 86 const int kMinTelephoneEventCode = 0; // RFC4733 (Section 2.3.1) |
104 const int kMaxTelephoneEventCode = 255; | 87 const int kMaxTelephoneEventCode = 255; |
105 const int kMinTelephoneEventDuration = 100; | 88 const int kMinTelephoneEventDuration = 100; |
106 const int kMaxTelephoneEventDuration = 60000; // Actual limit is 2^16 | 89 const int kMaxTelephoneEventDuration = 60000; // Actual limit is 2^16 |
(...skipping 19 matching lines...) Expand all Loading... | |
126 if (sp.ssrcs.size() > 1) { | 109 if (sp.ssrcs.size() > 1) { |
127 LOG(LS_ERROR) << "Multiple SSRCs in stream parameters: " << sp.ToString(); | 110 LOG(LS_ERROR) << "Multiple SSRCs in stream parameters: " << sp.ToString(); |
128 return false; | 111 return false; |
129 } | 112 } |
130 return true; | 113 return true; |
131 } | 114 } |
132 | 115 |
133 // Dumps an AudioCodec in RFC 2327-ish format. | 116 // Dumps an AudioCodec in RFC 2327-ish format. |
134 std::string ToString(const AudioCodec& codec) { | 117 std::string ToString(const AudioCodec& codec) { |
135 std::stringstream ss; | 118 std::stringstream ss; |
136 ss << codec.name << "/" << codec.clockrate << "/" << codec.channels | 119 ss << codec.name << "/" << codec.clockrate << "/" << codec.channels; |
137 << " (" << codec.id << ")"; | 120 if (!codec.params.empty()) { |
121 ss << " {"; | |
122 for (const auto& param : codec.params) { | |
123 ss << " " << param.first << "=" << param.second; | |
124 } | |
kwiberg-webrtc
2017/03/01 12:26:47
Broken indentation. Also, isn't there a second par
ossu
2017/03/02 01:30:28
Wow, what happened here? :)
I guess you're talking
| |
125 ss << " }"; | |
126 } | |
127 ss << " (" << codec.id << ")"; | |
138 return ss.str(); | 128 return ss.str(); |
139 } | 129 } |
140 | 130 |
141 std::string ToString(const webrtc::CodecInst& codec) { | 131 std::string ToString(const webrtc::CodecInst& codec) { |
142 std::stringstream ss; | 132 std::stringstream ss; |
143 ss << codec.plname << "/" << codec.plfreq << "/" << codec.channels | 133 ss << codec.plname << "/" << codec.plfreq << "/" << codec.channels |
144 << " (" << codec.pltype << ")"; | 134 << " (" << codec.pltype << ")"; |
145 return ss.str(); | 135 return ss.str(); |
146 } | 136 } |
147 | 137 |
(...skipping 25 matching lines...) Expand all Loading... | |
173 } | 163 } |
174 std::vector<int> payload_types; | 164 std::vector<int> payload_types; |
175 for (const AudioCodec& codec : codecs) { | 165 for (const AudioCodec& codec : codecs) { |
176 payload_types.push_back(codec.id); | 166 payload_types.push_back(codec.id); |
177 } | 167 } |
178 std::sort(payload_types.begin(), payload_types.end()); | 168 std::sort(payload_types.begin(), payload_types.end()); |
179 auto it = std::unique(payload_types.begin(), payload_types.end()); | 169 auto it = std::unique(payload_types.begin(), payload_types.end()); |
180 return it == payload_types.end(); | 170 return it == payload_types.end(); |
181 } | 171 } |
182 | 172 |
183 // Return true if codec.params[feature] == "1", false otherwise. | |
184 bool IsCodecFeatureEnabled(const AudioCodec& codec, const char* feature) { | |
185 int value; | |
186 return codec.GetParam(feature, &value) && value == 1; | |
187 } | |
188 | |
189 rtc::Optional<std::string> GetAudioNetworkAdaptorConfig( | 173 rtc::Optional<std::string> GetAudioNetworkAdaptorConfig( |
190 const AudioOptions& options) { | 174 const AudioOptions& options) { |
191 if (options.audio_network_adaptor && *options.audio_network_adaptor && | 175 if (options.audio_network_adaptor && *options.audio_network_adaptor && |
192 options.audio_network_adaptor_config) { | 176 options.audio_network_adaptor_config) { |
193 // Turn on audio network adaptor only when |options_.audio_network_adaptor| | 177 // Turn on audio network adaptor only when |options_.audio_network_adaptor| |
194 // equals true and |options_.audio_network_adaptor_config| has a value. | 178 // equals true and |options_.audio_network_adaptor_config| has a value. |
195 return options.audio_network_adaptor_config; | 179 return options.audio_network_adaptor_config; |
196 } | 180 } |
197 return rtc::Optional<std::string>(); | 181 return rtc::Optional<std::string>(); |
198 } | 182 } |
199 | 183 |
200 // Returns integer parameter params[feature] if it is defined. Returns | |
201 // |default_value| otherwise. | |
202 int GetCodecFeatureInt(const AudioCodec& codec, | |
203 const char* feature, | |
204 int default_value) { | |
205 int value = 0; | |
206 if (codec.GetParam(feature, &value)) { | |
207 return value; | |
208 } | |
209 return default_value; | |
210 } | |
211 | |
212 // Use params[kCodecParamMaxAverageBitrate] if it is defined, use codec.bitrate | |
213 // otherwise. If the value (either from params or codec.bitrate) <=0, use the | |
214 // default configuration. If the value is beyond feasible bit rate of Opus, | |
215 // clamp it. Returns the Opus bit rate for operation. | |
216 int GetOpusBitrate(const AudioCodec& codec, int max_playback_rate) { | |
217 int bitrate = 0; | |
218 bool use_param = true; | |
219 if (!codec.GetParam(kCodecParamMaxAverageBitrate, &bitrate)) { | |
220 bitrate = codec.bitrate; | |
221 use_param = false; | |
222 } | |
223 if (bitrate <= 0) { | |
224 if (max_playback_rate <= 8000) { | |
225 bitrate = kOpusBitrateNbBps; | |
226 } else if (max_playback_rate <= 16000) { | |
227 bitrate = kOpusBitrateWbBps; | |
228 } else { | |
229 bitrate = kOpusBitrateFbBps; | |
230 } | |
231 | |
232 if (IsCodecFeatureEnabled(codec, kCodecParamStereo)) { | |
233 bitrate *= 2; | |
234 } | |
235 } else if (bitrate < kOpusMinBitrateBps || bitrate > kOpusMaxBitrateBps) { | |
236 bitrate = (bitrate < kOpusMinBitrateBps) ? kOpusMinBitrateBps | |
237 : kOpusMaxBitrateBps; | |
238 std::string rate_source = | |
239 use_param ? "Codec parameter \"maxaveragebitrate\"" : | |
240 "Supplied Opus bitrate"; | |
241 LOG(LS_WARNING) << rate_source | |
242 << " is invalid and is replaced by: " | |
243 << bitrate; | |
244 } | |
245 return bitrate; | |
246 } | |
247 | |
248 void GetOpusConfig(const AudioCodec& codec, | |
249 webrtc::CodecInst* voe_codec, | |
250 bool* enable_codec_fec, | |
251 int* max_playback_rate, | |
252 bool* enable_codec_dtx, | |
253 int* min_ptime_ms, | |
254 int* max_ptime_ms) { | |
255 *enable_codec_fec = IsCodecFeatureEnabled(codec, kCodecParamUseInbandFec); | |
256 *enable_codec_dtx = IsCodecFeatureEnabled(codec, kCodecParamUseDtx); | |
257 *max_playback_rate = GetCodecFeatureInt(codec, kCodecParamMaxPlaybackRate, | |
258 kOpusDefaultMaxPlaybackRate); | |
259 *max_ptime_ms = | |
260 GetCodecFeatureInt(codec, kCodecParamMaxPTime, kOpusDefaultMaxPTime); | |
261 *min_ptime_ms = | |
262 GetCodecFeatureInt(codec, kCodecParamMinPTime, kOpusDefaultMinPTime); | |
263 if (*max_ptime_ms < *min_ptime_ms) { | |
264 // If min ptime or max ptime defined by codec parameter is wrong, we use | |
265 // the default values. | |
266 *max_ptime_ms = kOpusDefaultMaxPTime; | |
267 *min_ptime_ms = kOpusDefaultMinPTime; | |
268 } | |
269 | |
270 // If OPUS, change what we send according to the "stereo" codec | |
271 // parameter, and not the "channels" parameter. We set | |
272 // voe_codec.channels to 2 if "stereo=1" and 1 otherwise. If | |
273 // the bitrate is not specified, i.e. is <= zero, we set it to the | |
274 // appropriate default value for mono or stereo Opus. | |
275 voe_codec->channels = IsCodecFeatureEnabled(codec, kCodecParamStereo) ? 2 : 1; | |
276 voe_codec->rate = GetOpusBitrate(codec, *max_playback_rate); | |
277 } | |
278 | |
279 webrtc::AudioState::Config MakeAudioStateConfig( | 184 webrtc::AudioState::Config MakeAudioStateConfig( |
280 VoEWrapper* voe_wrapper, | 185 VoEWrapper* voe_wrapper, |
281 rtc::scoped_refptr<webrtc::AudioMixer> audio_mixer) { | 186 rtc::scoped_refptr<webrtc::AudioMixer> audio_mixer) { |
282 webrtc::AudioState::Config config; | 187 webrtc::AudioState::Config config; |
283 config.voice_engine = voe_wrapper->engine(); | 188 config.voice_engine = voe_wrapper->engine(); |
284 if (audio_mixer) { | 189 if (audio_mixer) { |
285 config.audio_mixer = audio_mixer; | 190 config.audio_mixer = audio_mixer; |
286 } else { | 191 } else { |
287 config.audio_mixer = webrtc::AudioMixerImpl::Create(); | 192 config.audio_mixer = webrtc::AudioMixerImpl::Create(); |
288 } | 193 } |
289 return config; | 194 return config; |
290 } | 195 } |
291 | 196 |
292 class WebRtcVoiceCodecs final { | 197 class WebRtcVoiceCodecs final { |
293 public: | 198 public: |
294 // TODO(solenberg): Do this filtering once off-line, add a simple AudioCodec | 199 static bool ToCodecInst(const AudioCodec& in, webrtc::CodecInst* out) { |
the sun
2017/03/02 20:37:24
So this is just needed for tests now? And it is st
ossu
2017/03/02 20:43:27
I'll try to clean up the tests, so we won't need t
ossu
2017/03/20 18:19:48
Cleaned up (or plain removed) all remaining tests
| |
295 // list and add a test which verifies VoE supports the listed codecs. | |
296 static std::vector<AudioCodec> SupportedSendCodecs() { | |
297 std::vector<AudioCodec> result; | |
298 // Iterate first over our preferred codecs list, so that the results are | |
299 // added in order of preference. | |
300 for (size_t i = 0; i < arraysize(kCodecPrefs); ++i) { | |
301 const CodecPref* pref = &kCodecPrefs[i]; | |
302 for (webrtc::CodecInst voe_codec : webrtc::acm2::RentACodec::Database()) { | |
303 // Change the sample rate of G722 to 8000 to match SDP. | |
304 MaybeFixupG722(&voe_codec, 8000); | |
305 // Skip uncompressed formats. | |
306 if (IsCodec(voe_codec, kL16CodecName)) { | |
307 continue; | |
308 } | |
309 | |
310 if (!IsCodec(voe_codec, pref->name) || | |
311 pref->clockrate != voe_codec.plfreq || | |
312 pref->channels != voe_codec.channels) { | |
313 // Not a match. | |
314 continue; | |
315 } | |
316 | |
317 AudioCodec codec(pref->payload_type, voe_codec.plname, voe_codec.plfreq, | |
318 voe_codec.rate, voe_codec.channels); | |
319 LOG(LS_INFO) << "Adding supported codec: " << ToString(codec); | |
320 if (IsCodec(codec, kIsacCodecName)) { | |
321 // Indicate auto-bitrate in signaling. | |
322 codec.bitrate = 0; | |
323 } | |
324 if (IsCodec(codec, kOpusCodecName)) { | |
325 // Only add fmtp parameters that differ from the spec. | |
326 if (kPreferredMinPTime != kOpusDefaultMinPTime) { | |
327 codec.params[kCodecParamMinPTime] = | |
328 rtc::ToString(kPreferredMinPTime); | |
329 } | |
330 if (kPreferredMaxPTime != kOpusDefaultMaxPTime) { | |
331 codec.params[kCodecParamMaxPTime] = | |
332 rtc::ToString(kPreferredMaxPTime); | |
333 } | |
334 codec.SetParam(kCodecParamUseInbandFec, 1); | |
335 codec.AddFeedbackParam( | |
336 FeedbackParam(kRtcpFbParamTransportCc, kParamValueEmpty)); | |
337 | |
338 // TODO(hellner): Add ptime, sprop-stereo, and stereo | |
339 // when they can be set to values other than the default. | |
340 } | |
341 result.push_back(codec); | |
342 } | |
343 } | |
344 return result; | |
345 } | |
346 | |
347 static bool ToCodecInst(const AudioCodec& in, | |
348 webrtc::CodecInst* out) { | |
349 for (webrtc::CodecInst voe_codec : webrtc::acm2::RentACodec::Database()) { | 200 for (webrtc::CodecInst voe_codec : webrtc::acm2::RentACodec::Database()) { |
350 // Change the sample rate of G722 to 8000 to match SDP. | 201 // Change the sample rate of G722 to 8000 to match SDP. |
351 MaybeFixupG722(&voe_codec, 8000); | 202 MaybeFixupG722(&voe_codec, 8000); |
352 AudioCodec codec(voe_codec.pltype, voe_codec.plname, voe_codec.plfreq, | 203 AudioCodec codec(voe_codec.pltype, voe_codec.plname, voe_codec.plfreq, |
353 voe_codec.rate, voe_codec.channels); | 204 voe_codec.rate, voe_codec.channels); |
354 bool multi_rate = IsCodecMultiRate(voe_codec); | 205 const bool multi_rate = |
206 IsCodec(codec, kIsacCodecName) || IsCodec(codec, kOpusCodecName); | |
355 // Allow arbitrary rates for ISAC to be specified. | 207 // Allow arbitrary rates for ISAC to be specified. |
356 if (multi_rate) { | 208 if (multi_rate) { |
357 // Set codec.bitrate to 0 so the check for codec.Matches() passes. | 209 // Set codec.bitrate to 0 so the check for codec.Matches() passes. |
358 codec.bitrate = 0; | 210 codec.bitrate = 0; |
359 } | 211 } |
360 if (codec.Matches(in)) { | 212 if (codec.Matches(in)) { |
361 if (out) { | 213 if (out) { |
362 // Fixup the payload type. | 214 // Fixup the payload type. |
363 voe_codec.pltype = in.id; | 215 voe_codec.pltype = in.id; |
364 | 216 |
365 // Set bitrate if specified. | 217 // Set bitrate if specified. |
366 if (multi_rate && in.bitrate != 0) { | 218 if (multi_rate && in.bitrate != 0) { |
367 voe_codec.rate = in.bitrate; | 219 voe_codec.rate = in.bitrate; |
368 } | 220 } |
369 | 221 |
370 // Reset G722 sample rate to 16000 to match WebRTC. | 222 // Reset G722 sample rate to 16000 to match WebRTC. |
371 MaybeFixupG722(&voe_codec, 16000); | 223 MaybeFixupG722(&voe_codec, 16000); |
372 | 224 |
373 *out = voe_codec; | 225 *out = voe_codec; |
374 } | 226 } |
375 return true; | 227 return true; |
376 } | 228 } |
377 } | 229 } |
378 return false; | 230 return false; |
379 } | 231 } |
380 | 232 |
381 static bool IsCodecMultiRate(const webrtc::CodecInst& codec) { | |
382 for (size_t i = 0; i < arraysize(kCodecPrefs); ++i) { | |
383 if (IsCodec(codec, kCodecPrefs[i].name) && | |
384 kCodecPrefs[i].clockrate == codec.plfreq) { | |
385 return kCodecPrefs[i].is_multi_rate; | |
386 } | |
387 } | |
388 return false; | |
389 } | |
390 | |
391 static int MaxBitrateBps(const webrtc::CodecInst& codec) { | |
392 for (size_t i = 0; i < arraysize(kCodecPrefs); ++i) { | |
393 if (IsCodec(codec, kCodecPrefs[i].name) && | |
394 kCodecPrefs[i].clockrate == codec.plfreq) { | |
395 return kCodecPrefs[i].max_bitrate_bps; | |
396 } | |
397 } | |
398 return 0; | |
399 } | |
400 | |
401 static rtc::ArrayView<const int> GetPacketSizesMs( | |
402 const webrtc::CodecInst& codec) { | |
403 for (size_t i = 0; i < arraysize(kCodecPrefs); ++i) { | |
404 if (IsCodec(codec, kCodecPrefs[i].name)) { | |
405 size_t num_packet_sizes = kMaxNumPacketSize; | |
406 for (int index = 0; index < kMaxNumPacketSize; index++) { | |
407 if (kCodecPrefs[i].packet_sizes_ms[index] == 0) { | |
408 num_packet_sizes = index; | |
409 break; | |
410 } | |
411 } | |
412 return rtc::ArrayView<const int>(kCodecPrefs[i].packet_sizes_ms, | |
413 num_packet_sizes); | |
414 } | |
415 } | |
416 return rtc::ArrayView<const int>(); | |
417 } | |
418 | |
419 // If the AudioCodec param kCodecParamPTime is set, then we will set it to | |
420 // codec pacsize if it's valid, or we will pick the next smallest value we | |
421 // support. | |
422 // TODO(Brave): Query supported packet sizes from ACM when the API is ready. | |
423 static bool SetPTimeAsPacketSize(webrtc::CodecInst* codec, int ptime_ms) { | |
424 for (const CodecPref& codec_pref : kCodecPrefs) { | |
425 if ((IsCodec(*codec, codec_pref.name) && | |
426 codec_pref.clockrate == codec->plfreq) || | |
427 IsCodec(*codec, kG722CodecName)) { | |
428 int packet_size_ms = SelectPacketSize(codec_pref, ptime_ms); | |
429 if (packet_size_ms) { | |
430 // Convert unit from milli-seconds to samples. | |
431 codec->pacsize = (codec->plfreq / 1000) * packet_size_ms; | |
432 return true; | |
433 } | |
434 } | |
435 } | |
436 return false; | |
437 } | |
438 | |
439 static const AudioCodec* GetPreferredCodec( | |
440 const std::vector<AudioCodec>& codecs, | |
441 webrtc::CodecInst* out) { | |
442 RTC_DCHECK(out); | |
443 // Select the preferred send codec (the first non-telephone-event/CN codec). | |
444 for (const AudioCodec& codec : codecs) { | |
445 if (IsCodec(codec, kDtmfCodecName) || IsCodec(codec, kCnCodecName)) { | |
446 // Skip telephone-event/CN codecs - they will be handled later. | |
447 continue; | |
448 } | |
449 | |
450 // We'll use the first codec in the list to actually send audio data. | |
451 // Be sure to use the payload type requested by the remote side. | |
452 // Ignore codecs we don't know about. The negotiation step should prevent | |
453 // this, but double-check to be sure. | |
454 if (!ToCodecInst(codec, out)) { | |
455 LOG(LS_WARNING) << "Unknown codec " << ToString(codec); | |
456 continue; | |
457 } | |
458 return &codec; | |
459 } | |
460 return nullptr; | |
461 } | |
462 | |
463 private: | |
464 static const int kMaxNumPacketSize = 6; | |
465 struct CodecPref { | |
466 const char* name; | |
467 int clockrate; | |
468 size_t channels; | |
469 int payload_type; | |
470 bool is_multi_rate; | |
471 int packet_sizes_ms[kMaxNumPacketSize]; | |
472 int max_bitrate_bps; | |
473 }; | |
474 // Note: keep the supported packet sizes in ascending order. | |
475 static const CodecPref kCodecPrefs[14]; | |
476 | |
477 static int SelectPacketSize(const CodecPref& codec_pref, int ptime_ms) { | |
478 int selected_packet_size_ms = codec_pref.packet_sizes_ms[0]; | |
479 for (int packet_size_ms : codec_pref.packet_sizes_ms) { | |
480 if (packet_size_ms && packet_size_ms <= ptime_ms) { | |
481 selected_packet_size_ms = packet_size_ms; | |
482 } | |
483 } | |
484 return selected_packet_size_ms; | |
485 } | |
486 | |
487 // Changes RTP timestamp rate of G722. This is due to the "bug" in the RFC | 233 // Changes RTP timestamp rate of G722. This is due to the "bug" in the RFC |
488 // which says that G722 should be advertised as 8 kHz although it is a 16 kHz | 234 // which says that G722 should be advertised as 8 kHz although it is a 16 kHz |
489 // codec. | 235 // codec. |
490 static void MaybeFixupG722(webrtc::CodecInst* voe_codec, int new_plfreq) { | 236 static void MaybeFixupG722(webrtc::CodecInst* voe_codec, int new_plfreq) { |
491 if (IsCodec(*voe_codec, kG722CodecName)) { | 237 if (IsCodec(*voe_codec, kG722CodecName)) { |
492 // If the DCHECK triggers, the codec definition in WebRTC VoiceEngine | 238 // If the DCHECK triggers, the codec definition in WebRTC VoiceEngine |
493 // has changed, and this special case is no longer needed. | 239 // has changed, and this special case is no longer needed. |
494 RTC_DCHECK(voe_codec->plfreq != new_plfreq); | 240 RTC_DCHECK(voe_codec->plfreq != new_plfreq); |
495 voe_codec->plfreq = new_plfreq; | 241 voe_codec->plfreq = new_plfreq; |
496 } | 242 } |
497 } | 243 } |
498 }; | 244 }; |
499 | 245 |
500 const WebRtcVoiceCodecs::CodecPref WebRtcVoiceCodecs::kCodecPrefs[14] = { | |
501 #if WEBRTC_OPUS_SUPPORT_120MS_PTIME | |
502 {kOpusCodecName, 48000, 2, 111, true, {10, 20, 40, 60, 120}, | |
503 kOpusMaxBitrateBps}, | |
504 #else | |
505 {kOpusCodecName, 48000, 2, 111, true, {10, 20, 40, 60}, kOpusMaxBitrateBps}, | |
506 #endif | |
507 {kIsacCodecName, 16000, 1, 103, true, {30, 60}, kIsacMaxBitrateBps}, | |
508 {kIsacCodecName, 32000, 1, 104, true, {30}, kIsacMaxBitrateBps}, | |
509 // G722 should be advertised as 8000 Hz because of the RFC "bug". | |
510 {kG722CodecName, 8000, 1, 9, false, {10, 20, 30, 40, 50, 60}}, | |
511 {kIlbcCodecName, 8000, 1, 102, false, {20, 30, 40, 60}}, | |
512 {kPcmuCodecName, 8000, 1, 0, false, {10, 20, 30, 40, 50, 60}}, | |
513 {kPcmaCodecName, 8000, 1, 8, false, {10, 20, 30, 40, 50, 60}}, | |
514 {kCnCodecName, 32000, 1, 106, false, {}}, | |
515 {kCnCodecName, 16000, 1, 105, false, {}}, | |
516 {kCnCodecName, 8000, 1, 13, false, {}}, | |
517 {kDtmfCodecName, 48000, 1, 110, false, {}}, | |
518 {kDtmfCodecName, 32000, 1, 112, false, {}}, | |
519 {kDtmfCodecName, 16000, 1, 113, false, {}}, | |
520 {kDtmfCodecName, 8000, 1, 126, false, {}} | |
521 }; | |
522 | |
523 // |max_send_bitrate_bps| is the bitrate from "b=" in SDP. | 246 // |max_send_bitrate_bps| is the bitrate from "b=" in SDP. |
524 // |rtp_max_bitrate_bps| is the bitrate from RtpSender::SetParameters. | 247 // |rtp_max_bitrate_bps| is the bitrate from RtpSender::SetParameters. |
525 rtc::Optional<int> ComputeSendBitrate(int max_send_bitrate_bps, | 248 rtc::Optional<int> ComputeSendBitrate(int max_send_bitrate_bps, |
526 rtc::Optional<int> rtp_max_bitrate_bps, | 249 rtc::Optional<int> rtp_max_bitrate_bps, |
527 const webrtc::CodecInst& codec_inst) { | 250 const webrtc::AudioCodecSpec& spec) { |
528 // If application-configured bitrate is set, take minimum of that and SDP | 251 // If application-configured bitrate is set, take minimum of that and SDP |
529 // bitrate. | 252 // bitrate. |
530 const int bps = rtp_max_bitrate_bps | 253 const int bps = rtp_max_bitrate_bps |
531 ? MinPositive(max_send_bitrate_bps, *rtp_max_bitrate_bps) | 254 ? MinPositive(max_send_bitrate_bps, *rtp_max_bitrate_bps) |
532 : max_send_bitrate_bps; | 255 : max_send_bitrate_bps; |
533 const int codec_rate = codec_inst.rate; | |
534 | |
535 if (bps <= 0) { | 256 if (bps <= 0) { |
536 return rtc::Optional<int>(codec_rate); | 257 return rtc::Optional<int>(spec.info.default_bitrate_bps); |
537 } | 258 } |
538 | 259 |
539 if (codec_inst.pltype == -1) { | 260 if (bps < spec.info.min_bitrate_bps) { |
540 return rtc::Optional<int>(codec_rate); | |
541 ; | |
542 } | |
543 | |
544 if (WebRtcVoiceCodecs::IsCodecMultiRate(codec_inst)) { | |
545 // If codec is multi-rate then just set the bitrate. | |
546 return rtc::Optional<int>( | |
547 std::min(bps, WebRtcVoiceCodecs::MaxBitrateBps(codec_inst))); | |
548 } | |
549 | |
550 if (bps < codec_inst.rate) { | |
551 // If codec is not multi-rate and |bps| is less than the fixed bitrate then | 261 // If codec is not multi-rate and |bps| is less than the fixed bitrate then |
552 // fail. If codec is not multi-rate and |bps| exceeds or equal the fixed | 262 // fail. If codec is not multi-rate and |bps| exceeds or equal the fixed |
553 // bitrate then ignore. | 263 // bitrate then ignore. |
554 LOG(LS_ERROR) << "Failed to set codec " << codec_inst.plname | 264 LOG(LS_ERROR) << "Failed to set codec " << spec.format.name |
555 << " to bitrate " << bps << " bps" | 265 << " to bitrate " << bps << " bps" |
556 << ", requires at least " << codec_inst.rate << " bps."; | 266 << ", requires at least " << spec.info.min_bitrate_bps |
267 << " bps."; | |
557 return rtc::Optional<int>(); | 268 return rtc::Optional<int>(); |
558 } | 269 } |
559 return rtc::Optional<int>(codec_rate); | 270 |
271 if (spec.info.HasFixedBitrate()) { | |
272 return rtc::Optional<int>(spec.info.default_bitrate_bps); | |
273 } else { | |
274 // If codec is multi-rate then just set the bitrate. | |
275 return rtc::Optional<int>(std::min(bps, spec.info.max_bitrate_bps)); | |
276 } | |
560 } | 277 } |
561 | 278 |
562 } // namespace { | 279 } // namespace |
563 | 280 |
564 bool WebRtcVoiceEngine::ToCodecInst(const AudioCodec& in, | 281 bool WebRtcVoiceEngine::ToCodecInst(const AudioCodec& in, |
565 webrtc::CodecInst* out) { | 282 webrtc::CodecInst* out) { |
566 return WebRtcVoiceCodecs::ToCodecInst(in, out); | 283 return WebRtcVoiceCodecs::ToCodecInst(in, out); |
567 } | 284 } |
568 | 285 |
569 WebRtcVoiceEngine::WebRtcVoiceEngine( | 286 WebRtcVoiceEngine::WebRtcVoiceEngine( |
570 webrtc::AudioDeviceModule* adm, | 287 webrtc::AudioDeviceModule* adm, |
571 const rtc::scoped_refptr<webrtc::AudioDecoderFactory>& decoder_factory, | 288 const rtc::scoped_refptr<webrtc::AudioDecoderFactory>& decoder_factory, |
572 rtc::scoped_refptr<webrtc::AudioMixer> audio_mixer) | 289 rtc::scoped_refptr<webrtc::AudioMixer> audio_mixer) |
573 : WebRtcVoiceEngine(adm, decoder_factory, audio_mixer, new VoEWrapper()) { | 290 : WebRtcVoiceEngine(adm, decoder_factory, audio_mixer, new VoEWrapper()) { |
574 audio_state_ = | 291 audio_state_ = |
575 webrtc::AudioState::Create(MakeAudioStateConfig(voe(), audio_mixer)); | 292 webrtc::AudioState::Create(MakeAudioStateConfig(voe(), audio_mixer)); |
576 } | 293 } |
577 | 294 |
578 WebRtcVoiceEngine::WebRtcVoiceEngine( | 295 WebRtcVoiceEngine::WebRtcVoiceEngine( |
579 webrtc::AudioDeviceModule* adm, | 296 webrtc::AudioDeviceModule* adm, |
580 const rtc::scoped_refptr<webrtc::AudioDecoderFactory>& decoder_factory, | 297 const rtc::scoped_refptr<webrtc::AudioDecoderFactory>& decoder_factory, |
581 rtc::scoped_refptr<webrtc::AudioMixer> audio_mixer, | 298 rtc::scoped_refptr<webrtc::AudioMixer> audio_mixer, |
582 VoEWrapper* voe_wrapper) | 299 VoEWrapper* voe_wrapper) |
583 : adm_(adm), decoder_factory_(decoder_factory), voe_wrapper_(voe_wrapper) { | 300 : adm_(adm), |
301 encoder_factory_(webrtc::CreateBuiltinAudioEncoderFactory()), | |
302 decoder_factory_(decoder_factory), | |
303 voe_wrapper_(voe_wrapper) { | |
584 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 304 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
585 LOG(LS_INFO) << "WebRtcVoiceEngine::WebRtcVoiceEngine"; | 305 LOG(LS_INFO) << "WebRtcVoiceEngine::WebRtcVoiceEngine"; |
586 RTC_DCHECK(voe_wrapper); | 306 RTC_DCHECK(voe_wrapper); |
587 RTC_DCHECK(decoder_factory); | 307 RTC_DCHECK(decoder_factory); |
588 | 308 |
589 signal_thread_checker_.DetachFromThread(); | 309 signal_thread_checker_.DetachFromThread(); |
590 | 310 |
591 // Load our audio codec list. | 311 // Load our audio codec list. |
592 LOG(LS_INFO) << "Supported send codecs in order of preference:"; | 312 LOG(LS_INFO) << "Supported send codecs in order of preference:"; |
593 send_codecs_ = WebRtcVoiceCodecs::SupportedSendCodecs(); | 313 send_codecs_ = CollectCodecs(encoder_factory_->GetSupportedEncoders()); |
594 for (const AudioCodec& codec : send_codecs_) { | 314 for (const AudioCodec& codec : send_codecs_) { |
595 LOG(LS_INFO) << ToString(codec); | 315 LOG(LS_INFO) << ToString(codec); |
596 } | 316 } |
597 | 317 |
598 LOG(LS_INFO) << "Supported recv codecs in order of preference:"; | 318 LOG(LS_INFO) << "Supported recv codecs in order of preference:"; |
599 recv_codecs_ = CollectRecvCodecs(); | 319 recv_codecs_ = CollectCodecs(decoder_factory_->GetSupportedDecoders()); |
600 for (const AudioCodec& codec : recv_codecs_) { | 320 for (const AudioCodec& codec : recv_codecs_) { |
601 LOG(LS_INFO) << ToString(codec); | 321 LOG(LS_INFO) << ToString(codec); |
602 } | 322 } |
603 | 323 |
604 channel_config_.enable_voice_pacing = true; | 324 channel_config_.enable_voice_pacing = true; |
605 | 325 |
606 // Temporarily turn logging level up for the Init() call. | 326 // Temporarily turn logging level up for the Init() call. |
607 webrtc::Trace::SetTraceCallback(this); | 327 webrtc::Trace::SetTraceCallback(this); |
608 webrtc::Trace::set_level_filter(kElevatedTraceFilter); | 328 webrtc::Trace::set_level_filter(kElevatedTraceFilter); |
609 LOG(LS_INFO) << webrtc::VoiceEngine::GetVersionString(); | 329 LOG(LS_INFO) << webrtc::VoiceEngine::GetVersionString(); |
(...skipping 531 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1141 RTC_DCHECK(adm_); | 861 RTC_DCHECK(adm_); |
1142 return adm_; | 862 return adm_; |
1143 } | 863 } |
1144 | 864 |
1145 webrtc::AudioProcessing* WebRtcVoiceEngine::apm() { | 865 webrtc::AudioProcessing* WebRtcVoiceEngine::apm() { |
1146 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 866 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
1147 RTC_DCHECK(apm_); | 867 RTC_DCHECK(apm_); |
1148 return apm_; | 868 return apm_; |
1149 } | 869 } |
1150 | 870 |
1151 AudioCodecs WebRtcVoiceEngine::CollectRecvCodecs() const { | 871 AudioCodecs WebRtcVoiceEngine::CollectCodecs( |
872 const std::vector<webrtc::AudioCodecSpec>& specs) const { | |
1152 PayloadTypeMapper mapper; | 873 PayloadTypeMapper mapper; |
1153 AudioCodecs out; | 874 AudioCodecs out; |
1154 const std::vector<webrtc::AudioCodecSpec>& specs = | |
1155 decoder_factory_->GetSupportedDecoders(); | |
1156 | 875 |
1157 // Only generate CN payload types for these clockrates: | 876 // Only generate CN payload types for these clockrates: |
1158 std::map<int, bool, std::greater<int>> generate_cn = {{ 8000, false }, | 877 std::map<int, bool, std::greater<int>> generate_cn = {{ 8000, false }, |
1159 { 16000, false }, | 878 { 16000, false }, |
1160 { 32000, false }}; | 879 { 32000, false }}; |
1161 // Only generate telephone-event payload types for these clockrates: | 880 // Only generate telephone-event payload types for these clockrates: |
1162 std::map<int, bool, std::greater<int>> generate_dtmf = {{ 8000, false }, | 881 std::map<int, bool, std::greater<int>> generate_dtmf = {{ 8000, false }, |
1163 { 16000, false }, | 882 { 16000, false }, |
1164 { 32000, false }, | 883 { 32000, false }, |
1165 { 48000, false }}; | 884 { 48000, false }}; |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1230 WebRtcAudioSendStream( | 949 WebRtcAudioSendStream( |
1231 int ch, | 950 int ch, |
1232 webrtc::AudioTransport* voe_audio_transport, | 951 webrtc::AudioTransport* voe_audio_transport, |
1233 uint32_t ssrc, | 952 uint32_t ssrc, |
1234 const std::string& c_name, | 953 const std::string& c_name, |
1235 const webrtc::AudioSendStream::Config::SendCodecSpec& send_codec_spec, | 954 const webrtc::AudioSendStream::Config::SendCodecSpec& send_codec_spec, |
1236 const std::vector<webrtc::RtpExtension>& extensions, | 955 const std::vector<webrtc::RtpExtension>& extensions, |
1237 int max_send_bitrate_bps, | 956 int max_send_bitrate_bps, |
1238 const rtc::Optional<std::string>& audio_network_adaptor_config, | 957 const rtc::Optional<std::string>& audio_network_adaptor_config, |
1239 webrtc::Call* call, | 958 webrtc::Call* call, |
1240 webrtc::Transport* send_transport) | 959 webrtc::Transport* send_transport, |
960 const rtc::scoped_refptr<webrtc::AudioEncoderFactory>& encoder_factory) | |
1241 : voe_audio_transport_(voe_audio_transport), | 961 : voe_audio_transport_(voe_audio_transport), |
1242 call_(call), | 962 call_(call), |
1243 config_(send_transport), | 963 config_(send_transport), |
1244 send_side_bwe_with_overhead_(webrtc::field_trial::FindFullName( | 964 send_side_bwe_with_overhead_(webrtc::field_trial::FindFullName( |
1245 "WebRTC-SendSideBwe-WithOverhead") == "Enabled"), | 965 "WebRTC-SendSideBwe-WithOverhead") == "Enabled"), |
1246 max_send_bitrate_bps_(max_send_bitrate_bps), | 966 max_send_bitrate_bps_(max_send_bitrate_bps), |
1247 rtp_parameters_(CreateRtpParametersWithOneEncoding()) { | 967 rtp_parameters_(CreateRtpParametersWithOneEncoding()) { |
1248 RTC_DCHECK_GE(ch, 0); | 968 RTC_DCHECK_GE(ch, 0); |
1249 // TODO(solenberg): Once we're not using FakeWebRtcVoiceEngine anymore: | 969 // TODO(solenberg): Once we're not using FakeWebRtcVoiceEngine anymore: |
1250 // RTC_DCHECK(voe_audio_transport); | 970 // RTC_DCHECK(voe_audio_transport); |
1251 RTC_DCHECK(call); | 971 RTC_DCHECK(call); |
972 RTC_DCHECK(encoder_factory); | |
1252 config_.rtp.ssrc = ssrc; | 973 config_.rtp.ssrc = ssrc; |
1253 config_.rtp.c_name = c_name; | 974 config_.rtp.c_name = c_name; |
1254 config_.voe_channel_id = ch; | 975 config_.voe_channel_id = ch; |
1255 config_.rtp.extensions = extensions; | 976 config_.rtp.extensions = extensions; |
1256 config_.audio_network_adaptor_config = audio_network_adaptor_config; | 977 config_.audio_network_adaptor_config = audio_network_adaptor_config; |
978 config_.encoder_factory = encoder_factory; | |
1257 rtp_parameters_.encodings[0].ssrc = rtc::Optional<uint32_t>(ssrc); | 979 rtp_parameters_.encodings[0].ssrc = rtc::Optional<uint32_t>(ssrc); |
1258 RecreateAudioSendStream(send_codec_spec); | 980 RecreateAudioSendStream(send_codec_spec); |
1259 } | 981 } |
1260 | 982 |
1261 ~WebRtcAudioSendStream() override { | 983 ~WebRtcAudioSendStream() override { |
1262 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 984 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
1263 ClearSource(); | 985 ClearSource(); |
1264 call_->DestroyAudioSendStream(stream_); | 986 call_->DestroyAudioSendStream(stream_); |
1265 } | 987 } |
1266 | 988 |
1267 void RecreateAudioSendStream( | 989 void RecreateAudioSendStream( |
1268 const webrtc::AudioSendStream::Config::SendCodecSpec& send_codec_spec) { | 990 const webrtc::AudioSendStream::Config::SendCodecSpec& send_codec_spec) { |
1269 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 991 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
1270 send_codec_spec_ = send_codec_spec; | 992 send_codec_spec_ = send_codec_spec; |
1271 config_.rtp.nack.rtp_history_ms = | 993 config_.rtp.nack.rtp_history_ms = |
1272 send_codec_spec_.nack_enabled ? kNackRtpHistoryMs : 0; | 994 send_codec_spec_.nack_enabled ? kNackRtpHistoryMs : 0; |
1273 config_.send_codec_spec = send_codec_spec_; | 995 config_.send_codec_spec = send_codec_spec_; |
1274 auto send_rate = ComputeSendBitrate( | 996 if (send_codec_spec_.format.name != "") { |
kwiberg-webrtc
2017/03/01 12:26:47
One of these again...
ossu
2017/03/02 01:30:28
Yes. This is the most important one. There are two
kwiberg-webrtc
2017/03/02 02:17:55
Dealing with it when cleaning up sounds OK.
ossu
2017/03/20 18:19:48
SendCodecSpec is now optional. No more string comp
| |
1275 max_send_bitrate_bps_, rtp_parameters_.encodings[0].max_bitrate_bps, | 997 auto info = |
1276 send_codec_spec.codec_inst); | 998 config_.encoder_factory->QueryAudioFormat(send_codec_spec_.format); |
1277 if (send_rate) { | 999 RTC_DCHECK(info); |
1278 // Apply a send rate that abides by |max_send_bitrate_bps_| and | 1000 // If a specific target bitrate has been set for the stream, use that as |
1279 // |rtp_parameters_| when possible. Otherwise use the codec rate. | 1001 // the new default bitrate when computing send bitrate. |
1280 config_.send_codec_spec.codec_inst.rate = *send_rate; | 1002 if (send_codec_spec_.target_bitrate_bps) { |
1003 info->default_bitrate_bps = | |
1004 std::max(info->min_bitrate_bps, | |
1005 std::min(info->max_bitrate_bps, | |
1006 *send_codec_spec.target_bitrate_bps)); | |
1007 } | |
1008 | |
1009 audio_codec_spec_.emplace( | |
1010 webrtc::AudioCodecSpec{send_codec_spec_.format, *info}); | |
1011 | |
1012 config_.send_codec_spec.target_bitrate_bps = ComputeSendBitrate( | |
1013 max_send_bitrate_bps_, rtp_parameters_.encodings[0].max_bitrate_bps, | |
1014 *audio_codec_spec_); | |
1281 } | 1015 } |
1282 RecreateAudioSendStream(); | 1016 RecreateAudioSendStream(); |
1283 } | 1017 } |
1284 | 1018 |
1285 void RecreateAudioSendStream( | 1019 void RecreateAudioSendStream( |
1286 const std::vector<webrtc::RtpExtension>& extensions) { | 1020 const std::vector<webrtc::RtpExtension>& extensions) { |
1287 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 1021 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
1288 config_.rtp.extensions = extensions; | 1022 config_.rtp.extensions = extensions; |
1289 RecreateAudioSendStream(); | 1023 RecreateAudioSendStream(); |
1290 } | 1024 } |
1291 | 1025 |
1292 void RecreateAudioSendStream( | 1026 void RecreateAudioSendStream( |
1293 const rtc::Optional<std::string>& audio_network_adaptor_config) { | 1027 const rtc::Optional<std::string>& audio_network_adaptor_config) { |
1294 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 1028 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
1295 if (config_.audio_network_adaptor_config == audio_network_adaptor_config) { | 1029 if (config_.audio_network_adaptor_config == audio_network_adaptor_config) { |
1296 return; | 1030 return; |
1297 } | 1031 } |
1298 config_.audio_network_adaptor_config = audio_network_adaptor_config; | 1032 config_.audio_network_adaptor_config = audio_network_adaptor_config; |
1299 RecreateAudioSendStream(); | 1033 RecreateAudioSendStream(); |
1300 } | 1034 } |
1301 | 1035 |
1302 bool SetMaxSendBitrate(int bps) { | 1036 bool SetMaxSendBitrate(int bps) { |
1303 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 1037 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
1038 RTC_DCHECK(audio_codec_spec_); | |
1304 auto send_rate = | 1039 auto send_rate = |
1305 ComputeSendBitrate(bps, rtp_parameters_.encodings[0].max_bitrate_bps, | 1040 ComputeSendBitrate(bps, rtp_parameters_.encodings[0].max_bitrate_bps, |
1306 send_codec_spec_.codec_inst); | 1041 *audio_codec_spec_); |
1042 | |
1307 if (!send_rate) { | 1043 if (!send_rate) { |
1308 return false; | 1044 return false; |
1309 } | 1045 } |
1310 | 1046 |
1311 max_send_bitrate_bps_ = bps; | 1047 max_send_bitrate_bps_ = bps; |
1312 | 1048 |
1313 if (config_.send_codec_spec.codec_inst.rate != *send_rate) { | 1049 if (send_rate != config_.send_codec_spec.target_bitrate_bps) { |
1314 // Recreate AudioSendStream with new bit rate. | 1050 // TODO(ossu): Should not recreate stream! |
1315 config_.send_codec_spec.codec_inst.rate = *send_rate; | 1051 config_.send_codec_spec.target_bitrate_bps = send_rate; |
1316 RecreateAudioSendStream(); | 1052 RecreateAudioSendStream(); |
1317 } | 1053 } |
1318 return true; | 1054 return true; |
1319 } | 1055 } |
1320 | 1056 |
1321 bool SendTelephoneEvent(int payload_type, int payload_freq, int event, | 1057 bool SendTelephoneEvent(int payload_type, int payload_freq, int event, |
1322 int duration_ms) { | 1058 int duration_ms) { |
1323 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 1059 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
1324 RTC_DCHECK(stream_); | 1060 RTC_DCHECK(stream_); |
1325 return stream_->SendTelephoneEvent(payload_type, payload_freq, event, | 1061 return stream_->SendTelephoneEvent(payload_type, payload_freq, event, |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1422 LOG(LS_ERROR) << "Attempted to set RtpParameters with modified SSRC"; | 1158 LOG(LS_ERROR) << "Attempted to set RtpParameters with modified SSRC"; |
1423 return false; | 1159 return false; |
1424 } | 1160 } |
1425 return true; | 1161 return true; |
1426 } | 1162 } |
1427 | 1163 |
1428 bool SetRtpParameters(const webrtc::RtpParameters& parameters) { | 1164 bool SetRtpParameters(const webrtc::RtpParameters& parameters) { |
1429 if (!ValidateRtpParameters(parameters)) { | 1165 if (!ValidateRtpParameters(parameters)) { |
1430 return false; | 1166 return false; |
1431 } | 1167 } |
1432 auto send_rate = ComputeSendBitrate(max_send_bitrate_bps_, | 1168 |
1433 parameters.encodings[0].max_bitrate_bps, | 1169 rtc::Optional<int> send_rate; |
1434 send_codec_spec_.codec_inst); | 1170 if (audio_codec_spec_) { |
1435 if (!send_rate) { | 1171 send_rate = ComputeSendBitrate(max_send_bitrate_bps_, |
1436 return false; | 1172 parameters.encodings[0].max_bitrate_bps, |
1173 *audio_codec_spec_); | |
1174 if (!send_rate) { | |
1175 return false; | |
1176 } | |
1437 } | 1177 } |
1438 | 1178 |
1439 rtp_parameters_ = parameters; | 1179 rtp_parameters_ = parameters; |
1440 | 1180 |
1441 // parameters.encodings[0].encodings[0].max_bitrate_bps could have changed. | 1181 // parameters.encodings[0].encodings[0].max_bitrate_bps could have changed. |
1442 if (config_.send_codec_spec.codec_inst.rate != *send_rate) { | 1182 if (send_rate && send_rate != config_.send_codec_spec.target_bitrate_bps) { |
1183 // TODO(ossu): Should not recreate stream! | |
1443 // Recreate AudioSendStream with new bit rate. | 1184 // Recreate AudioSendStream with new bit rate. |
1444 config_.send_codec_spec.codec_inst.rate = *send_rate; | 1185 config_.send_codec_spec.target_bitrate_bps = send_rate; |
1445 RecreateAudioSendStream(); | 1186 RecreateAudioSendStream(); |
1446 } else { | 1187 } else { |
1447 // parameters.encodings[0].active could have changed. | 1188 // parameters.encodings[0].active could have changed. |
1448 UpdateSendState(); | 1189 UpdateSendState(); |
1449 } | 1190 } |
1450 return true; | 1191 return true; |
1451 } | 1192 } |
1452 | 1193 |
1453 private: | 1194 private: |
1454 void UpdateSendState() { | 1195 void UpdateSendState() { |
(...skipping 14 matching lines...) Expand all Loading... | |
1469 stream_ = nullptr; | 1210 stream_ = nullptr; |
1470 } | 1211 } |
1471 RTC_DCHECK(!stream_); | 1212 RTC_DCHECK(!stream_); |
1472 if (webrtc::field_trial::FindFullName("WebRTC-Audio-SendSideBwe") == | 1213 if (webrtc::field_trial::FindFullName("WebRTC-Audio-SendSideBwe") == |
1473 "Enabled") { | 1214 "Enabled") { |
1474 config_.min_bitrate_bps = kOpusMinBitrateBps; | 1215 config_.min_bitrate_bps = kOpusMinBitrateBps; |
1475 config_.max_bitrate_bps = kOpusBitrateFbBps; | 1216 config_.max_bitrate_bps = kOpusBitrateFbBps; |
1476 // TODO(mflodman): Keep testing this and set proper values. | 1217 // TODO(mflodman): Keep testing this and set proper values. |
1477 // Note: This is an early experiment currently only supported by Opus. | 1218 // Note: This is an early experiment currently only supported by Opus. |
1478 if (send_side_bwe_with_overhead_) { | 1219 if (send_side_bwe_with_overhead_) { |
1479 auto packet_sizes_ms = WebRtcVoiceCodecs::GetPacketSizesMs( | 1220 const bool is_opus_with_ana = |
1480 config_.send_codec_spec.codec_inst); | 1221 config_.audio_network_adaptor_config && |
1481 if (!packet_sizes_ms.empty()) { | 1222 !STR_CASE_CMP(config_.send_codec_spec.format.name.c_str(), |
1482 int max_packet_size_ms = | 1223 kOpusCodecName); |
1483 *std::max_element(packet_sizes_ms.begin(), packet_sizes_ms.end()); | 1224 const int max_packet_size_ms = |
1484 int min_packet_size_ms = | 1225 (is_opus_with_ana && WEBRTC_OPUS_SUPPORT_120MS_PTIME) ? 120 : 60; |
1485 *std::min_element(packet_sizes_ms.begin(), packet_sizes_ms.end()); | 1226 // Audio network adaptor will just use 20ms and 60ms frame lengths. |
1227 // The adaptor will only be active for the Opus encoder. | |
1228 const int min_packet_size_ms = is_opus_with_ana ? 20 : 10; | |
1486 | 1229 |
1487 // Audio network adaptor will just use 20ms and 60ms frame lengths. | 1230 // OverheadPerPacket = Ipv4(20B) + UDP(8B) + SRTP(10B) + RTP(12) |
1488 // The adaptor will only be active for the Opus encoder. | 1231 constexpr int kOverheadPerPacket = 20 + 8 + 10 + 12; |
1489 if (config_.audio_network_adaptor_config && | |
1490 IsCodec(config_.send_codec_spec.codec_inst, kOpusCodecName)) { | |
1491 #if WEBRTC_OPUS_SUPPORT_120MS_PTIME | |
1492 max_packet_size_ms = 120; | |
1493 #else | |
1494 max_packet_size_ms = 60; | |
1495 #endif | |
1496 min_packet_size_ms = 20; | |
1497 } | |
1498 | 1232 |
1499 // OverheadPerPacket = Ipv4(20B) + UDP(8B) + SRTP(10B) + RTP(12) | 1233 int min_overhead_bps = |
1500 constexpr int kOverheadPerPacket = 20 + 8 + 10 + 12; | 1234 kOverheadPerPacket * 8 * 1000 / max_packet_size_ms; |
1501 | 1235 |
1502 int min_overhead_bps = | 1236 int max_overhead_bps = |
1503 kOverheadPerPacket * 8 * 1000 / max_packet_size_ms; | 1237 kOverheadPerPacket * 8 * 1000 / min_packet_size_ms; |
1504 | 1238 |
1505 int max_overhead_bps = | 1239 config_.min_bitrate_bps = kOpusMinBitrateBps + min_overhead_bps; |
1506 kOverheadPerPacket * 8 * 1000 / min_packet_size_ms; | 1240 config_.max_bitrate_bps = kOpusBitrateFbBps + max_overhead_bps; |
1507 | |
1508 config_.min_bitrate_bps = kOpusMinBitrateBps + min_overhead_bps; | |
1509 config_.max_bitrate_bps = kOpusBitrateFbBps + max_overhead_bps; | |
1510 } | |
1511 } | 1241 } |
1512 } | 1242 } |
1513 stream_ = call_->CreateAudioSendStream(config_); | 1243 stream_ = call_->CreateAudioSendStream(config_); |
1514 RTC_CHECK(stream_); | 1244 RTC_CHECK(stream_); |
1515 UpdateSendState(); | 1245 UpdateSendState(); |
1516 } | 1246 } |
1517 | 1247 |
1518 rtc::ThreadChecker worker_thread_checker_; | 1248 rtc::ThreadChecker worker_thread_checker_; |
1519 rtc::RaceChecker audio_capture_race_checker_; | 1249 rtc::RaceChecker audio_capture_race_checker_; |
1520 webrtc::AudioTransport* const voe_audio_transport_ = nullptr; | 1250 webrtc::AudioTransport* const voe_audio_transport_ = nullptr; |
1521 webrtc::Call* call_ = nullptr; | 1251 webrtc::Call* call_ = nullptr; |
1522 webrtc::AudioSendStream::Config config_; | 1252 webrtc::AudioSendStream::Config config_; |
1523 const bool send_side_bwe_with_overhead_; | 1253 const bool send_side_bwe_with_overhead_; |
1524 // The stream is owned by WebRtcAudioSendStream and may be reallocated if | 1254 // The stream is owned by WebRtcAudioSendStream and may be reallocated if |
1525 // configuration changes. | 1255 // configuration changes. |
1526 webrtc::AudioSendStream* stream_ = nullptr; | 1256 webrtc::AudioSendStream* stream_ = nullptr; |
1527 | 1257 |
1528 // Raw pointer to AudioSource owned by LocalAudioTrackHandler. | 1258 // Raw pointer to AudioSource owned by LocalAudioTrackHandler. |
1529 // PeerConnection will make sure invalidating the pointer before the object | 1259 // PeerConnection will make sure invalidating the pointer before the object |
1530 // goes away. | 1260 // goes away. |
1531 AudioSource* source_ = nullptr; | 1261 AudioSource* source_ = nullptr; |
1532 bool send_ = false; | 1262 bool send_ = false; |
1533 bool muted_ = false; | 1263 bool muted_ = false; |
1534 int max_send_bitrate_bps_; | 1264 int max_send_bitrate_bps_; |
1535 webrtc::RtpParameters rtp_parameters_; | 1265 webrtc::RtpParameters rtp_parameters_; |
1536 webrtc::AudioSendStream::Config::SendCodecSpec send_codec_spec_; | 1266 webrtc::AudioSendStream::Config::SendCodecSpec send_codec_spec_; |
1267 // TODO(ossu): Worst. Names. Ever. | |
1268 rtc::Optional<webrtc::AudioCodecSpec> audio_codec_spec_; | |
1537 | 1269 |
1538 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(WebRtcAudioSendStream); | 1270 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(WebRtcAudioSendStream); |
1539 }; | 1271 }; |
1540 | 1272 |
1541 class WebRtcVoiceMediaChannel::WebRtcAudioReceiveStream { | 1273 class WebRtcVoiceMediaChannel::WebRtcAudioReceiveStream { |
1542 public: | 1274 public: |
1543 WebRtcAudioReceiveStream( | 1275 WebRtcAudioReceiveStream( |
1544 int ch, | 1276 int ch, |
1545 uint32_t remote_ssrc, | 1277 uint32_t remote_ssrc, |
1546 uint32_t local_ssrc, | 1278 uint32_t local_ssrc, |
(...skipping 431 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1978 if (!dtmf_payload_type_ || codec.clockrate < dtmf_payload_freq_) { | 1710 if (!dtmf_payload_type_ || codec.clockrate < dtmf_payload_freq_) { |
1979 dtmf_payload_type_ = rtc::Optional<int>(codec.id); | 1711 dtmf_payload_type_ = rtc::Optional<int>(codec.id); |
1980 dtmf_payload_freq_ = codec.clockrate; | 1712 dtmf_payload_freq_ = codec.clockrate; |
1981 } | 1713 } |
1982 } | 1714 } |
1983 } | 1715 } |
1984 | 1716 |
1985 // Scan through the list to figure out the codec to use for sending, along | 1717 // Scan through the list to figure out the codec to use for sending, along |
1986 // with the proper configuration for VAD, CNG, NACK and Opus-specific | 1718 // with the proper configuration for VAD, CNG, NACK and Opus-specific |
1987 // parameters. | 1719 // parameters. |
1988 // TODO(solenberg): Refactor this logic once we create AudioEncoders here. | 1720 // TODO(solenberg): Refactor this logic once we create AudioEncoders here. |
the sun
2017/03/16 08:48:19
Comment doesn't apply anymore?
ossu
2017/03/20 18:19:48
Acknowledged.
| |
1989 webrtc::AudioSendStream::Config::SendCodecSpec send_codec_spec; | 1721 webrtc::AudioSendStream::Config::SendCodecSpec send_codec_spec; |
1990 { | 1722 { |
1991 send_codec_spec.nack_enabled = send_codec_spec_.nack_enabled; | 1723 send_codec_spec.nack_enabled = send_codec_spec_.nack_enabled; |
1992 | 1724 |
1993 // Find send codec (the first non-telephone-event/CN codec). | 1725 const AudioCodec* voice_codec = nullptr; |
1994 const AudioCodec* codec = WebRtcVoiceCodecs::GetPreferredCodec( | 1726 for (const AudioCodec& codec : codecs) { |
1995 codecs, &send_codec_spec.codec_inst); | 1727 if (!(IsCodec(codec, kCnCodecName) || |
1996 if (!codec) { | 1728 IsCodec(codec, kDtmfCodecName) || |
1997 LOG(LS_WARNING) << "Received empty list of codecs."; | 1729 IsCodec(codec, kRedCodecName))) { |
1998 return false; | 1730 webrtc::SdpAudioFormat format(codec.name, codec.clockrate, |
1731 codec.channels, | |
1732 CodecParameterMap(codec.params)); | |
1733 | |
1734 if (!engine()->encoder_factory_->IsSupportedEncoder(format)) { | |
1735 LOG(LS_WARNING) << "Unknown codec " << ToString(codec); | |
1736 continue; | |
1737 } | |
1738 | |
1739 voice_codec = &codec; | |
1740 send_codec_spec.payload_type = voice_codec->id; | |
1741 send_codec_spec.format = format; | |
1742 if (codec.bitrate > 0) { | |
1743 send_codec_spec.target_bitrate_bps = | |
1744 rtc::Optional<int>(codec.bitrate); | |
1745 } | |
1746 send_codec_spec.transport_cc_enabled = HasTransportCc(*voice_codec); | |
1747 send_codec_spec.nack_enabled = HasNack(*voice_codec); | |
1748 bitrate_config_ = GetBitrateConfigForCodec(*voice_codec); | |
1749 break; | |
1750 } | |
1999 } | 1751 } |
2000 | 1752 |
2001 send_codec_spec.transport_cc_enabled = HasTransportCc(*codec); | 1753 if (!voice_codec) |
2002 send_codec_spec.nack_enabled = HasNack(*codec); | 1754 return false; |
2003 bitrate_config_ = GetBitrateConfigForCodec(*codec); | |
2004 | |
2005 // For Opus as the send codec, we are to determine inband FEC, maximum | |
2006 // playback rate, and opus internal dtx. | |
2007 if (IsCodec(*codec, kOpusCodecName)) { | |
2008 GetOpusConfig(*codec, &send_codec_spec.codec_inst, | |
2009 &send_codec_spec.enable_codec_fec, | |
2010 &send_codec_spec.opus_max_playback_rate, | |
2011 &send_codec_spec.enable_opus_dtx, | |
2012 &send_codec_spec.min_ptime_ms, | |
2013 &send_codec_spec.max_ptime_ms); | |
2014 } | |
2015 | |
2016 // Set packet size if the AudioCodec param kCodecParamPTime is set. | |
2017 int ptime_ms = 0; | |
2018 if (codec->GetParam(kCodecParamPTime, &ptime_ms)) { | |
2019 if (!WebRtcVoiceCodecs::SetPTimeAsPacketSize( | |
2020 &send_codec_spec.codec_inst, ptime_ms)) { | |
2021 LOG(LS_WARNING) << "Failed to set packet size for codec " | |
2022 << send_codec_spec.codec_inst.plname; | |
2023 return false; | |
2024 } | |
2025 } | |
2026 | 1755 |
2027 // Loop through the codecs list again to find the CN codec. | 1756 // Loop through the codecs list again to find the CN codec. |
2028 // TODO(solenberg): Break out into a separate function? | 1757 // TODO(solenberg): Break out into a separate function? |
2029 for (const AudioCodec& codec : codecs) { | 1758 for (const AudioCodec& codec : codecs) { |
2030 // Ignore codecs we don't know about. The negotiation step should prevent | 1759 if (IsCodec(codec, kCnCodecName) && |
2031 // this, but double-check to be sure. | 1760 codec.clockrate == voice_codec->clockrate) { |
2032 webrtc::CodecInst voe_codec = {0}; | |
2033 if (!WebRtcVoiceEngine::ToCodecInst(codec, &voe_codec)) { | |
2034 LOG(LS_WARNING) << "Unknown codec " << ToString(codec); | |
2035 continue; | |
2036 } | |
2037 | |
2038 if (IsCodec(codec, kCnCodecName)) { | |
2039 // Turn voice activity detection/comfort noise on if supported. | 1761 // Turn voice activity detection/comfort noise on if supported. |
2040 // Set the wideband CN payload type appropriately. | 1762 // Set the wideband CN payload type appropriately. |
2041 // (narrowband always uses the static payload type 13). | 1763 // (narrowband always uses the static payload type 13). |
2042 int cng_plfreq = -1; | |
2043 switch (codec.clockrate) { | 1764 switch (codec.clockrate) { |
2044 case 8000: | 1765 case 8000: |
2045 case 16000: | 1766 case 16000: |
2046 case 32000: | 1767 case 32000: |
2047 cng_plfreq = codec.clockrate; | 1768 send_codec_spec.cng_payload_type = codec.id; |
2048 break; | 1769 break; |
2049 default: | 1770 default: |
2050 LOG(LS_WARNING) << "CN frequency " << codec.clockrate | 1771 LOG(LS_WARNING) << "CN frequency " << codec.clockrate |
2051 << " not supported."; | 1772 << " not supported."; |
2052 continue; | 1773 continue; |
2053 } | 1774 } |
2054 send_codec_spec.cng_payload_type = codec.id; | |
2055 send_codec_spec.cng_plfreq = cng_plfreq; | |
2056 break; | 1775 break; |
2057 } | 1776 } |
2058 } | 1777 } |
2059 | 1778 |
2060 // Find the telephone-event PT exactly matching the preferred send codec. | 1779 // Find the telephone-event PT exactly matching the preferred send codec. |
2061 for (const AudioCodec& dtmf_codec : dtmf_codecs) { | 1780 for (const AudioCodec& dtmf_codec : dtmf_codecs) { |
2062 if (dtmf_codec.clockrate == codec->clockrate) { | 1781 if (dtmf_codec.clockrate == voice_codec->clockrate) { |
2063 dtmf_payload_type_ = rtc::Optional<int>(dtmf_codec.id); | 1782 dtmf_payload_type_ = rtc::Optional<int>(dtmf_codec.id); |
2064 dtmf_payload_freq_ = dtmf_codec.clockrate; | 1783 dtmf_payload_freq_ = dtmf_codec.clockrate; |
2065 break; | 1784 break; |
2066 } | 1785 } |
2067 } | 1786 } |
2068 } | 1787 } |
2069 | 1788 |
2070 if (send_codec_spec_ != send_codec_spec) { | 1789 if (send_codec_spec_ != send_codec_spec) { |
2071 send_codec_spec_ = std::move(send_codec_spec); | 1790 send_codec_spec_ = std::move(send_codec_spec); |
2072 // Apply new settings to all streams. | 1791 // Apply new settings to all streams. |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2202 // Save the channel to send_streams_, so that RemoveSendStream() can still | 1921 // Save the channel to send_streams_, so that RemoveSendStream() can still |
2203 // delete the channel in case failure happens below. | 1922 // delete the channel in case failure happens below. |
2204 webrtc::AudioTransport* audio_transport = | 1923 webrtc::AudioTransport* audio_transport = |
2205 engine()->voe()->base()->audio_transport(); | 1924 engine()->voe()->base()->audio_transport(); |
2206 | 1925 |
2207 rtc::Optional<std::string> audio_network_adaptor_config = | 1926 rtc::Optional<std::string> audio_network_adaptor_config = |
2208 GetAudioNetworkAdaptorConfig(options_); | 1927 GetAudioNetworkAdaptorConfig(options_); |
2209 WebRtcAudioSendStream* stream = new WebRtcAudioSendStream( | 1928 WebRtcAudioSendStream* stream = new WebRtcAudioSendStream( |
2210 channel, audio_transport, ssrc, sp.cname, send_codec_spec_, | 1929 channel, audio_transport, ssrc, sp.cname, send_codec_spec_, |
2211 send_rtp_extensions_, max_send_bitrate_bps_, audio_network_adaptor_config, | 1930 send_rtp_extensions_, max_send_bitrate_bps_, audio_network_adaptor_config, |
2212 call_, this); | 1931 call_, this, engine()->encoder_factory_); |
2213 send_streams_.insert(std::make_pair(ssrc, stream)); | 1932 send_streams_.insert(std::make_pair(ssrc, stream)); |
2214 | 1933 |
2215 // At this point the stream's local SSRC has been updated. If it is the first | 1934 // At this point the stream's local SSRC has been updated. If it is the first |
2216 // send stream, make sure that all the receive streams are updated with the | 1935 // send stream, make sure that all the receive streams are updated with the |
2217 // same SSRC in order to send receiver reports. | 1936 // same SSRC in order to send receiver reports. |
2218 if (send_streams_.size() == 1) { | 1937 if (send_streams_.size() == 1) { |
2219 receiver_reports_ssrc_ = ssrc; | 1938 receiver_reports_ssrc_ = ssrc; |
2220 for (const auto& kv : recv_streams_) { | 1939 for (const auto& kv : recv_streams_) { |
2221 // TODO(solenberg): Allow applications to set the RTCP SSRC of receive | 1940 // TODO(solenberg): Allow applications to set the RTCP SSRC of receive |
2222 // streams instead, so we can avoid recreating the streams here. | 1941 // streams instead, so we can avoid recreating the streams here. |
(...skipping 475 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2698 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 2417 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
2699 const auto it = send_streams_.find(ssrc); | 2418 const auto it = send_streams_.find(ssrc); |
2700 if (it != send_streams_.end()) { | 2419 if (it != send_streams_.end()) { |
2701 return it->second->channel(); | 2420 return it->second->channel(); |
2702 } | 2421 } |
2703 return -1; | 2422 return -1; |
2704 } | 2423 } |
2705 } // namespace cricket | 2424 } // namespace cricket |
2706 | 2425 |
2707 #endif // HAVE_WEBRTC_VOICE | 2426 #endif // HAVE_WEBRTC_VOICE |
OLD | NEW |