| 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 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 127 // NOTE(ajm): Don't use hardcoded paths on platforms not explicitly specified | 127 // NOTE(ajm): Don't use hardcoded paths on platforms not explicitly specified |
| 128 // below. | 128 // below. |
| 129 #if defined(CHROMEOS) | 129 #if defined(CHROMEOS) |
| 130 const char kAecDumpByAudioOptionFilename[] = "/tmp/audio.aecdump"; | 130 const char kAecDumpByAudioOptionFilename[] = "/tmp/audio.aecdump"; |
| 131 #elif defined(ANDROID) | 131 #elif defined(ANDROID) |
| 132 const char kAecDumpByAudioOptionFilename[] = "/sdcard/audio.aecdump"; | 132 const char kAecDumpByAudioOptionFilename[] = "/sdcard/audio.aecdump"; |
| 133 #else | 133 #else |
| 134 const char kAecDumpByAudioOptionFilename[] = "audio.aecdump"; | 134 const char kAecDumpByAudioOptionFilename[] = "audio.aecdump"; |
| 135 #endif | 135 #endif |
| 136 | 136 |
| 137 // Constants from voice_engine_defines.h. |
| 138 const int kMinTelephoneEventCode = 0; // RFC4733 (Section 2.3.1) |
| 139 const int kMaxTelephoneEventCode = 255; |
| 140 const int kMinTelephoneEventDuration = 100; |
| 141 const int kMaxTelephoneEventDuration = 60000; // Actual limit is 2^16 |
| 142 |
| 137 bool ValidateStreamParams(const StreamParams& sp) { | 143 bool ValidateStreamParams(const StreamParams& sp) { |
| 138 if (sp.ssrcs.empty()) { | 144 if (sp.ssrcs.empty()) { |
| 139 LOG(LS_ERROR) << "No SSRCs in stream parameters: " << sp.ToString(); | 145 LOG(LS_ERROR) << "No SSRCs in stream parameters: " << sp.ToString(); |
| 140 return false; | 146 return false; |
| 141 } | 147 } |
| 142 if (sp.ssrcs.size() > 1) { | 148 if (sp.ssrcs.size() > 1) { |
| 143 LOG(LS_ERROR) << "Multiple SSRCs in stream parameters: " << sp.ToString(); | 149 LOG(LS_ERROR) << "Multiple SSRCs in stream parameters: " << sp.ToString(); |
| 144 return false; | 150 return false; |
| 145 } | 151 } |
| 146 return true; | 152 return true; |
| (...skipping 428 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 575 if (!SetOptions(GetDefaultEngineOptions())) { | 581 if (!SetOptions(GetDefaultEngineOptions())) { |
| 576 return false; | 582 return false; |
| 577 } | 583 } |
| 578 | 584 |
| 579 // Print our codec list again for the call diagnostic log | 585 // Print our codec list again for the call diagnostic log |
| 580 LOG(LS_INFO) << "WebRtc VoiceEngine codecs:"; | 586 LOG(LS_INFO) << "WebRtc VoiceEngine codecs:"; |
| 581 for (const AudioCodec& codec : codecs_) { | 587 for (const AudioCodec& codec : codecs_) { |
| 582 LOG(LS_INFO) << ToString(codec); | 588 LOG(LS_INFO) << ToString(codec); |
| 583 } | 589 } |
| 584 | 590 |
| 585 // Disable the DTMF playout when a tone is sent. | |
| 586 // PlayDtmfTone will be used if local playout is needed. | |
| 587 if (voe_wrapper_->dtmf()->SetDtmfFeedbackStatus(false) == -1) { | |
| 588 LOG_RTCERR1(SetDtmfFeedbackStatus, false); | |
| 589 } | |
| 590 | |
| 591 initialized_ = true; | 591 initialized_ = true; |
| 592 return true; | 592 return true; |
| 593 } | 593 } |
| 594 | 594 |
| 595 void WebRtcVoiceEngine::Terminate() { | 595 void WebRtcVoiceEngine::Terminate() { |
| 596 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 596 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
| 597 LOG(LS_INFO) << "WebRtcVoiceEngine::Terminate"; | 597 LOG(LS_INFO) << "WebRtcVoiceEngine::Terminate"; |
| 598 initialized_ = false; | 598 initialized_ = false; |
| 599 | 599 |
| 600 StopAecDump(); | 600 StopAecDump(); |
| (...skipping 650 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1251 if (stream_) { | 1251 if (stream_) { |
| 1252 call_->DestroyAudioSendStream(stream_); | 1252 call_->DestroyAudioSendStream(stream_); |
| 1253 stream_ = nullptr; | 1253 stream_ = nullptr; |
| 1254 } | 1254 } |
| 1255 config_.rtp.extensions = extensions; | 1255 config_.rtp.extensions = extensions; |
| 1256 RTC_DCHECK(!stream_); | 1256 RTC_DCHECK(!stream_); |
| 1257 stream_ = call_->CreateAudioSendStream(config_); | 1257 stream_ = call_->CreateAudioSendStream(config_); |
| 1258 RTC_CHECK(stream_); | 1258 RTC_CHECK(stream_); |
| 1259 } | 1259 } |
| 1260 | 1260 |
| 1261 bool SendTelephoneEvent(int payload_type, uint8_t event, |
| 1262 uint32_t duration_ms) { |
| 1263 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
| 1264 RTC_DCHECK(stream_); |
| 1265 return stream_->SendTelephoneEvent(payload_type, event, duration_ms); |
| 1266 } |
| 1267 |
| 1261 webrtc::AudioSendStream::Stats GetStats() const { | 1268 webrtc::AudioSendStream::Stats GetStats() const { |
| 1262 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 1269 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
| 1263 RTC_DCHECK(stream_); | 1270 RTC_DCHECK(stream_); |
| 1264 return stream_->GetStats(); | 1271 return stream_->GetStats(); |
| 1265 } | 1272 } |
| 1266 | 1273 |
| 1267 // Starts the rendering by setting a sink to the renderer to get data | 1274 // Starts the rendering by setting a sink to the renderer to get data |
| 1268 // callback. | 1275 // callback. |
| 1269 // This method is called on the libjingle worker thread. | 1276 // This method is called on the libjingle worker thread. |
| 1270 // TODO(xians): Make sure Start() is called only once. | 1277 // TODO(xians): Make sure Start() is called only once. |
| (...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1605 | 1612 |
| 1606 bool WebRtcVoiceMediaChannel::SetSendCodecs( | 1613 bool WebRtcVoiceMediaChannel::SetSendCodecs( |
| 1607 int channel, const std::vector<AudioCodec>& codecs) { | 1614 int channel, const std::vector<AudioCodec>& codecs) { |
| 1608 // Disable VAD, FEC, and RED unless we know the other side wants them. | 1615 // Disable VAD, FEC, and RED unless we know the other side wants them. |
| 1609 engine()->voe()->codec()->SetVADStatus(channel, false); | 1616 engine()->voe()->codec()->SetVADStatus(channel, false); |
| 1610 engine()->voe()->rtp()->SetNACKStatus(channel, false, 0); | 1617 engine()->voe()->rtp()->SetNACKStatus(channel, false, 0); |
| 1611 engine()->voe()->rtp()->SetREDStatus(channel, false); | 1618 engine()->voe()->rtp()->SetREDStatus(channel, false); |
| 1612 engine()->voe()->codec()->SetFECStatus(channel, false); | 1619 engine()->voe()->codec()->SetFECStatus(channel, false); |
| 1613 | 1620 |
| 1614 // Scan through the list to figure out the codec to use for sending, along | 1621 // Scan through the list to figure out the codec to use for sending, along |
| 1615 // with the proper configuration for VAD and DTMF. | 1622 // with the proper configuration for VAD. |
| 1616 bool found_send_codec = false; | 1623 bool found_send_codec = false; |
| 1617 webrtc::CodecInst send_codec; | 1624 webrtc::CodecInst send_codec; |
| 1618 memset(&send_codec, 0, sizeof(send_codec)); | 1625 memset(&send_codec, 0, sizeof(send_codec)); |
| 1619 | 1626 |
| 1620 bool nack_enabled = nack_enabled_; | 1627 bool nack_enabled = nack_enabled_; |
| 1621 bool enable_codec_fec = false; | 1628 bool enable_codec_fec = false; |
| 1622 bool enable_opus_dtx = false; | 1629 bool enable_opus_dtx = false; |
| 1623 int opus_max_playback_rate = 0; | 1630 int opus_max_playback_rate = 0; |
| 1624 | 1631 |
| 1625 // Set send codec (the first non-telephone-event/CN codec) | 1632 // Set send codec (the first non-telephone-event/CN codec) |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1734 } | 1741 } |
| 1735 } | 1742 } |
| 1736 | 1743 |
| 1737 // Always update the |send_codec_| to the currently set send codec. | 1744 // Always update the |send_codec_| to the currently set send codec. |
| 1738 send_codec_.reset(new webrtc::CodecInst(send_codec)); | 1745 send_codec_.reset(new webrtc::CodecInst(send_codec)); |
| 1739 | 1746 |
| 1740 if (send_bitrate_setting_) { | 1747 if (send_bitrate_setting_) { |
| 1741 SetSendBitrateInternal(send_bitrate_bps_); | 1748 SetSendBitrateInternal(send_bitrate_bps_); |
| 1742 } | 1749 } |
| 1743 | 1750 |
| 1744 // Loop through the codecs list again to config the telephone-event/CN codec. | 1751 // Loop through the codecs list again to config the CN codec. |
| 1745 for (const AudioCodec& codec : codecs) { | 1752 for (const AudioCodec& codec : codecs) { |
| 1746 // Ignore codecs we don't know about. The negotiation step should prevent | 1753 // Ignore codecs we don't know about. The negotiation step should prevent |
| 1747 // this, but double-check to be sure. | 1754 // this, but double-check to be sure. |
| 1748 webrtc::CodecInst voe_codec; | 1755 webrtc::CodecInst voe_codec; |
| 1749 if (!WebRtcVoiceEngine::ToCodecInst(codec, &voe_codec)) { | 1756 if (!WebRtcVoiceEngine::ToCodecInst(codec, &voe_codec)) { |
| 1750 LOG(LS_WARNING) << "Unknown codec " << ToString(codec); | 1757 LOG(LS_WARNING) << "Unknown codec " << ToString(codec); |
| 1751 continue; | 1758 continue; |
| 1752 } | 1759 } |
| 1753 | 1760 |
| 1754 // Find the DTMF telephone event "codec" and tell VoiceEngine channels | 1761 if (IsCodec(codec, kCnCodecName)) { |
| 1755 // about it. | |
| 1756 if (IsCodec(codec, kDtmfCodecName)) { | |
| 1757 if (engine()->voe()->dtmf()->SetSendTelephoneEventPayloadType( | |
| 1758 channel, codec.id) == -1) { | |
| 1759 LOG_RTCERR2(SetSendTelephoneEventPayloadType, channel, codec.id); | |
| 1760 return false; | |
| 1761 } | |
| 1762 } else if (IsCodec(codec, kCnCodecName)) { | |
| 1763 // Turn voice activity detection/comfort noise on if supported. | 1762 // Turn voice activity detection/comfort noise on if supported. |
| 1764 // Set the wideband CN payload type appropriately. | 1763 // Set the wideband CN payload type appropriately. |
| 1765 // (narrowband always uses the static payload type 13). | 1764 // (narrowband always uses the static payload type 13). |
| 1766 webrtc::PayloadFrequencies cn_freq; | 1765 webrtc::PayloadFrequencies cn_freq; |
| 1767 switch (codec.clockrate) { | 1766 switch (codec.clockrate) { |
| 1768 case 8000: | 1767 case 8000: |
| 1769 cn_freq = webrtc::kFreq8000Hz; | 1768 cn_freq = webrtc::kFreq8000Hz; |
| 1770 break; | 1769 break; |
| 1771 case 16000: | 1770 case 16000: |
| 1772 cn_freq = webrtc::kFreq16000Hz; | 1771 cn_freq = webrtc::kFreq16000Hz; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1807 } | 1806 } |
| 1808 } | 1807 } |
| 1809 } | 1808 } |
| 1810 } | 1809 } |
| 1811 return true; | 1810 return true; |
| 1812 } | 1811 } |
| 1813 | 1812 |
| 1814 bool WebRtcVoiceMediaChannel::SetSendCodecs( | 1813 bool WebRtcVoiceMediaChannel::SetSendCodecs( |
| 1815 const std::vector<AudioCodec>& codecs) { | 1814 const std::vector<AudioCodec>& codecs) { |
| 1816 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 1815 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
| 1816 // TODO(solenberg): Validate input - that payload types don't overlap, are |
| 1817 // within range, filter out codecs we don't support, |
| 1818 // redundant codecs etc. |
| 1817 | 1819 |
| 1818 dtmf_allowed_ = false; | 1820 // Find the DTMF telephone event "codec" payload type. |
| 1821 dtmf_payload_type_ = rtc::Optional<int>(); |
| 1819 for (const AudioCodec& codec : codecs) { | 1822 for (const AudioCodec& codec : codecs) { |
| 1820 // Find the DTMF telephone event "codec". | |
| 1821 if (IsCodec(codec, kDtmfCodecName)) { | 1823 if (IsCodec(codec, kDtmfCodecName)) { |
| 1822 dtmf_allowed_ = true; | 1824 dtmf_payload_type_ = rtc::Optional<int>(codec.id); |
| 1825 break; |
| 1823 } | 1826 } |
| 1824 } | 1827 } |
| 1825 | 1828 |
| 1826 // Cache the codecs in order to configure the channel created later. | 1829 // Cache the codecs in order to configure the channel created later. |
| 1827 send_codecs_ = codecs; | 1830 send_codecs_ = codecs; |
| 1828 for (const auto& ch : send_streams_) { | 1831 for (const auto& ch : send_streams_) { |
| 1829 if (!SetSendCodecs(ch.second->channel(), codecs)) { | 1832 if (!SetSendCodecs(ch.second->channel(), codecs)) { |
| 1830 return false; | 1833 return false; |
| 1831 } | 1834 } |
| 1832 } | 1835 } |
| (...skipping 442 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2275 volume)) { | 2278 volume)) { |
| 2276 LOG_RTCERR2(SetChannelOutputVolumeScaling, ch_id, volume); | 2279 LOG_RTCERR2(SetChannelOutputVolumeScaling, ch_id, volume); |
| 2277 return false; | 2280 return false; |
| 2278 } | 2281 } |
| 2279 LOG(LS_INFO) << "SetOutputVolume to " << volume | 2282 LOG(LS_INFO) << "SetOutputVolume to " << volume |
| 2280 << " for channel " << ch_id << " and ssrc " << ssrc; | 2283 << " for channel " << ch_id << " and ssrc " << ssrc; |
| 2281 return true; | 2284 return true; |
| 2282 } | 2285 } |
| 2283 | 2286 |
| 2284 bool WebRtcVoiceMediaChannel::CanInsertDtmf() { | 2287 bool WebRtcVoiceMediaChannel::CanInsertDtmf() { |
| 2285 return dtmf_allowed_; | 2288 return dtmf_payload_type_ ? true : false; |
| 2286 } | 2289 } |
| 2287 | 2290 |
| 2288 bool WebRtcVoiceMediaChannel::InsertDtmf(uint32_t ssrc, int event, | 2291 bool WebRtcVoiceMediaChannel::InsertDtmf(uint32_t ssrc, int event, |
| 2289 int duration) { | 2292 int duration) { |
| 2290 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 2293 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
| 2291 if (!dtmf_allowed_) { | 2294 LOG(LS_INFO) << "WebRtcVoiceMediaChannel::InsertDtmf"; |
| 2295 if (!dtmf_payload_type_) { |
| 2292 return false; | 2296 return false; |
| 2293 } | 2297 } |
| 2294 | 2298 |
| 2295 // Send the event. | 2299 // Figure out which WebRtcAudioSendStream to send the event on. |
| 2296 int channel = -1; | 2300 auto it = ssrc != 0 ? send_streams_.find(ssrc) : send_streams_.begin(); |
| 2297 if (ssrc == 0) { | 2301 if (it == send_streams_.end()) { |
| 2298 if (send_streams_.size() > 0) { | 2302 LOG(LS_WARNING) << "The specified ssrc " << ssrc << " is not in use."; |
| 2299 channel = send_streams_.begin()->second->channel(); | |
| 2300 } | |
| 2301 } else { | |
| 2302 channel = GetSendChannelId(ssrc); | |
| 2303 } | |
| 2304 if (channel == -1) { | |
| 2305 LOG(LS_WARNING) << "InsertDtmf - The specified ssrc " | |
| 2306 << ssrc << " is not in use."; | |
| 2307 return false; | 2303 return false; |
| 2308 } | 2304 } |
| 2309 // Send DTMF using out-of-band DTMF. ("true", as 3rd arg) | 2305 if (event < kMinTelephoneEventCode || |
| 2310 if (engine()->voe()->dtmf()->SendTelephoneEvent( | 2306 event > kMaxTelephoneEventCode) { |
| 2311 channel, event, true, duration) == -1) { | 2307 LOG(LS_WARNING) << "DTMF event code " << event << " out of range."; |
| 2312 LOG_RTCERR4(SendTelephoneEvent, channel, event, true, duration); | |
| 2313 return false; | 2308 return false; |
| 2314 } | 2309 } |
| 2315 | 2310 if (duration < kMinTelephoneEventDuration || |
| 2316 return true; | 2311 duration > kMaxTelephoneEventDuration) { |
| 2312 LOG(LS_WARNING) << "DTMF event duration " << duration << " out of range."; |
| 2313 return false; |
| 2314 } |
| 2315 return it->second->SendTelephoneEvent(*dtmf_payload_type_, event, duration); |
| 2317 } | 2316 } |
| 2318 | 2317 |
| 2319 void WebRtcVoiceMediaChannel::OnPacketReceived( | 2318 void WebRtcVoiceMediaChannel::OnPacketReceived( |
| 2320 rtc::Buffer* packet, const rtc::PacketTime& packet_time) { | 2319 rtc::Buffer* packet, const rtc::PacketTime& packet_time) { |
| 2321 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 2320 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
| 2322 | 2321 |
| 2323 uint32_t ssrc = 0; | 2322 uint32_t ssrc = 0; |
| 2324 if (!GetRtpSsrc(packet->data(), packet->size(), &ssrc)) { | 2323 if (!GetRtpSsrc(packet->data(), packet->size(), &ssrc)) { |
| 2325 return; | 2324 return; |
| 2326 } | 2325 } |
| (...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2638 } | 2637 } |
| 2639 } else { | 2638 } else { |
| 2640 LOG(LS_INFO) << "Stopping playout for channel #" << channel; | 2639 LOG(LS_INFO) << "Stopping playout for channel #" << channel; |
| 2641 engine()->voe()->base()->StopPlayout(channel); | 2640 engine()->voe()->base()->StopPlayout(channel); |
| 2642 } | 2641 } |
| 2643 return true; | 2642 return true; |
| 2644 } | 2643 } |
| 2645 } // namespace cricket | 2644 } // namespace cricket |
| 2646 | 2645 |
| 2647 #endif // HAVE_WEBRTC_VOICE | 2646 #endif // HAVE_WEBRTC_VOICE |
| OLD | NEW |