/*
 *  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/logging.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() {
  // Decrease ref count.
  (*this)--;

  int32_t ref_count = GetCount();
  if (ref_count < 0) {
    LOG(LS_ERROR) << "ViERTP_RTCP released too many times.";
    shared_data_->SetLastError(kViEAPIDoesNotExist);
    return -1;
  }
  return ref_count;
}

ViERTP_RTCPImpl::ViERTP_RTCPImpl(ViESharedData* shared_data)
    : shared_data_(shared_data) {}

ViERTP_RTCPImpl::~ViERTP_RTCPImpl() {}

int ViERTP_RTCPImpl::SetLocalSSRC(const int video_channel,
                                  const unsigned int SSRC,
                                  const StreamType usage,
                                  const unsigned char simulcast_idx) {
  LOG_F(LS_INFO) << "channel: " << video_channel << " ssrc: " << SSRC << "";
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_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 {
  LOG_F(LS_INFO) << "channel: " << videoChannel
                 << " usage: " << static_cast<int>(usage) << " ssrc: " << SSRC;

  // Get the channel
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* ptrViEChannel = cs.Channel(videoChannel);
  if (ptrViEChannel == NULL) {
    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 {
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_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 {
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_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 {
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_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) {
  LOG_F(LS_INFO) << "channel: " << video_channel
                 << " payload_type: " << static_cast<int>(payload_type);
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel) {
    shared_data_->SetLastError(kViERtpRtcpInvalidChannelId);
    return -1;
  }
  if (vie_channel->SetRtxSendPayloadType(payload_type) != 0) {
    return -1;
  }
  return 0;
}

int ViERTP_RTCPImpl::SetPadWithRedundantPayloads(int video_channel,
                                                 bool enable) {
  LOG_F(LS_INFO) << "channel: " << video_channel
                 << " pad with redundant payloads: " << (enable ? "enable" :
                 "disable");
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel) {
    shared_data_->SetLastError(kViERtpRtcpInvalidChannelId);
    return -1;
  }
  vie_channel->SetPadWithRedundantPayloads(enable);
  return 0;
}

int ViERTP_RTCPImpl::SetRtxReceivePayloadType(const int video_channel,
                                              const uint8_t payload_type) {
  LOG_F(LS_INFO) << "channel: " << video_channel
               << " payload_type: " << static_cast<int>(payload_type);
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_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) {
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel) {
    shared_data_->SetLastError(kViERtpRtcpInvalidChannelId);
    return -1;
  }
  if (vie_channel->Sending()) {
    LOG_F(LS_ERROR) << "channel " << video_channel << " is already sending.";
    shared_data_->SetLastError(kViERtpRtcpAlreadySending);
    return -1;
  }
  if (vie_channel->SetStartSequenceNumber(sequence_number) != 0) {
    shared_data_->SetLastError(kViERtpRtcpUnknownError);
    return -1;
  }
  return 0;
}

void ViERTP_RTCPImpl::SetRtpStateForSsrc(int video_channel,
                                         uint32_t ssrc,
                                         const RtpState& rtp_state) {
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel)
    return;

  if (vie_channel->Sending()) {
    LOG_F(LS_ERROR) << "channel " << video_channel << " is already sending.";
    return;
  }
  vie_channel->SetRtpStateForSsrc(ssrc, rtp_state);
}

RtpState ViERTP_RTCPImpl::GetRtpStateForSsrc(int video_channel, uint32_t ssrc) {
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel)
    return RtpState();

  return vie_channel->GetRtpStateForSsrc(ssrc);
}

int ViERTP_RTCPImpl::SetRTCPStatus(const int video_channel,
                                   const ViERTCPMode rtcp_mode) {
  LOG_F(LS_INFO) << "channel: " << video_channel
                 << " mode: " << static_cast<int>(rtcp_mode);
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_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 {
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel) {
    shared_data_->SetLastError(kViERtpRtcpInvalidChannelId);
    return -1;
  }
  RTCPMethod module_mode = kRtcpOff;
  if (vie_channel->GetRTCPMode(&module_mode) != 0) {
    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]) {
  LOG_F(LS_INFO) << "channel: " << video_channel
                 << " rtcp_cname: " << rtcp_cname;
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel) {
    shared_data_->SetLastError(kViERtpRtcpInvalidChannelId);
    return -1;
  }
  if (vie_channel->Sending()) {
    LOG_F(LS_ERROR) << "channel " << video_channel << " is already sending.";
    shared_data_->SetLastError(kViERtpRtcpAlreadySending);
    return -1;
  }
  if (vie_channel->SetRTCPCName(rtcp_cname) != 0) {
    shared_data_->SetLastError(kViERtpRtcpUnknownError);
    return -1;
  }
  return 0;
}

int ViERTP_RTCPImpl::GetRemoteRTCPCName(
    const int video_channel,
    char rtcp_cname[KMaxRTCPCNameLength]) const {
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_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) {
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel) {
    shared_data_->SetLastError(kViERtpRtcpInvalidChannelId);
    return -1;
  }
  if (!vie_channel->Sending()) {
    shared_data_->SetLastError(kViERtpRtcpNotSending);
    return -1;
  }
  RTCPMethod method;
  if (vie_channel->GetRTCPMode(&method) != 0 || method == kRtcpOff) {
    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) {
  LOG_F(LS_INFO) << "channel: " << video_channel << " "
                 << (enable ? "on" : "off");
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel) {
    shared_data_->SetLastError(kViERtpRtcpInvalidChannelId);
    return -1;
  }
  if (vie_channel->SetNACKStatus(enable) != 0) {
    shared_data_->SetLastError(kViERtpRtcpUnknownError);
    return -1;
  }

  // Update the encoder
  ViEEncoder* vie_encoder = cs.Encoder(video_channel);
  if (!vie_encoder) {
    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) {
  LOG_F(LS_INFO) << "channel: " << video_channel
                 << " enable: " << (enable ? "on" : "off")
                 << " payload_typeRED: " << static_cast<int>(payload_typeRED)
                 << " payload_typeFEC: " << static_cast<int>(payload_typeFEC);
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel) {
    shared_data_->SetLastError(kViERtpRtcpInvalidChannelId);
    return -1;
  }
  if (vie_channel->SetFECStatus(enable, payload_typeRED,
                                payload_typeFEC) != 0) {
    shared_data_->SetLastError(kViERtpRtcpUnknownError);
    return -1;
  }
  // Update the encoder.
  ViEEncoder* vie_encoder = cs.Encoder(video_channel);
  if (!vie_encoder) {
    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) {
  LOG_F(LS_INFO) << "channel: " << video_channel
                 << " enable: " << (enable ? "on" : "off")
                 << " payload_typeRED: " << static_cast<int>(payload_typeRED)
                 << " payload_typeFEC: " << static_cast<int>(payload_typeFEC);
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_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) {
    shared_data_->SetLastError(kViERtpRtcpUnknownError);
    return -1;
  }

  // Update the encoder.
  ViEEncoder* vie_encoder = cs.Encoder(video_channel);
  if (!vie_encoder) {
    shared_data_->SetLastError(kViERtpRtcpUnknownError);
    return -1;
  }
  vie_encoder->UpdateProtectionMethod(enable);
  return 0;
}

int ViERTP_RTCPImpl::SetSenderBufferingMode(int video_channel,
                                            int target_delay_ms) {
  LOG_F(LS_INFO) << "channel: " << video_channel
                 << " target_delay_ms: " << target_delay_ms;
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel) {
    shared_data_->SetLastError(kViERtpRtcpInvalidChannelId);
    return -1;
  }
  ViEEncoder* vie_encoder = cs.Encoder(video_channel);
  if (!vie_encoder) {
    shared_data_->SetLastError(kViERtpRtcpInvalidChannelId);
    return -1;
  }

  // Update the channel with buffering mode settings.
  if (vie_channel->SetSenderBufferingMode(target_delay_ms) != 0) {
    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) {
  LOG_F(LS_INFO) << "channel: " << video_channel
                 << " target_delay_ms: " << target_delay_ms;
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel) {
    shared_data_->SetLastError(kViERtpRtcpInvalidChannelId);
    return -1;
  }

  // Update the channel with buffering mode settings.
  if (vie_channel->SetReceiverBufferingMode(target_delay_ms) != 0) {
    shared_data_->SetLastError(kViERtpRtcpUnknownError);
    return -1;
  }
  return 0;
}

int ViERTP_RTCPImpl::SetKeyFrameRequestMethod(
  const int video_channel,
  const ViEKeyFrameRequestMethod method) {
  LOG_F(LS_INFO) << "channel: " << video_channel
                 << " method: " << static_cast<int>(method);

  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_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) {
  LOG_F(LS_INFO) << "channel: " << video_channel
                 << "enable: " << (enable ? "on" : "off");
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_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) {
  LOG_F(LS_INFO) << "channel: " << video_channel
                 << " sender: " << (sender ? "on" : "off")
                 << " receiver: " << (receiver ? "on" : "off");
  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) {
  LOG_F(LS_INFO) << "channel: " << video_channel
                 << "enable: " << (enable ? "on" : "off") << " id: " << id;

  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_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) {
  LOG_F(LS_INFO) << "channel: " << video_channel
                 << "enable: " << (enable ? "on" : "off") << " id: " << id;
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_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) {
  LOG_F(LS_INFO) << "channel: " << video_channel
                 << "enable: " << (enable ? "on" : "off") << " id: " << id;

  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_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) {
  LOG_F(LS_INFO) << "channel: " << video_channel
                 << "enable: " << (enable ? "on" : "off") << " id: " << id;
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_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) {
  LOG_F(LS_INFO) << "channel: " << video_channel
                 << " enable: " << (enable ? "on" : "off");

  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel) {
    shared_data_->SetLastError(kViERtpRtcpInvalidChannelId);
    return -1;
  }
  vie_channel->SetRtcpXrRrtrStatus(enable);
  return 0;
}

int ViERTP_RTCPImpl::SetTransmissionSmoothingStatus(int video_channel,
                                                    bool enable) {
  LOG_F(LS_INFO) << "channel: " << video_channel
                 << " enable: " << (enable ? "on" : "off");
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_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) {
  LOG_F(LS_INFO) << "channel: " << video_channel
                 << " min_transmit_bitrate_kbps: " << 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) {
  LOG_F(LS_INFO) << "channel: " << video_channel
                 << " reserved_transmit_bitrate_bps: "
                 << 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 {
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_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 {
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_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 {
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_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) {
    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 {
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_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 {
  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 {
  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 {
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_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 {
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEEncoder* vie_encoder = cs.Encoder(video_channel);
  if (!vie_encoder) {
    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) {
  LOG_F(LS_INFO) << "channel: " << video_channel
                 << " filename: " << file_nameUTF8
                 << " direction: " << static_cast<int>(direction);
  assert(FileWrapper::kMaxFileNameSize == 1024);
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_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) {
  LOG_F(LS_INFO) << "channel: " << video_channel
                 << " direction: " << static_cast<int>(direction);
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_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) {
  LOG_F(LS_INFO) << "channel " << video_channel;
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_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) {
  LOG_F(LS_INFO) << "channel " << video_channel;
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_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) {
  LOG_F(LS_INFO) << "channel " << video_channel;
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_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) {
  LOG_F(LS_INFO) << "channel " << video_channel;
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_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) {
  LOG_F(LS_INFO) << "channel " << video_channel;
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel) {
    shared_data_->SetLastError(kViERtpRtcpInvalidChannelId);
    return -1;
  }
  vie_channel->RegisterSendChannelRtcpStatisticsCallback(callback);
  return 0;
}

int ViERTP_RTCPImpl::DeregisterSendChannelRtcpStatisticsCallback(
    int video_channel, RtcpStatisticsCallback* callback) {
  LOG_F(LS_INFO) << "channel " << video_channel;
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel) {
    shared_data_->SetLastError(kViERtpRtcpInvalidChannelId);
    return -1;
  }
  vie_channel->RegisterSendChannelRtcpStatisticsCallback(NULL);
  return 0;
}

int ViERTP_RTCPImpl::RegisterReceiveChannelRtcpStatisticsCallback(
    const int video_channel,
    RtcpStatisticsCallback* callback) {
  LOG_F(LS_INFO) << "channel " << 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) {
  LOG_F(LS_INFO) << "channel " << 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) {
  LOG_F(LS_INFO) << "channel " << 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) {
  LOG_F(LS_INFO) << "channel " << 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) {
  LOG_F(LS_INFO) << "channel " << 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) {
  LOG_F(LS_INFO) << "channel " << 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) {
  LOG_F(LS_INFO) << "channel " << 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) {
  LOG_F(LS_INFO) << "channel " << 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) {
  LOG_F(LS_INFO) << "channel " << video_channel;
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel) {
    shared_data_->SetLastError(kViERtpRtcpInvalidChannelId);
    return -1;
  }
  vie_channel->RegisterSendFrameCountObserver(callback);
  return 0;
}

int ViERTP_RTCPImpl::DeregisterSendFrameCountObserver(
    int video_channel, FrameCountObserver* callback) {
  LOG_F(LS_INFO) << "channel " << video_channel;
  ViEChannelManagerScoped cs(*(shared_data_->channel_manager()));
  ViEChannel* vie_channel = cs.Channel(video_channel);
  if (!vie_channel) {
    shared_data_->SetLastError(kViERtpRtcpInvalidChannelId);
    return -1;
  }
  vie_channel->RegisterSendFrameCountObserver(NULL);
  return 0;
}
}  // namespace webrtc
