1/*
2 *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/video/video_receive_stream.h"
12
13#include <assert.h>
14#include <stdlib.h>
15
16#include <string>
17
18#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
19#include "webrtc/system_wrappers/interface/clock.h"
20#include "webrtc/system_wrappers/interface/logging.h"
21#include "webrtc/video/receive_statistics_proxy.h"
22#include "webrtc/video_engine/include/vie_base.h"
23#include "webrtc/video_engine/include/vie_capture.h"
24#include "webrtc/video_engine/include/vie_codec.h"
25#include "webrtc/video_engine/include/vie_external_codec.h"
26#include "webrtc/video_engine/include/vie_image_process.h"
27#include "webrtc/video_engine/include/vie_network.h"
28#include "webrtc/video_engine/include/vie_render.h"
29#include "webrtc/video_engine/include/vie_rtp_rtcp.h"
30#include "webrtc/video_receive_stream.h"
31
32namespace webrtc {
33namespace internal {
34
35VideoReceiveStream::VideoReceiveStream(webrtc::VideoEngine* video_engine,
36                                       const VideoReceiveStream::Config& config,
37                                       newapi::Transport* transport,
38                                       webrtc::VoiceEngine* voice_engine,
39                                       int base_channel)
40    : transport_adapter_(transport),
41      encoded_frame_proxy_(config.pre_decode_callback),
42      config_(config),
43      clock_(Clock::GetRealTimeClock()),
44      channel_(-1) {
45  video_engine_base_ = ViEBase::GetInterface(video_engine);
46  video_engine_base_->CreateReceiveChannel(channel_, base_channel);
47  assert(channel_ != -1);
48
49  rtp_rtcp_ = ViERTP_RTCP::GetInterface(video_engine);
50  assert(rtp_rtcp_ != NULL);
51
52  // TODO(pbos): This is not fine grained enough...
53  rtp_rtcp_->SetNACKStatus(channel_, config_.rtp.nack.rtp_history_ms > 0);
54  rtp_rtcp_->SetKeyFrameRequestMethod(channel_, kViEKeyFrameRequestPliRtcp);
55  SetRtcpMode(config_.rtp.rtcp_mode);
56
57  assert(config_.rtp.remote_ssrc != 0);
58  // TODO(pbos): What's an appropriate local_ssrc for receive-only streams?
59  assert(config_.rtp.local_ssrc != 0);
60  assert(config_.rtp.remote_ssrc != config_.rtp.local_ssrc);
61
62  rtp_rtcp_->SetLocalSSRC(channel_, config_.rtp.local_ssrc);
63  // TODO(pbos): Support multiple RTX, per video payload.
64  Config::Rtp::RtxMap::const_iterator it = config_.rtp.rtx.begin();
65  if (it != config_.rtp.rtx.end()) {
66    assert(it->second.ssrc != 0);
67    assert(it->second.payload_type != 0);
68
69    rtp_rtcp_->SetRemoteSSRCType(channel_, kViEStreamTypeRtx, it->second.ssrc);
70    rtp_rtcp_->SetRtxReceivePayloadType(channel_, it->second.payload_type);
71  }
72
73  rtp_rtcp_->SetRembStatus(channel_, false, config_.rtp.remb);
74
75  for (size_t i = 0; i < config_.rtp.extensions.size(); ++i) {
76    const std::string& extension = config_.rtp.extensions[i].name;
77    int id = config_.rtp.extensions[i].id;
78    if (extension == RtpExtension::kTOffset) {
79      if (rtp_rtcp_->SetReceiveTimestampOffsetStatus(channel_, true, id) != 0)
80        abort();
81    } else if (extension == RtpExtension::kAbsSendTime) {
82      if (rtp_rtcp_->SetReceiveAbsoluteSendTimeStatus(channel_, true, id) != 0)
83        abort();
84    } else {
85      abort();  // Unsupported extension.
86    }
87  }
88
89  network_ = ViENetwork::GetInterface(video_engine);
90  assert(network_ != NULL);
91
92  network_->RegisterSendTransport(channel_, transport_adapter_);
93
94  codec_ = ViECodec::GetInterface(video_engine);
95
96  if (config_.rtp.fec.ulpfec_payload_type != -1) {
97    // ULPFEC without RED doesn't make sense.
98    assert(config_.rtp.fec.red_payload_type != -1);
99    VideoCodec codec;
100    memset(&codec, 0, sizeof(codec));
101    codec.codecType = kVideoCodecULPFEC;
102    strcpy(codec.plName, "ulpfec");
103    codec.plType = config_.rtp.fec.ulpfec_payload_type;
104    if (codec_->SetReceiveCodec(channel_, codec) != 0) {
105      LOG(LS_ERROR) << "Could not set ULPFEC codec. This shouldn't happen.";
106      abort();
107    }
108  }
109  if (config_.rtp.fec.red_payload_type != -1) {
110    VideoCodec codec;
111    memset(&codec, 0, sizeof(codec));
112    codec.codecType = kVideoCodecRED;
113    strcpy(codec.plName, "red");
114    codec.plType = config_.rtp.fec.red_payload_type;
115    if (codec_->SetReceiveCodec(channel_, codec) != 0) {
116      LOG(LS_ERROR) << "Could not set RED codec. This shouldn't happen.";
117      abort();
118    }
119  }
120
121  assert(!config_.codecs.empty());
122  for (size_t i = 0; i < config_.codecs.size(); ++i) {
123    if (codec_->SetReceiveCodec(channel_, config_.codecs[i]) != 0) {
124      // TODO(pbos): Abort gracefully, this can be a runtime error.
125      //             Factor out to an Init() method.
126      abort();
127    }
128  }
129
130  stats_proxy_.reset(new ReceiveStatisticsProxy(
131      config_.rtp.local_ssrc, clock_, rtp_rtcp_, codec_, channel_));
132
133  if (rtp_rtcp_->RegisterReceiveChannelRtcpStatisticsCallback(
134          channel_, stats_proxy_.get()) != 0)
135    abort();
136
137  if (rtp_rtcp_->RegisterReceiveChannelRtpStatisticsCallback(
138          channel_, stats_proxy_.get()) != 0)
139    abort();
140
141  if (codec_->RegisterDecoderObserver(channel_, *stats_proxy_) != 0)
142    abort();
143
144  external_codec_ = ViEExternalCodec::GetInterface(video_engine);
145  for (size_t i = 0; i < config_.external_decoders.size(); ++i) {
146    const ExternalVideoDecoder& decoder = config_.external_decoders[i];
147    if (external_codec_->RegisterExternalReceiveCodec(
148            channel_,
149            decoder.payload_type,
150            decoder.decoder,
151            decoder.renderer,
152            decoder.expected_delay_ms) != 0) {
153      // TODO(pbos): Abort gracefully? Can this be a runtime error?
154      abort();
155    }
156  }
157
158  render_ = ViERender::GetInterface(video_engine);
159  assert(render_ != NULL);
160
161  render_->AddRenderCallback(channel_, this);
162
163  if (voice_engine) {
164    video_engine_base_->SetVoiceEngine(voice_engine);
165    video_engine_base_->ConnectAudioChannel(channel_, config_.audio_channel_id);
166  }
167
168  image_process_ = ViEImageProcess::GetInterface(video_engine);
169  if (config.pre_decode_callback) {
170    image_process_->RegisterPreDecodeImageCallback(channel_,
171                                                   &encoded_frame_proxy_);
172  }
173  image_process_->RegisterPreRenderCallback(channel_, this);
174
175  if (config.rtp.rtcp_xr.receiver_reference_time_report) {
176    rtp_rtcp_->SetRtcpXrRrtrStatus(channel_, true);
177  }
178}
179
180VideoReceiveStream::~VideoReceiveStream() {
181  image_process_->DeRegisterPreRenderCallback(channel_);
182  image_process_->DeRegisterPreDecodeCallback(channel_);
183
184  render_->RemoveRenderer(channel_);
185
186  for (size_t i = 0; i < config_.external_decoders.size(); ++i) {
187    external_codec_->DeRegisterExternalReceiveCodec(
188        channel_, config_.external_decoders[i].payload_type);
189  }
190
191  network_->DeregisterSendTransport(channel_);
192
193  video_engine_base_->SetVoiceEngine(NULL);
194  image_process_->Release();
195  video_engine_base_->Release();
196  external_codec_->Release();
197  codec_->DeregisterDecoderObserver(channel_);
198  rtp_rtcp_->DeregisterReceiveChannelRtpStatisticsCallback(channel_,
199                                                           stats_proxy_.get());
200  rtp_rtcp_->DeregisterReceiveChannelRtcpStatisticsCallback(channel_,
201                                                            stats_proxy_.get());
202  codec_->Release();
203  network_->Release();
204  render_->Release();
205  rtp_rtcp_->Release();
206}
207
208void VideoReceiveStream::Start() {
209  transport_adapter_.Enable();
210  if (render_->StartRender(channel_) != 0)
211    abort();
212  if (video_engine_base_->StartReceive(channel_) != 0)
213    abort();
214}
215
216void VideoReceiveStream::Stop() {
217  if (render_->StopRender(channel_) != 0)
218    abort();
219  if (video_engine_base_->StopReceive(channel_) != 0)
220    abort();
221  transport_adapter_.Disable();
222}
223
224VideoReceiveStream::Stats VideoReceiveStream::GetStats() const {
225  return stats_proxy_->GetStats();
226}
227
228void VideoReceiveStream::GetCurrentReceiveCodec(VideoCodec* receive_codec) {
229  // TODO(pbos): Implement
230}
231
232bool VideoReceiveStream::DeliverRtcp(const uint8_t* packet, size_t length) {
233  return network_->ReceivedRTCPPacket(
234             channel_, packet, static_cast<int>(length)) == 0;
235}
236
237bool VideoReceiveStream::DeliverRtp(const uint8_t* packet, size_t length) {
238  return network_->ReceivedRTPPacket(
239             channel_, packet, static_cast<int>(length), PacketTime()) == 0;
240}
241
242void VideoReceiveStream::FrameCallback(I420VideoFrame* video_frame) {
243  stats_proxy_->OnDecodedFrame();
244
245  if (config_.pre_render_callback)
246    config_.pre_render_callback->FrameCallback(video_frame);
247}
248
249int32_t VideoReceiveStream::RenderFrame(const uint32_t stream_id,
250                                        I420VideoFrame& video_frame) {
251  if (config_.renderer != NULL)
252    config_.renderer->RenderFrame(
253        video_frame,
254        video_frame.render_time_ms() - clock_->TimeInMilliseconds());
255
256  stats_proxy_->OnRenderedFrame();
257
258  return 0;
259}
260
261void VideoReceiveStream::SignalNetworkState(Call::NetworkState state) {
262  if (state == Call::kNetworkUp)
263    SetRtcpMode(config_.rtp.rtcp_mode);
264  network_->SetNetworkTransmissionState(channel_, state == Call::kNetworkUp);
265  if (state == Call::kNetworkDown)
266    rtp_rtcp_->SetRTCPStatus(channel_, kRtcpNone);
267}
268
269void VideoReceiveStream::SetRtcpMode(newapi::RtcpMode mode) {
270  switch (mode) {
271    case newapi::kRtcpCompound:
272      rtp_rtcp_->SetRTCPStatus(channel_, kRtcpCompound_RFC4585);
273      break;
274    case newapi::kRtcpReducedSize:
275      rtp_rtcp_->SetRTCPStatus(channel_, kRtcpNonCompound_RFC5506);
276      break;
277  }
278}
279}  // namespace internal
280}  // namespace webrtc
281