OLD | NEW |
---|---|
1 /* | 1 /* |
2 * libjingle | 2 * libjingle |
3 * Copyright 2004 Google Inc. | 3 * Copyright 2004 Google Inc. |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions are met: | 6 * modification, are permitted provided that the following conditions are met: |
7 * | 7 * |
8 * 1. Redistributions of source code must retain the above copyright notice, | 8 * 1. Redistributions of source code must retain the above copyright notice, |
9 * this list of conditions and the following disclaimer. | 9 * this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright notice, | 10 * 2. Redistributions in binary form must reproduce the above copyright notice, |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
126 // NOTE(ajm): Don't use hardcoded paths on platforms not explicitly specified | 126 // NOTE(ajm): Don't use hardcoded paths on platforms not explicitly specified |
127 // below. | 127 // below. |
128 #if defined(CHROMEOS) | 128 #if defined(CHROMEOS) |
129 const char kAecDumpByAudioOptionFilename[] = "/tmp/audio.aecdump"; | 129 const char kAecDumpByAudioOptionFilename[] = "/tmp/audio.aecdump"; |
130 #elif defined(ANDROID) | 130 #elif defined(ANDROID) |
131 const char kAecDumpByAudioOptionFilename[] = "/sdcard/audio.aecdump"; | 131 const char kAecDumpByAudioOptionFilename[] = "/sdcard/audio.aecdump"; |
132 #else | 132 #else |
133 const char kAecDumpByAudioOptionFilename[] = "audio.aecdump"; | 133 const char kAecDumpByAudioOptionFilename[] = "audio.aecdump"; |
134 #endif | 134 #endif |
135 | 135 |
136 // Constants from voice_engine_defines.h. | |
137 const int kMinTelephoneEventCode = 0; // RFC4733 (Section 2.3.1) | |
138 const int kMaxTelephoneEventCode = 255; | |
139 const int kMinTelephoneEventDuration = 100; | |
140 const int kMaxTelephoneEventDuration = 60000; // Actual limit is 2^16 | |
141 | |
136 bool ValidateStreamParams(const StreamParams& sp) { | 142 bool ValidateStreamParams(const StreamParams& sp) { |
137 if (sp.ssrcs.empty()) { | 143 if (sp.ssrcs.empty()) { |
138 LOG(LS_ERROR) << "No SSRCs in stream parameters: " << sp.ToString(); | 144 LOG(LS_ERROR) << "No SSRCs in stream parameters: " << sp.ToString(); |
139 return false; | 145 return false; |
140 } | 146 } |
141 if (sp.ssrcs.size() > 1) { | 147 if (sp.ssrcs.size() > 1) { |
142 LOG(LS_ERROR) << "Multiple SSRCs in stream parameters: " << sp.ToString(); | 148 LOG(LS_ERROR) << "Multiple SSRCs in stream parameters: " << sp.ToString(); |
143 return false; | 149 return false; |
144 } | 150 } |
145 return true; | 151 return true; |
(...skipping 442 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
588 if (!SetOptions(GetDefaultEngineOptions())) { | 594 if (!SetOptions(GetDefaultEngineOptions())) { |
589 return false; | 595 return false; |
590 } | 596 } |
591 | 597 |
592 // Print our codec list again for the call diagnostic log | 598 // Print our codec list again for the call diagnostic log |
593 LOG(LS_INFO) << "WebRtc VoiceEngine codecs:"; | 599 LOG(LS_INFO) << "WebRtc VoiceEngine codecs:"; |
594 for (const AudioCodec& codec : codecs_) { | 600 for (const AudioCodec& codec : codecs_) { |
595 LOG(LS_INFO) << ToString(codec); | 601 LOG(LS_INFO) << ToString(codec); |
596 } | 602 } |
597 | 603 |
598 // Disable the DTMF playout when a tone is sent. | |
599 // PlayDtmfTone will be used if local playout is needed. | |
600 if (voe_wrapper_->dtmf()->SetDtmfFeedbackStatus(false) == -1) { | |
601 LOG_RTCERR1(SetDtmfFeedbackStatus, false); | |
602 } | |
603 | |
604 initialized_ = true; | 604 initialized_ = true; |
605 return true; | 605 return true; |
606 } | 606 } |
607 | 607 |
608 void WebRtcVoiceEngine::Terminate() { | 608 void WebRtcVoiceEngine::Terminate() { |
609 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 609 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
610 LOG(LS_INFO) << "WebRtcVoiceEngine::Terminate"; | 610 LOG(LS_INFO) << "WebRtcVoiceEngine::Terminate"; |
611 initialized_ = false; | 611 initialized_ = false; |
612 | 612 |
613 StopAecDump(); | 613 StopAecDump(); |
(...skipping 709 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1323 | 1323 |
1324 // Callback from the |renderer_| when it is going away. In case Start() has | 1324 // Callback from the |renderer_| when it is going away. In case Start() has |
1325 // never been called, this callback won't be triggered. | 1325 // never been called, this callback won't be triggered. |
1326 void OnClose() override { | 1326 void OnClose() override { |
1327 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 1327 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
1328 // Set |renderer_| to nullptr to make sure no more callback will get into | 1328 // Set |renderer_| to nullptr to make sure no more callback will get into |
1329 // the renderer. | 1329 // the renderer. |
1330 renderer_ = nullptr; | 1330 renderer_ = nullptr; |
1331 } | 1331 } |
1332 | 1332 |
1333 // Accessor to the Call stream. | |
1334 webrtc::AudioSendStream* stream() { | |
1335 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | |
1336 RTC_DCHECK(stream_); | |
1337 return stream_; | |
pthatcher1
2015/12/02 18:45:37
Rather than expose the stream underneath, it seems
the sun
2015/12/03 09:57:47
Done.
| |
1338 } | |
1339 | |
1333 // Accessor to the VoE channel ID. | 1340 // Accessor to the VoE channel ID. |
1334 int channel() const { | 1341 int channel() const { |
1335 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 1342 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
1336 return config_.voe_channel_id; | 1343 return config_.voe_channel_id; |
1337 } | 1344 } |
1338 | 1345 |
1339 private: | 1346 private: |
1340 rtc::ThreadChecker worker_thread_checker_; | 1347 rtc::ThreadChecker worker_thread_checker_; |
1341 rtc::ThreadChecker audio_capture_thread_checker_; | 1348 rtc::ThreadChecker audio_capture_thread_checker_; |
1342 webrtc::AudioTransport* const voe_audio_transport_ = nullptr; | 1349 webrtc::AudioTransport* const voe_audio_transport_ = nullptr; |
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1606 | 1613 |
1607 bool WebRtcVoiceMediaChannel::SetSendCodecs( | 1614 bool WebRtcVoiceMediaChannel::SetSendCodecs( |
1608 int channel, const std::vector<AudioCodec>& codecs) { | 1615 int channel, const std::vector<AudioCodec>& codecs) { |
1609 // Disable VAD, FEC, and RED unless we know the other side wants them. | 1616 // Disable VAD, FEC, and RED unless we know the other side wants them. |
1610 engine()->voe()->codec()->SetVADStatus(channel, false); | 1617 engine()->voe()->codec()->SetVADStatus(channel, false); |
1611 engine()->voe()->rtp()->SetNACKStatus(channel, false, 0); | 1618 engine()->voe()->rtp()->SetNACKStatus(channel, false, 0); |
1612 engine()->voe()->rtp()->SetREDStatus(channel, false); | 1619 engine()->voe()->rtp()->SetREDStatus(channel, false); |
1613 engine()->voe()->codec()->SetFECStatus(channel, false); | 1620 engine()->voe()->codec()->SetFECStatus(channel, false); |
1614 | 1621 |
1615 // Scan through the list to figure out the codec to use for sending, along | 1622 // Scan through the list to figure out the codec to use for sending, along |
1616 // with the proper configuration for VAD and DTMF. | 1623 // with the proper configuration for VAD. |
1617 bool found_send_codec = false; | 1624 bool found_send_codec = false; |
1618 webrtc::CodecInst send_codec; | 1625 webrtc::CodecInst send_codec; |
1619 memset(&send_codec, 0, sizeof(send_codec)); | 1626 memset(&send_codec, 0, sizeof(send_codec)); |
1620 | 1627 |
1621 bool nack_enabled = nack_enabled_; | 1628 bool nack_enabled = nack_enabled_; |
1622 bool enable_codec_fec = false; | 1629 bool enable_codec_fec = false; |
1623 bool enable_opus_dtx = false; | 1630 bool enable_opus_dtx = false; |
1624 int opus_max_playback_rate = 0; | 1631 int opus_max_playback_rate = 0; |
1625 | 1632 |
1626 // Set send codec (the first non-telephone-event/CN codec) | 1633 // Set send codec (the first non-telephone-event/CN codec) |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1735 } | 1742 } |
1736 } | 1743 } |
1737 | 1744 |
1738 // Always update the |send_codec_| to the currently set send codec. | 1745 // Always update the |send_codec_| to the currently set send codec. |
1739 send_codec_.reset(new webrtc::CodecInst(send_codec)); | 1746 send_codec_.reset(new webrtc::CodecInst(send_codec)); |
1740 | 1747 |
1741 if (send_bitrate_setting_) { | 1748 if (send_bitrate_setting_) { |
1742 SetSendBitrateInternal(send_bitrate_bps_); | 1749 SetSendBitrateInternal(send_bitrate_bps_); |
1743 } | 1750 } |
1744 | 1751 |
1745 // Loop through the codecs list again to config the telephone-event/CN codec. | 1752 // Loop through the codecs list again to config the CN codec. |
1746 for (const AudioCodec& codec : codecs) { | 1753 for (const AudioCodec& codec : codecs) { |
1747 // Ignore codecs we don't know about. The negotiation step should prevent | 1754 // Ignore codecs we don't know about. The negotiation step should prevent |
1748 // this, but double-check to be sure. | 1755 // this, but double-check to be sure. |
1749 webrtc::CodecInst voe_codec; | 1756 webrtc::CodecInst voe_codec; |
1750 if (!WebRtcVoiceEngine::ToCodecInst(codec, &voe_codec)) { | 1757 if (!WebRtcVoiceEngine::ToCodecInst(codec, &voe_codec)) { |
1751 LOG(LS_WARNING) << "Unknown codec " << ToString(codec); | 1758 LOG(LS_WARNING) << "Unknown codec " << ToString(codec); |
1752 continue; | 1759 continue; |
1753 } | 1760 } |
1754 | 1761 |
1755 // Find the DTMF telephone event "codec" and tell VoiceEngine channels | 1762 if (IsCodec(codec, kCnCodecName)) { |
1756 // about it. | |
1757 if (IsCodec(codec, kDtmfCodecName)) { | |
1758 if (engine()->voe()->dtmf()->SetSendTelephoneEventPayloadType( | |
1759 channel, codec.id) == -1) { | |
1760 LOG_RTCERR2(SetSendTelephoneEventPayloadType, channel, codec.id); | |
1761 return false; | |
1762 } | |
1763 } else if (IsCodec(codec, kCnCodecName)) { | |
1764 // Turn voice activity detection/comfort noise on if supported. | 1763 // Turn voice activity detection/comfort noise on if supported. |
1765 // Set the wideband CN payload type appropriately. | 1764 // Set the wideband CN payload type appropriately. |
1766 // (narrowband always uses the static payload type 13). | 1765 // (narrowband always uses the static payload type 13). |
1767 webrtc::PayloadFrequencies cn_freq; | 1766 webrtc::PayloadFrequencies cn_freq; |
1768 switch (codec.clockrate) { | 1767 switch (codec.clockrate) { |
1769 case 8000: | 1768 case 8000: |
1770 cn_freq = webrtc::kFreq8000Hz; | 1769 cn_freq = webrtc::kFreq8000Hz; |
1771 break; | 1770 break; |
1772 case 16000: | 1771 case 16000: |
1773 cn_freq = webrtc::kFreq16000Hz; | 1772 cn_freq = webrtc::kFreq16000Hz; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1808 } | 1807 } |
1809 } | 1808 } |
1810 } | 1809 } |
1811 } | 1810 } |
1812 return true; | 1811 return true; |
1813 } | 1812 } |
1814 | 1813 |
1815 bool WebRtcVoiceMediaChannel::SetSendCodecs( | 1814 bool WebRtcVoiceMediaChannel::SetSendCodecs( |
1816 const std::vector<AudioCodec>& codecs) { | 1815 const std::vector<AudioCodec>& codecs) { |
1817 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 1816 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
1817 // TODO(solenberg): Validate input - that payload types don't overlap, are | |
1818 // within range, filter out codecs we don't support, | |
1819 // redundant codecs etc. | |
1818 | 1820 |
1819 dtmf_allowed_ = false; | 1821 // Find the DTMF telephone event "codec" payload type. |
1822 dtmf_payload_type_ = rtc::Optional<int>(); | |
1820 for (const AudioCodec& codec : codecs) { | 1823 for (const AudioCodec& codec : codecs) { |
1821 // Find the DTMF telephone event "codec". | |
1822 if (IsCodec(codec, kDtmfCodecName)) { | 1824 if (IsCodec(codec, kDtmfCodecName)) { |
1823 dtmf_allowed_ = true; | 1825 dtmf_payload_type_ = rtc::Optional<int>(codec.id); |
1826 break; | |
1824 } | 1827 } |
1825 } | 1828 } |
1826 | 1829 |
1827 // Cache the codecs in order to configure the channel created later. | 1830 // Cache the codecs in order to configure the channel created later. |
1828 send_codecs_ = codecs; | 1831 send_codecs_ = codecs; |
1829 for (const auto& ch : send_streams_) { | 1832 for (const auto& ch : send_streams_) { |
1830 if (!SetSendCodecs(ch.second->channel(), codecs)) { | 1833 if (!SetSendCodecs(ch.second->channel(), codecs)) { |
1831 return false; | 1834 return false; |
1832 } | 1835 } |
1833 } | 1836 } |
(...skipping 442 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2276 volume)) { | 2279 volume)) { |
2277 LOG_RTCERR2(SetChannelOutputVolumeScaling, ch_id, volume); | 2280 LOG_RTCERR2(SetChannelOutputVolumeScaling, ch_id, volume); |
2278 return false; | 2281 return false; |
2279 } | 2282 } |
2280 LOG(LS_INFO) << "SetOutputVolume to " << volume | 2283 LOG(LS_INFO) << "SetOutputVolume to " << volume |
2281 << " for channel " << ch_id << " and ssrc " << ssrc; | 2284 << " for channel " << ch_id << " and ssrc " << ssrc; |
2282 return true; | 2285 return true; |
2283 } | 2286 } |
2284 | 2287 |
2285 bool WebRtcVoiceMediaChannel::CanInsertDtmf() { | 2288 bool WebRtcVoiceMediaChannel::CanInsertDtmf() { |
2286 return dtmf_allowed_; | 2289 return dtmf_payload_type_ ? true : false; |
2287 } | 2290 } |
2288 | 2291 |
2289 bool WebRtcVoiceMediaChannel::InsertDtmf(uint32_t ssrc, int event, | 2292 bool WebRtcVoiceMediaChannel::InsertDtmf(uint32_t ssrc, int event, |
2290 int duration) { | 2293 int duration) { |
2291 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 2294 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
2292 if (!dtmf_allowed_) { | 2295 LOG(LS_INFO) << "WebRtcVoiceMediaChannel::InsertDtmf"; |
2296 if (!dtmf_payload_type_) { | |
2293 return false; | 2297 return false; |
2294 } | 2298 } |
2295 | 2299 |
2296 // Send the event. | 2300 // Figure out which WebRtcAudioSendStream to send the event on. |
2297 int channel = -1; | 2301 auto it = send_streams_.end(); |
2298 if (ssrc == 0) { | 2302 if (ssrc == 0) { |
2299 if (send_streams_.size() > 0) { | 2303 it = send_streams_.begin(); |
2300 channel = send_streams_.begin()->second->channel(); | |
2301 } | |
2302 } else { | 2304 } else { |
2303 channel = GetSendChannelId(ssrc); | 2305 it = send_streams_.find(ssrc); |
2304 } | 2306 } |
pthatcher1
2015/12/02 18:45:37
Does this work?
audio it = ssrc ? send_streams_.f
the sun
2015/12/03 09:57:47
Nice one!
Except "audio" is not a recognized C++
| |
2305 if (channel == -1) { | 2307 if (it == send_streams_.end()) { |
2306 LOG(LS_WARNING) << "InsertDtmf - The specified ssrc " | 2308 LOG(LS_WARNING) << "The specified ssrc " << ssrc << " is not in use."; |
2307 << ssrc << " is not in use."; | |
2308 return false; | 2309 return false; |
2309 } | 2310 } |
2310 // Send DTMF using out-of-band DTMF. ("true", as 3rd arg) | 2311 if (event < kMinTelephoneEventCode || |
2311 if (engine()->voe()->dtmf()->SendTelephoneEvent( | 2312 event > kMaxTelephoneEventCode) { |
2312 channel, event, true, duration) == -1) { | 2313 LOG(LS_WARNING) << "DTMF event code " << event << " out of range."; |
2313 LOG_RTCERR4(SendTelephoneEvent, channel, event, true, duration); | |
2314 return false; | 2314 return false; |
2315 } | 2315 } |
2316 | 2316 if (duration < kMinTelephoneEventDuration || |
2317 return true; | 2317 duration > kMaxTelephoneEventDuration) { |
2318 LOG(LS_WARNING) << "DTMF event duration " << duration << " out of range."; | |
2319 return false; | |
2320 } | |
2321 return it->second->stream()->SendTelephoneEvent(*dtmf_payload_type_, event, | |
2322 duration); | |
2318 } | 2323 } |
2319 | 2324 |
2320 void WebRtcVoiceMediaChannel::OnPacketReceived( | 2325 void WebRtcVoiceMediaChannel::OnPacketReceived( |
2321 rtc::Buffer* packet, const rtc::PacketTime& packet_time) { | 2326 rtc::Buffer* packet, const rtc::PacketTime& packet_time) { |
2322 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 2327 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
2323 | 2328 |
2324 uint32_t ssrc = 0; | 2329 uint32_t ssrc = 0; |
2325 if (!GetRtpSsrc(packet->data(), packet->size(), &ssrc)) { | 2330 if (!GetRtpSsrc(packet->data(), packet->size(), &ssrc)) { |
2326 return; | 2331 return; |
2327 } | 2332 } |
(...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2639 } | 2644 } |
2640 } else { | 2645 } else { |
2641 LOG(LS_INFO) << "Stopping playout for channel #" << channel; | 2646 LOG(LS_INFO) << "Stopping playout for channel #" << channel; |
2642 engine()->voe()->base()->StopPlayout(channel); | 2647 engine()->voe()->base()->StopPlayout(channel); |
2643 } | 2648 } |
2644 return true; | 2649 return true; |
2645 } | 2650 } |
2646 } // namespace cricket | 2651 } // namespace cricket |
2647 | 2652 |
2648 #endif // HAVE_WEBRTC_VOICE | 2653 #endif // HAVE_WEBRTC_VOICE |
OLD | NEW |