1/*
2 *  Copyright (c) 2012 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 <iostream>  // NOLINT
12
13#include "webrtc/common_types.h"
14#include "webrtc/video_engine/include/vie_base.h"
15#include "webrtc/video_engine/include/vie_capture.h"
16#include "webrtc/video_engine/include/vie_codec.h"
17#include "webrtc/video_engine/include/vie_network.h"
18#include "webrtc/video_engine/include/vie_render.h"
19#include "webrtc/video_engine/include/vie_rtp_rtcp.h"
20#include "webrtc/video_engine/test/auto_test/interface/vie_autotest.h"
21#include "webrtc/video_engine/test/auto_test/interface/vie_autotest_defines.h"
22#include "webrtc/video_engine/test/libvietest/include/tb_external_transport.h"
23#include "webrtc/voice_engine/include/voe_base.h"
24
25enum RelayMode {
26  kRelayOneStream = 1,
27  kRelayAllStreams = 2
28};
29
30#define VCM_RED_PAYLOAD_TYPE        96
31#define VCM_ULPFEC_PAYLOAD_TYPE     97
32
33const int kNumStreams = 3;
34
35void InitialSingleStreamSettings(webrtc::VideoCodec* video_codec) {
36  video_codec->numberOfSimulcastStreams = 0;
37  video_codec->width = 1200;
38  video_codec->height = 800;
39}
40
41void SetSimulcastSettings(webrtc::VideoCodec* video_codec) {
42  video_codec->width = 1280;
43  video_codec->height = 720;
44
45  // Simulcast settings.
46  video_codec->numberOfSimulcastStreams = kNumStreams;
47  video_codec->simulcastStream[0].width = 320;
48  video_codec->simulcastStream[0].height = 180;
49  video_codec->simulcastStream[0].numberOfTemporalLayers = 0;
50  video_codec->simulcastStream[0].maxBitrate = 100;
51  video_codec->simulcastStream[0].targetBitrate = 100;
52  video_codec->simulcastStream[0].minBitrate = 0;
53  video_codec->simulcastStream[0].qpMax = video_codec->qpMax;
54
55  video_codec->simulcastStream[1].width = 640;
56  video_codec->simulcastStream[1].height = 360;
57  video_codec->simulcastStream[1].numberOfTemporalLayers = 0;
58  video_codec->simulcastStream[1].maxBitrate = 500;
59  video_codec->simulcastStream[1].targetBitrate = 500;
60  video_codec->simulcastStream[1].minBitrate = 200;
61  video_codec->simulcastStream[1].qpMax = video_codec->qpMax;
62
63  video_codec->simulcastStream[2].width = 1280;
64  video_codec->simulcastStream[2].height = 720;
65  video_codec->simulcastStream[2].numberOfTemporalLayers = 0;
66  video_codec->simulcastStream[2].maxBitrate = 1200;
67  video_codec->simulcastStream[2].targetBitrate = 1200;
68  video_codec->simulcastStream[2].minBitrate = 900;
69  video_codec->simulcastStream[2].qpMax = video_codec->qpMax;
70}
71
72void RuntimeSingleStreamSettings(webrtc::VideoCodec* video_codec) {
73  SetSimulcastSettings(video_codec);
74  video_codec->width = 1200;
75  video_codec->height = 800;
76  video_codec->numberOfSimulcastStreams = kNumStreams;
77  video_codec->simulcastStream[0].maxBitrate = 0;
78  video_codec->simulcastStream[0].targetBitrate = 0;
79  video_codec->simulcastStream[0].minBitrate = 0;
80  video_codec->simulcastStream[1].maxBitrate = 0;
81  video_codec->simulcastStream[1].targetBitrate = 0;
82  video_codec->simulcastStream[1].minBitrate = 0;
83  video_codec->simulcastStream[2].maxBitrate = 0;
84  video_codec->simulcastStream[2].targetBitrate = 0;
85  video_codec->simulcastStream[2].minBitrate = 0;
86}
87
88int VideoEngineSimulcastTest(void* window1, void* window2) {
89  // *******************************************************
90  //  Begin create/initialize Video Engine for testing
91  // *******************************************************
92
93  int error = 0;
94  int receive_channels[kNumStreams];
95
96  // Create a VideoEngine instance.
97  webrtc::VideoEngine* video_engine = NULL;
98  video_engine = webrtc::VideoEngine::Create();
99  if (video_engine == NULL) {
100    printf("ERROR in VideoEngine::Create\n");
101    return -1;
102  }
103
104  error = video_engine->SetTraceFilter(webrtc::kTraceAll);
105  if (error == -1) {
106    printf("ERROR in VideoEngine::SetTraceLevel\n");
107    return -1;
108  }
109
110  std::string trace_file =
111    ViETest::GetResultOutputPath() + "ViESimulcast_trace.txt";
112  error = video_engine->SetTraceFile(trace_file.c_str());
113  if (error == -1) {
114    printf("ERROR in VideoEngine::SetTraceFile\n");
115    return -1;
116  }
117
118  // Init VideoEngine and create a channel.
119  webrtc::ViEBase* vie_base = webrtc::ViEBase::GetInterface(video_engine);
120  if (vie_base == NULL) {
121    printf("ERROR in ViEBase::GetInterface\n");
122    return -1;
123  }
124
125  error = vie_base->Init();
126  if (error == -1) {
127    printf("ERROR in ViEBase::Init\n");
128    return -1;
129  }
130
131  RelayMode relay_mode = kRelayOneStream;
132  printf("Select relay mode:\n");
133  printf("\t1. Relay one stream\n");
134  printf("\t2. Relay all streams\n");
135  if (scanf("%d", reinterpret_cast<int*>(&relay_mode)) != 1) {
136    printf("Error in scanf()\n");
137    return -1;
138  }
139  getchar();
140
141  webrtc::ViERTP_RTCP* vie_rtp_rtcp =
142      webrtc::ViERTP_RTCP::GetInterface(video_engine);
143  if (vie_rtp_rtcp == NULL) {
144    printf("ERROR in ViERTP_RTCP::GetInterface\n");
145    return -1;
146  }
147
148  int video_channel = -1;
149  error = vie_base->CreateChannel(video_channel);
150  if (error == -1) {
151    printf("ERROR in ViEBase::CreateChannel\n");
152    return -1;
153  }
154
155  for (int i = 0; i < kNumStreams; ++i) {
156    receive_channels[i] = -1;
157    error = vie_base->CreateReceiveChannel(receive_channels[i], video_channel);
158    if (error == -1) {
159      printf("ERROR in ViEBase::CreateChannel\n");
160      return -1;
161    }
162  }
163
164  // List available capture devices, allocate and connect.
165  webrtc::ViECapture* vie_capture =
166      webrtc::ViECapture::GetInterface(video_engine);
167  if (vie_base == NULL) {
168    printf("ERROR in ViECapture::GetInterface\n");
169    return -1;
170  }
171
172  const unsigned int KMaxDeviceNameLength = 128;
173  const unsigned int KMaxUniqueIdLength = 256;
174  char device_name[KMaxDeviceNameLength];
175  memset(device_name, 0, KMaxDeviceNameLength);
176  char unique_id[KMaxUniqueIdLength];
177  memset(unique_id, 0, KMaxUniqueIdLength);
178
179  printf("Available capture devices:\n");
180  int capture_idx = 0;
181  for (capture_idx = 0; capture_idx < vie_capture->NumberOfCaptureDevices();
182       capture_idx++) {
183    memset(device_name, 0, KMaxDeviceNameLength);
184    memset(unique_id, 0, KMaxUniqueIdLength);
185
186    error = vie_capture->GetCaptureDevice(capture_idx, device_name,
187                                          KMaxDeviceNameLength, unique_id,
188                                          KMaxUniqueIdLength);
189    if (error == -1) {
190      printf("ERROR in ViECapture::GetCaptureDevice\n");
191      return -1;
192    }
193    printf("\t %d. %s\n", capture_idx + 1, device_name);
194  }
195  printf("\nChoose capture device: ");
196#ifdef WEBRTC_ANDROID
197  capture_idx = 0;
198  printf("0\n");
199#else
200  if (scanf("%d", &capture_idx) != 1) {
201    printf("Error in scanf()\n");
202    return -1;
203  }
204  getchar();
205  // Compensate for idx start at 1.
206  capture_idx = capture_idx - 1;
207#endif
208  error = vie_capture->GetCaptureDevice(capture_idx, device_name,
209                                        KMaxDeviceNameLength, unique_id,
210                                        KMaxUniqueIdLength);
211  if (error == -1) {
212    printf("ERROR in ViECapture::GetCaptureDevice\n");
213    return -1;
214  }
215
216  int capture_id = 0;
217  error = vie_capture->AllocateCaptureDevice(unique_id, KMaxUniqueIdLength,
218                                             capture_id);
219  if (error == -1) {
220    printf("ERROR in ViECapture::AllocateCaptureDevice\n");
221    return -1;
222  }
223
224  error = vie_capture->ConnectCaptureDevice(capture_id, video_channel);
225  if (error == -1) {
226    printf("ERROR in ViECapture::ConnectCaptureDevice\n");
227    return -1;
228  }
229
230  error = vie_capture->StartCapture(capture_id);
231  if (error == -1) {
232    printf("ERROR in ViECapture::StartCapture\n");
233    return -1;
234  }
235
236  // RTP/RTCP settings.
237  error = vie_rtp_rtcp->SetRTCPStatus(video_channel,
238                                      webrtc::kRtcpCompound_RFC4585);
239  if (error == -1) {
240    printf("ERROR in ViERTP_RTCP::SetRTCPStatus\n");
241    return -1;
242  }
243
244  vie_rtp_rtcp->SetRembStatus(video_channel, true, false);
245  if (error == -1) {
246    printf("ERROR in ViERTP_RTCP::SetRTCPStatus\n");
247    return -1;
248  }
249
250  error = vie_rtp_rtcp->SetKeyFrameRequestMethod(
251            video_channel, webrtc::kViEKeyFrameRequestPliRtcp);
252  if (error == -1) {
253    printf("ERROR in ViERTP_RTCP::SetKeyFrameRequestMethod\n");
254    return -1;
255  }
256
257  for (int i = 0; i < kNumStreams; ++i) {
258    error = vie_rtp_rtcp->SetRTCPStatus(receive_channels[i],
259                                        webrtc::kRtcpCompound_RFC4585);
260    if (error == -1) {
261      printf("ERROR in ViERTP_RTCP::SetRTCPStatus\n");
262      return -1;
263    }
264
265    vie_rtp_rtcp->SetRembStatus(receive_channels[i], false, true);
266    if (error == -1) {
267      printf("ERROR in ViERTP_RTCP::SetRTCPStatus\n");
268      return -1;
269    }
270
271    error = vie_rtp_rtcp->SetKeyFrameRequestMethod(
272        receive_channels[i], webrtc::kViEKeyFrameRequestPliRtcp);
273    if (error == -1) {
274      printf("ERROR in ViERTP_RTCP::SetKeyFrameRequestMethod\n");
275      return -1;
276    }
277  }
278
279  // Set up rendering.
280  webrtc::ViERender* vie_render = webrtc::ViERender::GetInterface(video_engine);
281  if (vie_render == NULL) {
282    printf("ERROR in ViERender::GetInterface\n");
283    return -1;
284  }
285
286  error = vie_render->AddRenderer(capture_id, window1, 0, 0.0, 0.0, 1.0, 1.0);
287  if (error == -1) {
288    printf("ERROR in ViERender::AddRenderer\n");
289    return -1;
290  }
291
292  error = vie_render->StartRender(capture_id);
293  if (error == -1) {
294    printf("ERROR in ViERender::StartRender\n");
295    return -1;
296  }
297
298  // Only rendering the thumbnail.
299  int channel_to_render = video_channel;
300  if (relay_mode == kRelayAllStreams) {
301    channel_to_render = receive_channels[0];
302  }
303  error = vie_render->AddRenderer(channel_to_render, window2, 1, 0.0, 0.0, 1.0,
304                                  1.0);
305  if (error == -1) {
306    printf("ERROR in ViERender::AddRenderer\n");
307    return -1;
308  }
309
310  error = vie_render->StartRender(channel_to_render);
311  if (error == -1) {
312    printf("ERROR in ViERender::StartRender\n");
313    return -1;
314  }
315
316  // Setup codecs.
317  webrtc::ViECodec* vie_codec = webrtc::ViECodec::GetInterface(video_engine);
318  if (vie_codec == NULL) {
319    printf("ERROR in ViECodec::GetInterface\n");
320    return -1;
321  }
322
323  // Check available codecs and prepare receive codecs.
324  printf("\nAvailable codecs:\n");
325  webrtc::VideoCodec video_codec;
326  memset(&video_codec, 0, sizeof(webrtc::VideoCodec));
327  int codec_idx = 0;
328  for (codec_idx = 0; codec_idx < vie_codec->NumberOfCodecs(); codec_idx++) {
329    error = vie_codec->GetCodec(codec_idx, video_codec);
330    if (error == -1) {
331      printf("ERROR in ViECodec::GetCodec\n");
332      return -1;
333    }
334    // Try to keep the test frame size small when I420.
335    if (video_codec.codecType != webrtc::kVideoCodecVP8) {
336      continue;
337    }
338    for (int i = 0; i < kNumStreams; ++i) {
339      error = vie_codec->SetReceiveCodec(receive_channels[i], video_codec);
340      if (error == -1) {
341        printf("ERROR in ViECodec::SetReceiveCodec\n");
342        return -1;
343      }
344    }
345    if (video_codec.codecType != webrtc::kVideoCodecRED &&
346        video_codec.codecType != webrtc::kVideoCodecULPFEC) {
347      printf("\t %d. %s\n", codec_idx + 1, video_codec.plName);
348    }
349    break;
350  }
351  error = vie_codec->GetCodec(codec_idx, video_codec);
352  if (error == -1) {
353    printf("ERROR in ViECodec::GetCodec\n");
354    return -1;
355  }
356
357  bool simulcast_mode = true;
358  int num_streams = 1;
359  // Set spatial resolution option.
360  if (simulcast_mode) {
361    SetSimulcastSettings(&video_codec);
362    num_streams = video_codec.numberOfSimulcastStreams;
363  } else {
364    InitialSingleStreamSettings(&video_codec);
365    num_streams = 1;
366  }
367
368  // Set start bit rate.
369  std::string str;
370  std::cout << std::endl;
371  std::cout << "Choose start rate (in kbps). Press enter for default:  ";
372  std::getline(std::cin, str);
373  int start_rate = atoi(str.c_str());
374  if (start_rate != 0) {
375    video_codec.startBitrate = start_rate;
376  }
377
378  error = vie_codec->SetSendCodec(video_channel, video_codec);
379  if (error == -1) {
380    printf("ERROR in ViECodec::SetSendCodec\n");
381    return -1;
382  }
383
384  // Address settings.
385  webrtc::ViENetwork* vie_network =
386      webrtc::ViENetwork::GetInterface(video_engine);
387  if (vie_network == NULL) {
388    printf("ERROR in ViENetwork::GetInterface\n");
389    return -1;
390  }
391
392  TbExternalTransport::SsrcChannelMap ssrc_channel_map;
393  for (int idx = 0; idx < num_streams; idx++) {
394    error = vie_rtp_rtcp->SetLocalSSRC(video_channel, idx + 1,  // SSRC
395                                       webrtc::kViEStreamTypeNormal, idx);
396    ssrc_channel_map[idx + 1] = receive_channels[idx];
397    if (error == -1) {
398      printf("ERROR in ViERTP_RTCP::SetLocalSSRC(idx:%d)\n",
399             idx);
400      return -1;
401    }
402  }
403
404  TbExternalTransport::SsrcChannelMap* channel_map = &ssrc_channel_map;
405  if (relay_mode == kRelayOneStream) {
406    channel_map = NULL;
407  }
408
409  // Setting External transport.
410  TbExternalTransport ext_transport(*vie_network, video_channel, channel_map);
411
412  error = vie_network->RegisterSendTransport(video_channel, ext_transport);
413  if (error == -1) {
414    printf("ERROR in ViECodec::RegisterSendTransport \n");
415    return -1;
416  }
417
418  for (int i = 0; i < kNumStreams; ++i) {
419    error = vie_network->RegisterSendTransport(receive_channels[i],
420                                               ext_transport);
421    if (error == -1) {
422      printf("ERROR in ViECodec::RegisterSendTransport \n");
423      return -1;
424    }
425  }
426
427  // Set network one-way delay value.
428  // 10 ms one-way delay.
429  NetworkParameters network;
430  network.loss_model = kUniformLoss;
431  network.mean_one_way_delay = 10;
432  ext_transport.SetNetworkParameters(network);
433
434  if (relay_mode == kRelayOneStream) {
435    ext_transport.SetSSRCFilter(num_streams);
436  }
437
438  error = vie_base->StartSend(video_channel);
439  if (error == -1) {
440    printf("ERROR in ViENetwork::StartSend\n");
441    return -1;
442  }
443  error = vie_base->StartReceive(video_channel);
444  if (error == -1) {
445    printf("ERROR in ViENetwork::StartReceive\n");
446    return -1;
447  }
448
449  for (int i = 0; i < kNumStreams; ++i) {
450    error = vie_base->StartReceive(receive_channels[i]);
451    if (error == -1) {
452      printf("ERROR in ViENetwork::StartReceive\n");
453      return -1;
454    }
455  }
456
457  // Create a receive channel to verify that it doesn't mess up toggling
458  // between single stream and simulcast.
459  int video_channel2 = -1;
460  error = vie_base->CreateReceiveChannel(video_channel2, video_channel);
461  if (error == -1) {
462    printf("ERROR in ViEBase::CreateReceiveChannel\n");
463    return -1;
464  }
465
466  // *******************************************************
467  //  Engine started
468  // *******************************************************
469
470  printf("\nSimulcast call started\n\n");
471  do {
472    printf("Enter new SSRC filter 1,2 or 3\n");
473    printf("... or 0 to switch between simulcast and a single stream\n");
474    printf("Press enter to stop...");
475    str.clear();
476    std::getline(std::cin, str);
477    if (!str.empty()) {
478      int ssrc = atoi(str.c_str());
479      if (ssrc == 0) {
480        // Toggle between simulcast and a single stream with different
481        // resolution.
482        if (simulcast_mode) {
483          RuntimeSingleStreamSettings(&video_codec);
484          num_streams = 1;
485          printf("Disabling simulcast\n");
486        } else {
487          SetSimulcastSettings(&video_codec);
488          num_streams = video_codec.numberOfSimulcastStreams;
489          printf("Enabling simulcast\n");
490        }
491        simulcast_mode = !simulcast_mode;
492        if (vie_codec->SetSendCodec(video_channel, video_codec) != 0) {
493          printf("ERROR switching between simulcast and single stream\n");
494          return -1;
495        }
496        for (int idx = 0; idx < num_streams; idx++) {
497          error = vie_rtp_rtcp->SetLocalSSRC(video_channel, idx + 1,  // SSRC
498                                             webrtc::kViEStreamTypeNormal, idx);
499          if (error == -1) {
500            printf("ERROR in ViERTP_RTCP::SetLocalSSRC(idx:%d)\n", idx);
501            return -1;
502          }
503        }
504        if (relay_mode == kRelayOneStream) {
505          ext_transport.SetSSRCFilter(num_streams);
506        }
507      } else if (ssrc > 0 && ssrc < 4) {
508        if (relay_mode == kRelayOneStream) {
509          ext_transport.SetSSRCFilter(ssrc);
510        }
511      } else {
512        printf("Invalid SSRC\n");
513      }
514    } else {
515      break;
516    }
517  } while (true);
518
519  // *******************************************************
520  //  Testing finished. Tear down Video Engine
521  // *******************************************************
522  error = vie_base->DeleteChannel(video_channel2);
523  if (error == -1) {
524    printf("ERROR in ViEBase::DeleteChannel\n");
525    return -1;
526  }
527
528  for (int i = 0; i < kNumStreams; ++i) {
529    error = vie_base->StopReceive(receive_channels[i]);
530    if (error == -1) {
531      printf("ERROR in ViEBase::StopReceive\n");
532      return -1;
533    }
534  }
535
536  error = vie_base->StopReceive(video_channel);
537  if (error == -1) {
538    printf("ERROR in ViEBase::StopReceive\n");
539    return -1;
540  }
541
542  error = vie_base->StopSend(video_channel);
543  if (error == -1) {
544    printf("ERROR in ViEBase::StopSend\n");
545    return -1;
546  }
547
548  error = vie_render->StopRender(capture_id);
549  if (error == -1) {
550    printf("ERROR in ViERender::StopRender\n");
551    return -1;
552  }
553
554  error = vie_render->RemoveRenderer(capture_id);
555  if (error == -1) {
556    printf("ERROR in ViERender::RemoveRenderer\n");
557    return -1;
558  }
559
560  error = vie_render->StopRender(channel_to_render);
561  if (error == -1) {
562    printf("ERROR in ViERender::StopRender\n");
563    return -1;
564  }
565
566  error = vie_render->RemoveRenderer(channel_to_render);
567  if (error == -1) {
568    printf("ERROR in ViERender::RemoveRenderer\n");
569    return -1;
570  }
571
572  error = vie_capture->StopCapture(capture_id);
573  if (error == -1) {
574    printf("ERROR in ViECapture::StopCapture\n");
575    return -1;
576  }
577
578  error = vie_capture->DisconnectCaptureDevice(video_channel);
579  if (error == -1) {
580    printf("ERROR in ViECapture::DisconnectCaptureDevice\n");
581    return -1;
582  }
583
584  error = vie_capture->ReleaseCaptureDevice(capture_id);
585  if (error == -1) {
586    printf("ERROR in ViECapture::ReleaseCaptureDevice\n");
587    return -1;
588  }
589
590  for (int i = 0; i < kNumStreams; ++i) {
591    error = vie_base->DeleteChannel(receive_channels[i]);
592    if (error == -1) {
593      printf("ERROR in ViEBase::DeleteChannel\n");
594      return -1;
595    }
596  }
597
598  error = vie_base->DeleteChannel(video_channel);
599  if (error == -1) {
600    printf("ERROR in ViEBase::DeleteChannel\n");
601    return -1;
602  }
603
604  int remaining_interfaces = 0;
605  remaining_interfaces = vie_codec->Release();
606  remaining_interfaces += vie_capture->Release();
607  remaining_interfaces += vie_rtp_rtcp->Release();
608  remaining_interfaces += vie_render->Release();
609  remaining_interfaces += vie_network->Release();
610  remaining_interfaces += vie_base->Release();
611  if (remaining_interfaces > 0) {
612    printf("ERROR: Could not release all interfaces\n");
613    return -1;
614  }
615
616  bool deleted = webrtc::VideoEngine::Delete(video_engine);
617  if (deleted == false) {
618    printf("ERROR in VideoEngine::Delete\n");
619    return -1;
620  }
621  return 0;
622}
623
624int ViEAutoTest::ViESimulcastCall() {
625  ViETest::Log(" ");
626  ViETest::Log("========================================");
627  ViETest::Log(" ViE Autotest Simulcast Call\n");
628
629  if (VideoEngineSimulcastTest(_window1, _window2) == 0) {
630    ViETest::Log(" ");
631    ViETest::Log(" ViE Autotest Simulcast Call Done");
632    ViETest::Log("========================================");
633    ViETest::Log(" ");
634
635    return 0;
636  }
637  ViETest::Log(" ");
638  ViETest::Log(" ViE Autotest Simulcast Call Failed");
639  ViETest::Log("========================================");
640  ViETest::Log(" ");
641  return 1;
642}
643