| /* | 
 |  *  Copyright (c) 2012 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/video_engine/vie_rtp_rtcp_impl.h" | 
 |  | 
 | #include "webrtc/engine_configurations.h" | 
 | #include "webrtc/system_wrappers/interface/file_wrapper.h" | 
 | #include "webrtc/system_wrappers/interface/trace.h" | 
 | #include "webrtc/video_engine/include/vie_errors.h" | 
 | #include "webrtc/video_engine/vie_channel.h" | 
 | #include "webrtc/video_engine/vie_channel_manager.h" | 
 | #include "webrtc/video_engine/vie_defines.h" | 
 | #include "webrtc/video_engine/vie_encoder.h" | 
 | #include "webrtc/video_engine/vie_impl.h" | 
 | #include "webrtc/video_engine/vie_shared_data.h" | 
 |  | 
 | namespace webrtc { | 
 |  | 
 | // Helper methods for converting between module format and ViE API format. | 
 |  | 
 | static RTCPMethod ViERTCPModeToRTCPMethod(ViERTCPMode api_mode) { | 
 |   switch (api_mode) { | 
 |     case kRtcpNone: | 
 |       return kRtcpOff; | 
 |  | 
 |     case kRtcpCompound_RFC4585: | 
 |       return kRtcpCompound; | 
 |  | 
 |     case kRtcpNonCompound_RFC5506: | 
 |       return kRtcpNonCompound; | 
 |   } | 
 |   assert(false); | 
 |   return kRtcpOff; | 
 | } | 
 |  | 
 | static ViERTCPMode RTCPMethodToViERTCPMode(RTCPMethod module_method) { | 
 |   switch (module_method) { | 
 |     case kRtcpOff: | 
 |       return kRtcpNone; | 
 |  | 
 |     case kRtcpCompound: | 
 |       return kRtcpCompound_RFC4585; | 
 |  | 
 |     case kRtcpNonCompound: | 
 |       return kRtcpNonCompound_RFC5506; | 
 |   } | 
 |   assert(false); | 
 |   return kRtcpNone; | 
 | } | 
 |  | 
 | static KeyFrameRequestMethod APIRequestToModuleRequest( | 
 |   ViEKeyFrameRequestMethod api_method) { | 
 |   switch (api_method) { | 
 |     case kViEKeyFrameRequestNone: | 
 |       return kKeyFrameReqFirRtp; | 
 |  | 
 |     case kViEKeyFrameRequestPliRtcp: | 
 |       return kKeyFrameReqPliRtcp; | 
 |  | 
 |     case kViEKeyFrameRequestFirRtp: | 
 |       return kKeyFrameReqFirRtp; | 
 |  | 
 |     case kViEKeyFrameRequestFirRtcp: | 
 |       return kKeyFrameReqFirRtcp; | 
 |   } | 
 |   assert(false); | 
 |   return kKeyFrameReqFirRtp; | 
 | } | 
 |  | 
 | ViERTP_RTCP* ViERTP_RTCP::GetInterface(VideoEngine* video_engine) { | 
 | #ifdef WEBRTC_VIDEO_ENGINE_RTP_RTCP_API | 
 |   if (!video_engine) { | 
 |     return NULL; | 
 |   } | 
 |   VideoEngineImpl* vie_impl = static_cast<VideoEngineImpl*>(video_engine); | 
 |   ViERTP_RTCPImpl* vie_rtpimpl = vie_impl; | 
 |   // Increase ref count. | 
 |   (*vie_rtpimpl)++; | 
 |   return vie_rtpimpl; | 
 | #else | 
 |   return NULL; | 
 | #endif | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::Release() { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, shared_data_->instance_id(), | 
 |                "ViERTP_RTCP::Release()"); | 
 |   // Decrease ref count. | 
 |   (*this)--; | 
 |  | 
 |   int32_t ref_count = GetCount(); | 
 |   if (ref_count < 0) { | 
 |     WEBRTC_TRACE(kTraceWarning, kTraceVideo, shared_data_->instance_id(), | 
 |                  "ViERTP_RTCP release too many times"); | 
 |     shared_data_->SetLastError(kViEAPIDoesNotExist); | 
 |     return -1; | 
 |   } | 
 |   WEBRTC_TRACE(kTraceInfo, kTraceVideo, shared_data_->instance_id(), | 
 |                "ViERTP_RTCP reference count: %d", ref_count); | 
 |   return ref_count; | 
 | } | 
 |  | 
 | ViERTP_RTCPImpl::ViERTP_RTCPImpl(ViESharedData* shared_data) | 
 |     : shared_data_(shared_data) { | 
 |   WEBRTC_TRACE(kTraceMemory, kTraceVideo, shared_data_->instance_id(), | 
 |                "ViERTP_RTCPImpl::ViERTP_RTCPImpl() Ctor"); | 
 | } | 
 |  | 
 | ViERTP_RTCPImpl::~ViERTP_RTCPImpl() { | 
 |   WEBRTC_TRACE(kTraceMemory, kTraceVideo, shared_data_->instance_id(), | 
 |                "ViERTP_RTCPImpl::~ViERTP_RTCPImpl() Dtor"); | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::SetLocalSSRC(const int video_channel, | 
 |                                   const unsigned int SSRC, | 
 |                                   const StreamType usage, | 
 |                                   const unsigned char simulcast_idx) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d, SSRC: %d)", __FUNCTION__, video_channel, SSRC); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     // The channel doesn't exists | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   if (vie_channel->SetSSRC(SSRC, usage, simulcast_idx) != 0) { | 
 |     shared_data_->SetLastError(kViERtpRtcpUnknownError); | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::SetRemoteSSRCType(const int videoChannel, | 
 |                                        const StreamType usage, | 
 |                                        const unsigned int SSRC) const { | 
 |   WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), videoChannel), | 
 |                "%s(channel: %d, usage:%d SSRC: 0x%x)", | 
 |                __FUNCTION__, usage, videoChannel, SSRC); | 
 |  | 
 |   // Get the channel | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* ptrViEChannel = cs.Channel(videoChannel); | 
 |   if (ptrViEChannel == NULL) { | 
 |     // The channel doesn't exists | 
 |     WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), videoChannel), | 
 |                  "%s: Channel %d doesn't exist", | 
 |                  __FUNCTION__, videoChannel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   if (ptrViEChannel->SetRemoteSSRCType(usage, SSRC) != 0) { | 
 |     shared_data_->SetLastError(kViERtpRtcpUnknownError); | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::GetLocalSSRC(const int video_channel, | 
 |                                   unsigned int& SSRC) const { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d, SSRC: %d)", __FUNCTION__, video_channel, SSRC); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   uint8_t idx = 0; | 
 |   if (vie_channel->GetLocalSSRC(idx, &SSRC) != 0) { | 
 |     shared_data_->SetLastError(kViERtpRtcpUnknownError); | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::GetRemoteSSRC(const int video_channel, | 
 |                                    unsigned int& SSRC) const { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d)", __FUNCTION__, video_channel, SSRC); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   if (vie_channel->GetRemoteSSRC(&SSRC) != 0) { | 
 |     shared_data_->SetLastError(kViERtpRtcpUnknownError); | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::GetRemoteCSRCs(const int video_channel, | 
 |                                     unsigned int CSRCs[kRtpCsrcSize]) const { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d)", __FUNCTION__, video_channel); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   if (vie_channel->GetRemoteCSRC(CSRCs) != 0) { | 
 |     shared_data_->SetLastError(kViERtpRtcpUnknownError); | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::SetRtxSendPayloadType(const int video_channel, | 
 |                                            const uint8_t payload_type) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d)", __FUNCTION__, video_channel); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   if (vie_channel->SetRtxSendPayloadType(payload_type) != 0) { | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::SetRtxReceivePayloadType(const int video_channel, | 
 |                                               const uint8_t payload_type) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d)", __FUNCTION__, video_channel); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   vie_channel->SetRtxReceivePayloadType(payload_type); | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::SetStartSequenceNumber(const int video_channel, | 
 |                                             uint16_t sequence_number) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d, sequence_number: %u)", __FUNCTION__, | 
 |                video_channel, sequence_number); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   if (vie_channel->Sending()) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d already sending.", __FUNCTION__, | 
 |                  video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpAlreadySending); | 
 |     return -1; | 
 |   } | 
 |   if (vie_channel->SetStartSequenceNumber(sequence_number) != 0) { | 
 |     shared_data_->SetLastError(kViERtpRtcpUnknownError); | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::SetRTCPStatus(const int video_channel, | 
 |                                    const ViERTCPMode rtcp_mode) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d, mode: %d)", __FUNCTION__, video_channel, | 
 |                rtcp_mode); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |  | 
 |   RTCPMethod module_mode = ViERTCPModeToRTCPMethod(rtcp_mode); | 
 |   if (vie_channel->SetRTCPMode(module_mode) != 0) { | 
 |     shared_data_->SetLastError(kViERtpRtcpUnknownError); | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::GetRTCPStatus(const int video_channel, | 
 |                                    ViERTCPMode& rtcp_mode) const { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d)", __FUNCTION__, video_channel, rtcp_mode); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   RTCPMethod module_mode = kRtcpOff; | 
 |   if (vie_channel->GetRTCPMode(&module_mode) != 0) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: could not get current RTCP mode", __FUNCTION__); | 
 |     shared_data_->SetLastError(kViERtpRtcpUnknownError); | 
 |     return -1; | 
 |   } | 
 |   rtcp_mode = RTCPMethodToViERTCPMode(module_mode); | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::SetRTCPCName(const int video_channel, | 
 |                                   const char rtcp_cname[KMaxRTCPCNameLength]) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d, name: %s)", __FUNCTION__, video_channel, | 
 |                rtcp_cname); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   if (vie_channel->Sending()) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d already sending.", __FUNCTION__, | 
 |                  video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpAlreadySending); | 
 |     return -1; | 
 |   } | 
 |   if (vie_channel->SetRTCPCName(rtcp_cname) != 0) { | 
 |     shared_data_->SetLastError(kViERtpRtcpUnknownError); | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::GetRTCPCName(const int video_channel, | 
 |                                   char rtcp_cname[KMaxRTCPCNameLength]) const { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d)", __FUNCTION__, video_channel); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   if (vie_channel->GetRTCPCName(rtcp_cname) != 0) { | 
 |     shared_data_->SetLastError(kViERtpRtcpUnknownError); | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::GetRemoteRTCPCName( | 
 |     const int video_channel, | 
 |     char rtcp_cname[KMaxRTCPCNameLength]) const { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d)", __FUNCTION__, video_channel); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   if (vie_channel->GetRemoteRTCPCName(rtcp_cname) != 0) { | 
 |     shared_data_->SetLastError(kViERtpRtcpUnknownError); | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::SendApplicationDefinedRTCPPacket( | 
 |   const int video_channel, | 
 |   const unsigned char sub_type, | 
 |   unsigned int name, | 
 |   const char* data, | 
 |   uint16_t data_length_in_bytes) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d, sub_type: %c, name: %d, data: x, length: %u)", | 
 |                __FUNCTION__, video_channel, sub_type, name, | 
 |                data_length_in_bytes); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   if (!vie_channel->Sending()) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d not sending", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpNotSending); | 
 |     return -1; | 
 |   } | 
 |   RTCPMethod method; | 
 |   if (vie_channel->GetRTCPMode(&method) != 0 || method == kRtcpOff) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: RTCP disabled on channel %d.", __FUNCTION__, | 
 |                  video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpRtcpDisabled); | 
 |     return -1; | 
 |   } | 
 |   if (vie_channel->SendApplicationDefinedRTCPPacket( | 
 |         sub_type, name, reinterpret_cast<const uint8_t*>(data), | 
 |         data_length_in_bytes) != 0) { | 
 |     shared_data_->SetLastError(kViERtpRtcpUnknownError); | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::SetNACKStatus(const int video_channel, const bool enable) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d, enable: %d)", __FUNCTION__, video_channel, | 
 |                enable); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   if (vie_channel->SetNACKStatus(enable) != 0) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: failed for channel %d", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpUnknownError); | 
 |     return -1; | 
 |   } | 
 |  | 
 |   // Update the encoder | 
 |   ViEEncoder* vie_encoder = cs.Encoder(video_channel); | 
 |   if (!vie_encoder) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Could not get encoder for channel %d", __FUNCTION__, | 
 |                  video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpUnknownError); | 
 |     return -1; | 
 |   } | 
 |   vie_encoder->UpdateProtectionMethod(enable); | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::SetFECStatus(const int video_channel, const bool enable, | 
 |                                   const unsigned char payload_typeRED, | 
 |                                   const unsigned char payload_typeFEC) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d, enable: %d, payload_typeRED: %u, " | 
 |                "payloadTypeFEC: %u)", | 
 |                __FUNCTION__, video_channel, enable, payload_typeRED, | 
 |                payload_typeFEC); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, | 
 |                  video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   if (vie_channel->SetFECStatus(enable, payload_typeRED, | 
 |                                 payload_typeFEC) != 0) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: failed for channel %d", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpUnknownError); | 
 |     return -1; | 
 |   } | 
 |   // Update the encoder. | 
 |   ViEEncoder* vie_encoder = cs.Encoder(video_channel); | 
 |   if (!vie_encoder) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Could not get encoder for channel %d", __FUNCTION__, | 
 |                  video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpUnknownError); | 
 |     return -1; | 
 |   } | 
 |   vie_encoder->UpdateProtectionMethod(false); | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::SetHybridNACKFECStatus( | 
 |     const int video_channel, | 
 |     const bool enable, | 
 |     const unsigned char payload_typeRED, | 
 |     const unsigned char payload_typeFEC) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d, enable: %d, payload_typeRED: %u, " | 
 |                "payloadTypeFEC: %u)", | 
 |                __FUNCTION__, video_channel, enable, payload_typeRED, | 
 |                payload_typeFEC); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |  | 
 |   // Update the channel status with hybrid NACK FEC mode. | 
 |   if (vie_channel->SetHybridNACKFECStatus(enable, payload_typeRED, | 
 |                                           payload_typeFEC) != 0) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: failed for channel %d", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpUnknownError); | 
 |     return -1; | 
 |   } | 
 |  | 
 |   // Update the encoder. | 
 |   ViEEncoder* vie_encoder = cs.Encoder(video_channel); | 
 |   if (!vie_encoder) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Could not get encoder for channel %d", __FUNCTION__, | 
 |                  video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpUnknownError); | 
 |     return -1; | 
 |   } | 
 |   vie_encoder->UpdateProtectionMethod(enable); | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::SetSenderBufferingMode(int video_channel, | 
 |                                                int target_delay_ms) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d, sender target_delay: %d)", | 
 |                __FUNCTION__, video_channel, target_delay_ms); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   ViEEncoder* vie_encoder = cs.Encoder(video_channel); | 
 |   if (!vie_encoder) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Could not get encoder for channel %d", __FUNCTION__, | 
 |                  video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |  | 
 |   // Update the channel with buffering mode settings. | 
 |   if (vie_channel->SetSenderBufferingMode(target_delay_ms) != 0) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: failed for channel %d", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpUnknownError); | 
 |     return -1; | 
 |   } | 
 |  | 
 |   // Update the encoder's buffering mode settings. | 
 |   vie_encoder->SetSenderBufferingMode(target_delay_ms); | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::SetReceiverBufferingMode(int video_channel, | 
 |                                                  int target_delay_ms) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d, receiver target_delay: %d)", | 
 |                __FUNCTION__, video_channel, target_delay_ms); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |  | 
 |   // Update the channel with buffering mode settings. | 
 |   if (vie_channel->SetReceiverBufferingMode(target_delay_ms) != 0) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: failed for channel %d", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpUnknownError); | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::SetKeyFrameRequestMethod( | 
 |   const int video_channel, | 
 |   const ViEKeyFrameRequestMethod method) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d, method: %d)", __FUNCTION__, video_channel, | 
 |                method); | 
 |  | 
 |   // Get the channel. | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   KeyFrameRequestMethod module_method = APIRequestToModuleRequest(method); | 
 |   if (vie_channel->SetKeyFrameRequestMethod(module_method) != 0) { | 
 |     shared_data_->SetLastError(kViERtpRtcpUnknownError); | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::SetTMMBRStatus(const int video_channel, | 
 |                                     const bool enable) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d, enable: %d)", __FUNCTION__, video_channel, | 
 |                enable); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   if (vie_channel->EnableTMMBR(enable) != 0) { | 
 |     shared_data_->SetLastError(kViERtpRtcpUnknownError); | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::SetRembStatus(int video_channel, bool sender, | 
 |                                    bool receiver) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "ViERTP_RTCPImpl::SetRembStatus(%d, %d, %d)", video_channel, | 
 |                sender, receiver); | 
 |   if (!shared_data_->channel_manager()->SetRembStatus(video_channel, sender, | 
 |                                                       receiver)) { | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::SetSendTimestampOffsetStatus(int video_channel, | 
 |                                                   bool enable, | 
 |                                                   int id) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "ViERTP_RTCPImpl::SetSendTimestampOffsetStatus(%d, %d, %d)", | 
 |                video_channel, enable, id); | 
 |  | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   if (vie_channel->SetSendTimestampOffsetStatus(enable, id) != 0) { | 
 |     shared_data_->SetLastError(kViERtpRtcpUnknownError); | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::SetReceiveTimestampOffsetStatus(int video_channel, | 
 |                                                      bool enable, | 
 |                                                      int id) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "ViERTP_RTCPImpl::SetReceiveTimestampOffsetStatus(%d, %d, %d)", | 
 |                video_channel, enable, id); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   if (vie_channel->SetReceiveTimestampOffsetStatus(enable, id) != 0) { | 
 |     shared_data_->SetLastError(kViERtpRtcpUnknownError); | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::SetSendAbsoluteSendTimeStatus(int video_channel, | 
 |                                                    bool enable, | 
 |                                                    int id) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "ViERTP_RTCPImpl::SetSendAbsoluteSendTimeStatus(%d, %d, %d)", | 
 |                video_channel, enable, id); | 
 |  | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   if (vie_channel->SetSendAbsoluteSendTimeStatus(enable, id) != 0) { | 
 |     shared_data_->SetLastError(kViERtpRtcpUnknownError); | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::SetReceiveAbsoluteSendTimeStatus(int video_channel, | 
 |                                                       bool enable, | 
 |                                                       int id) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "ViERTP_RTCPImpl::SetReceiveAbsoluteSendTimeStatus(%d, %d, %d)", | 
 |                video_channel, enable, id); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   if (vie_channel->SetReceiveAbsoluteSendTimeStatus(enable, id) != 0) { | 
 |     shared_data_->SetLastError(kViERtpRtcpUnknownError); | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::SetRtcpXrRrtrStatus(int video_channel, bool enable) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "ViERTP_RTCPImpl::SetRtcpXrRrtrStatus(%d, %d)", | 
 |                video_channel, enable); | 
 |  | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   vie_channel->SetRtcpXrRrtrStatus(enable); | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::SetTransmissionSmoothingStatus(int video_channel, | 
 |                                                     bool enable) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d, enble: %d)", __FUNCTION__, video_channel, | 
 |                enable); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   vie_channel->SetTransmissionSmoothingStatus(enable); | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::SetMinTransmitBitrate(int video_channel, | 
 |                                            int min_transmit_bitrate_kbps) { | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEEncoder* vie_encoder = cs.Encoder(video_channel); | 
 |   if (vie_encoder == NULL) | 
 |     return -1; | 
 |   vie_encoder->SetMinTransmitBitrate(min_transmit_bitrate_kbps); | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::SetReservedTransmitBitrate( | 
 |     int video_channel, unsigned int reserved_transmit_bitrate_bps) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "ViERTP_RTCPImpl::SetReservedTransmitBitrate(%d, %d)", | 
 |                video_channel, reserved_transmit_bitrate_bps); | 
 |   if (!shared_data_->channel_manager()->SetReservedTransmitBitrate( | 
 |       video_channel, reserved_transmit_bitrate_bps)) { | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::GetReceiveChannelRtcpStatistics( | 
 |     const int video_channel, | 
 |     RtcpStatistics& basic_stats, | 
 |     int& rtt_ms) const { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d)", __FUNCTION__, video_channel); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |  | 
 |   // TODO(sprang): Clean this up when stats struct is propagated all the way. | 
 |   uint16_t frac_lost; | 
 |   if (vie_channel->GetReceivedRtcpStatistics( | 
 |           &frac_lost, | 
 |           &basic_stats.cumulative_lost, | 
 |           &basic_stats.extended_max_sequence_number, | 
 |           &basic_stats.jitter, | 
 |           &rtt_ms) != 0) { | 
 |     shared_data_->SetLastError(kViERtpRtcpUnknownError); | 
 |     return -1; | 
 |   } | 
 |   basic_stats.fraction_lost = frac_lost; | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::GetSendChannelRtcpStatistics(const int video_channel, | 
 |                                                   RtcpStatistics& basic_stats, | 
 |                                                   int& rtt_ms) const { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d)", __FUNCTION__, video_channel); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |  | 
 |   // TODO(sprang): Clean this up when stats struct is propagated all the way. | 
 |   uint16_t frac_lost; | 
 |   if (vie_channel->GetSendRtcpStatistics( | 
 |           &frac_lost, | 
 |           &basic_stats.cumulative_lost, | 
 |           &basic_stats.extended_max_sequence_number, | 
 |           &basic_stats.jitter, | 
 |           &rtt_ms) != 0) { | 
 |     shared_data_->SetLastError(kViERtpRtcpUnknownError); | 
 |     return -1; | 
 |   } | 
 |   basic_stats.fraction_lost = frac_lost; | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::GetRtpStatistics(const int video_channel, | 
 |                                       StreamDataCounters& sent, | 
 |                                       StreamDataCounters& received) const { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d)", __FUNCTION__, video_channel); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   if (vie_channel->GetRtpStatistics(&sent.bytes, | 
 |                                     &sent.packets, | 
 |                                     &received.bytes, | 
 |                                     &received.packets) != 0) { | 
 |     shared_data_->SetLastError(kViERtpRtcpUnknownError); | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::GetRtcpPacketTypeCounters( | 
 |     int video_channel, | 
 |     RtcpPacketTypeCounter* packets_sent, | 
 |     RtcpPacketTypeCounter* packets_received) const { | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   vie_channel->GetRtcpPacketTypeCounters(packets_sent, packets_received); | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::GetBandwidthUsage(const int video_channel, | 
 |                                        unsigned int& total_bitrate_sent, | 
 |                                        unsigned int& video_bitrate_sent, | 
 |                                        unsigned int& fec_bitrate_sent, | 
 |                                        unsigned int& nackBitrateSent) const { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d)", __FUNCTION__, video_channel); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   vie_channel->GetBandwidthUsage(&total_bitrate_sent, | 
 |                                  &video_bitrate_sent, | 
 |                                  &fec_bitrate_sent, | 
 |                                  &nackBitrateSent); | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::GetEstimatedSendBandwidth( | 
 |     const int video_channel, | 
 |     unsigned int* estimated_bandwidth) const { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d)", __FUNCTION__, video_channel); | 
 |   if (!shared_data_->channel_manager()->GetEstimatedSendBandwidth( | 
 |       video_channel, estimated_bandwidth)) { | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::GetEstimatedReceiveBandwidth( | 
 |     const int video_channel, | 
 |     unsigned int* estimated_bandwidth) const { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d)", __FUNCTION__, video_channel); | 
 |   if (!shared_data_->channel_manager()->GetEstimatedReceiveBandwidth( | 
 |       video_channel, estimated_bandwidth)) { | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::GetReceiveBandwidthEstimatorStats( | 
 |     const int video_channel, | 
 |     ReceiveBandwidthEstimatorStats* output) const { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d)", __FUNCTION__, video_channel); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Could not get channel %d", __FUNCTION__, | 
 |                  video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   vie_channel->GetReceiveBandwidthEstimatorStats(output); | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::GetPacerQueuingDelayMs( | 
 |     const int video_channel, int* delay_ms) const { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d)", __FUNCTION__, video_channel); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEEncoder* vie_encoder = cs.Encoder(video_channel); | 
 |   if (!vie_encoder) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Could not get encoder for channel %d", __FUNCTION__, | 
 |                  video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   *delay_ms = vie_encoder->PacerQueuingDelayMs(); | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::StartRTPDump(const int video_channel, | 
 |                                   const char file_nameUTF8[1024], | 
 |                                   RTPDirections direction) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d, file_name: %s, direction: %d)", __FUNCTION__, | 
 |                video_channel, file_nameUTF8, direction); | 
 |   assert(FileWrapper::kMaxFileNameSize == 1024); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   if (vie_channel->StartRTPDump(file_nameUTF8, direction) != 0) { | 
 |     shared_data_->SetLastError(kViERtpRtcpUnknownError); | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::StopRTPDump(const int video_channel, | 
 |                                  RTPDirections direction) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d, direction: %d)", __FUNCTION__, video_channel, | 
 |                direction); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   if (vie_channel->StopRTPDump(direction) != 0) { | 
 |     shared_data_->SetLastError(kViERtpRtcpUnknownError); | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::RegisterRTPObserver(const int video_channel, | 
 |                                          ViERTPObserver& observer) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d)", __FUNCTION__, video_channel); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   if (vie_channel->RegisterRtpObserver(&observer) != 0) { | 
 |     shared_data_->SetLastError(kViERtpRtcpObserverAlreadyRegistered); | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::DeregisterRTPObserver(const int video_channel) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d)", __FUNCTION__, video_channel); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   if (vie_channel->RegisterRtpObserver(NULL) != 0) { | 
 |     shared_data_->SetLastError(kViERtpRtcpObserverNotRegistered); | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::RegisterRTCPObserver(const int video_channel, | 
 |                                           ViERTCPObserver& observer) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d)", __FUNCTION__, video_channel); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   if (vie_channel->RegisterRtcpObserver(&observer) != 0) { | 
 |     shared_data_->SetLastError(kViERtpRtcpObserverAlreadyRegistered); | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::DeregisterRTCPObserver(const int video_channel) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d)", __FUNCTION__, video_channel); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   if (vie_channel->RegisterRtcpObserver(NULL) != 0) { | 
 |     shared_data_->SetLastError(kViERtpRtcpObserverNotRegistered); | 
 |     return -1; | 
 |   } | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::RegisterSendChannelRtcpStatisticsCallback( | 
 |   int video_channel, RtcpStatisticsCallback* callback) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d)", __FUNCTION__, video_channel); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   vie_channel->RegisterSendChannelRtcpStatisticsCallback(callback); | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::DeregisterSendChannelRtcpStatisticsCallback( | 
 |     int video_channel, RtcpStatisticsCallback* callback) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d)", __FUNCTION__, video_channel); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   vie_channel->RegisterSendChannelRtcpStatisticsCallback(NULL); | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::RegisterReceiveChannelRtcpStatisticsCallback( | 
 |     const int video_channel, | 
 |     RtcpStatisticsCallback* callback) { | 
 |   WEBRTC_TRACE(kTraceApiCall, | 
 |                kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d)", | 
 |                __FUNCTION__, | 
 |                video_channel); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   assert(vie_channel != NULL); | 
 |   vie_channel->RegisterReceiveChannelRtcpStatisticsCallback(callback); | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::DeregisterReceiveChannelRtcpStatisticsCallback( | 
 |     const int video_channel, | 
 |     RtcpStatisticsCallback* callback) { | 
 |   WEBRTC_TRACE(kTraceApiCall, | 
 |                kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d)", | 
 |                __FUNCTION__, | 
 |                video_channel); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   assert(vie_channel != NULL); | 
 |   vie_channel->RegisterReceiveChannelRtcpStatisticsCallback(NULL); | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::RegisterSendChannelRtpStatisticsCallback( | 
 |     int video_channel, StreamDataCountersCallback* callback) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d)", __FUNCTION__, video_channel); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   assert(vie_channel != NULL); | 
 |   vie_channel->RegisterSendChannelRtpStatisticsCallback(callback); | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::DeregisterSendChannelRtpStatisticsCallback( | 
 |     int video_channel, StreamDataCountersCallback* callback) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d)", __FUNCTION__, video_channel); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   assert(vie_channel != NULL); | 
 |   vie_channel->RegisterSendChannelRtpStatisticsCallback(NULL); | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::RegisterReceiveChannelRtpStatisticsCallback( | 
 |     const int video_channel, | 
 |     StreamDataCountersCallback* callback) { | 
 |   WEBRTC_TRACE(kTraceApiCall, | 
 |                kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d)", | 
 |                __FUNCTION__, | 
 |                video_channel); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   assert(vie_channel != NULL); | 
 |   vie_channel->RegisterReceiveChannelRtpStatisticsCallback(callback); | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::DeregisterReceiveChannelRtpStatisticsCallback( | 
 |     const int video_channel, | 
 |     StreamDataCountersCallback* callback) { | 
 |   WEBRTC_TRACE(kTraceApiCall, | 
 |                kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d)", | 
 |                __FUNCTION__, | 
 |                video_channel); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   assert(vie_channel != NULL); | 
 |   vie_channel->RegisterReceiveChannelRtpStatisticsCallback(NULL); | 
 |   return 0; | 
 | } | 
 |  | 
 | // Called whenever the send bitrate is updated. | 
 | int ViERTP_RTCPImpl::RegisterSendBitrateObserver( | 
 |     const int video_channel, | 
 |     BitrateStatisticsObserver* observer) { | 
 |   WEBRTC_TRACE(kTraceApiCall, | 
 |                kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d)", | 
 |                __FUNCTION__, | 
 |                video_channel); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   assert(vie_channel != NULL); | 
 |   vie_channel->RegisterSendBitrateObserver(observer); | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::DeregisterSendBitrateObserver( | 
 |     const int video_channel, | 
 |     BitrateStatisticsObserver* observer) { | 
 |   WEBRTC_TRACE(kTraceApiCall, | 
 |                kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d)", | 
 |                __FUNCTION__, | 
 |                video_channel); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   assert(vie_channel != NULL); | 
 |   vie_channel->RegisterSendBitrateObserver(NULL); | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::RegisterSendFrameCountObserver( | 
 |     int video_channel, FrameCountObserver* callback) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d)", __FUNCTION__, video_channel); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   vie_channel->RegisterSendFrameCountObserver(callback); | 
 |   return 0; | 
 | } | 
 |  | 
 | int ViERTP_RTCPImpl::DeregisterSendFrameCountObserver( | 
 |     int video_channel, FrameCountObserver* callback) { | 
 |   WEBRTC_TRACE(kTraceApiCall, kTraceVideo, | 
 |                ViEId(shared_data_->instance_id(), video_channel), | 
 |                "%s(channel: %d)", __FUNCTION__, video_channel); | 
 |   ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); | 
 |   ViEChannel* vie_channel = cs.Channel(video_channel); | 
 |   if (!vie_channel) { | 
 |     WEBRTC_TRACE(kTraceError, kTraceVideo, | 
 |                  ViEId(shared_data_->instance_id(), video_channel), | 
 |                  "%s: Channel %d doesn't exist", __FUNCTION__, video_channel); | 
 |     shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); | 
 |     return -1; | 
 |   } | 
 |   vie_channel->RegisterSendFrameCountObserver(NULL); | 
 |   return 0; | 
 | } | 
 | }  // namespace webrtc |