/* * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "webrtc/voice_engine/channel_proxy.h" #include #include "webrtc/api/call/audio_sink.h" #include "webrtc/base/checks.h" #include "webrtc/base/logging.h" #include "webrtc/voice_engine/channel.h" namespace webrtc { namespace voe { ChannelProxy::ChannelProxy() : channel_owner_(nullptr) {} ChannelProxy::ChannelProxy(const ChannelOwner& channel_owner) : channel_owner_(channel_owner) { RTC_CHECK(channel_owner_.channel()); module_process_thread_checker_.DetachFromThread(); } ChannelProxy::~ChannelProxy() {} void ChannelProxy::SetRTCPStatus(bool enable) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); channel()->SetRTCPStatus(enable); } void ChannelProxy::SetLocalSSRC(uint32_t ssrc) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); int error = channel()->SetLocalSSRC(ssrc); RTC_DCHECK_EQ(0, error); } void ChannelProxy::SetRTCP_CNAME(const std::string& c_name) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); // Note: VoERTP_RTCP::SetRTCP_CNAME() accepts a char[256] array. std::string c_name_limited = c_name.substr(0, 255); int error = channel()->SetRTCP_CNAME(c_name_limited.c_str()); RTC_DCHECK_EQ(0, error); } void ChannelProxy::SetNACKStatus(bool enable, int max_packets) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); channel()->SetNACKStatus(enable, max_packets); } void ChannelProxy::SetSendAudioLevelIndicationStatus(bool enable, int id) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); int error = channel()->SetSendAudioLevelIndicationStatus(enable, id); RTC_DCHECK_EQ(0, error); } void ChannelProxy::SetReceiveAudioLevelIndicationStatus(bool enable, int id) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); int error = channel()->SetReceiveAudioLevelIndicationStatus(enable, id); RTC_DCHECK_EQ(0, error); } void ChannelProxy::EnableSendTransportSequenceNumber(int id) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); channel()->EnableSendTransportSequenceNumber(id); } void ChannelProxy::EnableReceiveTransportSequenceNumber(int id) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); channel()->EnableReceiveTransportSequenceNumber(id); } void ChannelProxy::RegisterSenderCongestionControlObjects( RtpPacketSender* rtp_packet_sender, TransportFeedbackObserver* transport_feedback_observer, PacketRouter* packet_router, RtcpBandwidthObserver* bandwidth_observer) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); channel()->RegisterSenderCongestionControlObjects( rtp_packet_sender, transport_feedback_observer, packet_router, bandwidth_observer); } void ChannelProxy::RegisterReceiverCongestionControlObjects( PacketRouter* packet_router) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); channel()->RegisterReceiverCongestionControlObjects(packet_router); } void ChannelProxy::ResetCongestionControlObjects() { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); channel()->ResetCongestionControlObjects(); } CallStatistics ChannelProxy::GetRTCPStatistics() const { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); CallStatistics stats = {0}; int error = channel()->GetRTPStatistics(stats); RTC_DCHECK_EQ(0, error); return stats; } std::vector ChannelProxy::GetRemoteRTCPReportBlocks() const { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); std::vector blocks; int error = channel()->GetRemoteRTCPReportBlocks(&blocks); RTC_DCHECK_EQ(0, error); return blocks; } NetworkStatistics ChannelProxy::GetNetworkStatistics() const { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); NetworkStatistics stats = {0}; int error = channel()->GetNetworkStatistics(stats); RTC_DCHECK_EQ(0, error); return stats; } AudioDecodingCallStats ChannelProxy::GetDecodingCallStatistics() const { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); AudioDecodingCallStats stats; channel()->GetDecodingCallStatistics(&stats); return stats; } int ChannelProxy::GetSpeechOutputLevel() const { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); return channel()->GetSpeechOutputLevel(); } int ChannelProxy::GetSpeechOutputLevelFullRange() const { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); return channel()->GetSpeechOutputLevelFullRange(); } uint32_t ChannelProxy::GetDelayEstimate() const { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread() || module_process_thread_checker_.CalledOnValidThread()); return channel()->GetDelayEstimate(); } bool ChannelProxy::SetSendTelephoneEventPayloadType(int payload_type, int payload_frequency) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); return channel()->SetSendTelephoneEventPayloadType(payload_type, payload_frequency) == 0; } bool ChannelProxy::SendTelephoneEventOutband(int event, int duration_ms) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); return channel()->SendTelephoneEventOutband(event, duration_ms) == 0; } void ChannelProxy::SetBitrate(int bitrate_bps, int64_t probing_interval_ms) { // This method can be called on the worker thread, module process thread // or on a TaskQueue via VideoSendStreamImpl::OnEncoderConfigurationChanged. // TODO(solenberg): Figure out a good way to check this or enforce calling // rules. // RTC_DCHECK(worker_thread_checker_.CalledOnValidThread() || // module_process_thread_checker_.CalledOnValidThread()); channel()->SetBitRate(bitrate_bps, probing_interval_ms); } void ChannelProxy::SetRecPayloadType(int payload_type, const SdpAudioFormat& format) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); const int result = channel()->SetRecPayloadType(payload_type, format); RTC_DCHECK_EQ(0, result); } void ChannelProxy::SetSink(std::unique_ptr sink) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); channel()->SetSink(std::move(sink)); } void ChannelProxy::SetInputMute(bool muted) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); channel()->SetInputMute(muted); } void ChannelProxy::RegisterExternalTransport(Transport* transport) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); int error = channel()->RegisterExternalTransport(transport); RTC_DCHECK_EQ(0, error); } void ChannelProxy::DeRegisterExternalTransport() { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); channel()->DeRegisterExternalTransport(); } void ChannelProxy::OnRtpPacket(const RtpPacketReceived& packet) { // May be called on either worker thread or network thread. channel()->OnRtpPacket(packet); } bool ChannelProxy::ReceivedRTCPPacket(const uint8_t* packet, size_t length) { // May be called on either worker thread or network thread. return channel()->ReceivedRTCPPacket(packet, length) == 0; } const rtc::scoped_refptr& ChannelProxy::GetAudioDecoderFactory() const { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); return channel()->GetAudioDecoderFactory(); } void ChannelProxy::SetChannelOutputVolumeScaling(float scaling) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); channel()->SetChannelOutputVolumeScaling(scaling); } void ChannelProxy::SetRtcEventLog(RtcEventLog* event_log) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); channel()->SetRtcEventLog(event_log); } void ChannelProxy::EnableAudioNetworkAdaptor(const std::string& config_string) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); bool ret = channel()->EnableAudioNetworkAdaptor(config_string); RTC_DCHECK(ret); ;} void ChannelProxy::DisableAudioNetworkAdaptor() { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); channel()->DisableAudioNetworkAdaptor(); } void ChannelProxy::SetReceiverFrameLengthRange(int min_frame_length_ms, int max_frame_length_ms) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); channel()->SetReceiverFrameLengthRange(min_frame_length_ms, max_frame_length_ms); } AudioMixer::Source::AudioFrameInfo ChannelProxy::GetAudioFrameWithInfo( int sample_rate_hz, AudioFrame* audio_frame) { RTC_DCHECK_RUNS_SERIALIZED(&audio_thread_race_checker_); return channel()->GetAudioFrameWithInfo(sample_rate_hz, audio_frame); } int ChannelProxy::NeededFrequency() const { RTC_DCHECK_RUNS_SERIALIZED(&audio_thread_race_checker_); return static_cast(channel()->NeededFrequency(-1)); } void ChannelProxy::SetTransportOverhead(int transport_overhead_per_packet) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); channel()->SetTransportOverhead(transport_overhead_per_packet); } void ChannelProxy::AssociateSendChannel( const ChannelProxy& send_channel_proxy) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); channel()->set_associate_send_channel(send_channel_proxy.channel_owner_); } void ChannelProxy::DisassociateSendChannel() { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); channel()->set_associate_send_channel(ChannelOwner(nullptr)); } void ChannelProxy::GetRtpRtcp(RtpRtcp** rtp_rtcp, RtpReceiver** rtp_receiver) const { RTC_DCHECK(module_process_thread_checker_.CalledOnValidThread()); RTC_DCHECK(rtp_rtcp); RTC_DCHECK(rtp_receiver); int error = channel()->GetRtpRtcp(rtp_rtcp, rtp_receiver); RTC_DCHECK_EQ(0, error); } uint32_t ChannelProxy::GetPlayoutTimestamp() const { RTC_DCHECK_RUNS_SERIALIZED(&video_capture_thread_race_checker_); unsigned int timestamp = 0; int error = channel()->GetPlayoutTimestamp(timestamp); RTC_DCHECK(!error || timestamp == 0); return timestamp; } void ChannelProxy::SetMinimumPlayoutDelay(int delay_ms) { RTC_DCHECK(module_process_thread_checker_.CalledOnValidThread()); // Limit to range accepted by both VoE and ACM, so we're at least getting as // close as possible, instead of failing. delay_ms = std::max(0, std::min(delay_ms, 10000)); int error = channel()->SetMinimumPlayoutDelay(delay_ms); if (0 != error) { LOG(LS_WARNING) << "Error setting minimum playout delay."; } } void ChannelProxy::SetRtcpRttStats(RtcpRttStats* rtcp_rtt_stats) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); channel()->SetRtcpRttStats(rtcp_rtt_stats); } bool ChannelProxy::GetRecCodec(CodecInst* codec_inst) const { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); return channel()->GetRecCodec(*codec_inst) == 0; } bool ChannelProxy::GetSendCodec(CodecInst* codec_inst) const { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); return channel()->GetSendCodec(*codec_inst) == 0; } bool ChannelProxy::SetVADStatus(bool enable) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); return channel()->SetVADStatus(enable, VADNormal, false) == 0; } bool ChannelProxy::SetCodecFECStatus(bool enable) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); return channel()->SetCodecFECStatus(enable) == 0; } bool ChannelProxy::SetOpusDtx(bool enable) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); return channel()->SetOpusDtx(enable) == 0; } bool ChannelProxy::SetOpusMaxPlaybackRate(int frequency_hz) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); return channel()->SetOpusMaxPlaybackRate(frequency_hz) == 0; } bool ChannelProxy::SetSendCodec(const CodecInst& codec_inst) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); // Validation code copied from VoECodecImpl::SetSendCodec(). if ((STR_CASE_CMP(codec_inst.plname, "L16") == 0) && (codec_inst.pacsize >= 960)) { return false; } if (!STR_CASE_CMP(codec_inst.plname, "CN") || !STR_CASE_CMP(codec_inst.plname, "TELEPHONE-EVENT") || !STR_CASE_CMP(codec_inst.plname, "RED")) { return false; } if ((codec_inst.channels != 1) && (codec_inst.channels != 2)) { return false; } if (!AudioCodingModule::IsCodecValid(codec_inst)) { return false; } return channel()->SetSendCodec(codec_inst) == 0; } bool ChannelProxy::SetSendCNPayloadType(int type, PayloadFrequencies frequency) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); // Validation code copied from VoECodecImpl::SetSendCNPayloadType(). if (type < 96 || type > 127) { // Only allow dynamic range: 96 to 127 return false; } if ((frequency != kFreq16000Hz) && (frequency != kFreq32000Hz)) { // It is not possible to modify the payload type for CN/8000. // We only allow modification of the CN payload type for CN/16000 // and CN/32000. return false; } return channel()->SetSendCNPayloadType(type, frequency) == 0; } void ChannelProxy::OnTwccBasedUplinkPacketLossRate(float packet_loss_rate) { RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); channel()->OnTwccBasedUplinkPacketLossRate(packet_loss_rate); } void ChannelProxy::OnRecoverableUplinkPacketLossRate( float recoverable_packet_loss_rate) { // TODO(elad.alon): This fails in UT; fix and uncomment. // RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); channel()->OnRecoverableUplinkPacketLossRate(recoverable_packet_loss_rate); } Channel* ChannelProxy::channel() const { RTC_DCHECK(channel_owner_.channel()); return channel_owner_.channel(); } } // namespace voe } // namespace webrtc