/**********
This library is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the
Free Software Foundation; either version 2.1 of the License, or (at your
option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)

This library is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
more details.

You should have received a copy of the GNU Lesser General Public License
along with this library; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
**********/
// Copyright (c) 1996-2007, Live Networks, Inc.  All rights reserved
// A test program that receives a UDP multicast stream
// and retransmits it to another (multicast or unicast) address & port
// main program

// testStreamDup - duplicate incoming stream to several output streams

#include <liveMedia.hh>
#include "BasicUsageEnvironment.hh"
#include "GroupsockHelper.hh"

//#define USE_SSM 1        // To receive a "source-specific multicast" (SSM) stream, uncomment this:
#define   inputTTL                          0            // we're only reading from this mcast group
#define   outputTTL                       255
#define   rtpPayloadFormatAudio            97
#define   rtpPayloadFormatVideo            96
#define   rtpTimestampFrequencyAudio    44100
#define   rtpTimestampFrequencyVideo    90000
#define   sizeLength                       13
#define   indexLength                       3
#define   indexDeltaLength                  3
#define   maxPacketSize                 65536           // allow for large UDP packets
#define   mediumName                "//AUDIO"
#define   mode                      "AAC-hbr"

#define   sdpMediaTypeString          "audio"
#define   mpeg4Mode                 "AAC-hbr"    //
#define   configString                 "1210"     // has to contain the audio specific config? rfc3640
#define   sprop_parameter_sets_str     "Z0IAHqtAwEt/4ACAAGIAHoxQAvuz0Qg=,aM48gA=="


UsageEnvironment* env;


int main(int argc, char** argv)
  {

	if (argc < 10)
    {
		fprintf(stderr, "Usage:\n\n");
		fprintf(stderr, "testStreamDup.exe in-ipadr in-port-audio in-port-video out-ipadr1 out-port-audio1 out-port-video1 out-ipadr2 out-port-audio2 out-port-video2\n\n");
		fprintf(stderr, "Example: testStreamDup 10.10.10.10 1234 1236 10.10.10.10 1238 1240 10.10.10.11 1242 1244\n");
		exit(1);
	  } ;

   struct in_addr inputAddress, outputAddress, outputAddress2 ;
   char*          inputAddressStr     = argv[1];
   char*          outputAddressStr    = argv[4];
   char*          outputAddressStr2    = argv[7];
   char*          SDP_String ;
   const WORD     rtpInPortNumAudio   = atoi(argv[2]);
   const WORD     rtcpInPortNumAudio  = rtpInPortNumAudio+1;
   const WORD     rtpInPortNumVideo   = atoi(argv[3]);
   const WORD     rtcpInPortNumVideo  = rtpInPortNumVideo+1;
   const WORD     rtpOutPortNumAudio  = atoi(argv[5]);
   const WORD     rtcpOutPortNumAudio = rtpOutPortNumAudio+1;
   const WORD     rtpOutPortNumVideo  = atoi(argv[6]);
   const WORD     rtcpOutPortNumVideo = rtpOutPortNumVideo+1;
   const WORD     rtpOutPortNumAudio2  = atoi(argv[8]);
   const WORD     rtcpOutPortNumAudio2 = rtpOutPortNumAudio+1;
   const WORD     rtpOutPortNumVideo2  = atoi(argv[9]);
   const WORD     rtcpOutPortNumVideo2 = rtpOutPortNumVideo+1;
   UINT           ProfileLevelID = 0 ;


   // Begin by setting up our usage environment:
  TaskScheduler* scheduler = BasicTaskScheduler::createNew();
  env                      = BasicUsageEnvironment::createNew(*scheduler);
  SDP_String               = new char[ strlen(sprop_parameter_sets_str)+1 ] ;
  strcpy( SDP_String, sprop_parameter_sets_str) ;

  inputAddress.s_addr = our_inet_addr(inputAddressStr);
  Port const inputPortAudio(rtpInPortNumAudio);
  Port const inputPortVideo(rtpInPortNumVideo);

  Groupsock inputGroupsockAudio(*env, inputAddress, inputPortAudio, inputTTL);
  Groupsock inputGroupsockVideo(*env, inputAddress, inputPortVideo, inputTTL);
  //#endif

  // Then create a liveMedia 'source' object, encapsulating this groupsock:
  FramedSource* sourceAudio = MPEG4GenericRTPSource::createNew( *env, &inputGroupsockAudio, rtpPayloadFormatAudio, rtpTimestampFrequencyAudio,
				                                                                  mediumName, mode, sizeLength, indexLength, indexDeltaLength);
//  FramedSource* sourceVideo = H264VideoRTPSource::createNew( *env, &inputGroupsockVideo, rtpPayloadFormatVideo, rtpTimestampFrequencyVideo);

  StreamDup* dupSourceAudio = StreamDup::createNew(*env, sourceAudio);
//  StreamDup* dupSourceVideo = StreamDup::createNew(*env, sourceVideo);

  FramedSource* sa1 = dupSourceAudio->registerDuplicateStream();
//  FramedSource* sv1 = dupSourceVideo->registerDuplicateStream();
  FramedSource* sa2 = dupSourceAudio->registerDuplicateStream();
//  FramedSource* sv2 = dupSourceVideo->registerDuplicateStream();


  // Create 'groupsock' for dest. address/port. Could be different multi or unicast adresses, but *not* the same multicast address as input.
  outputAddress.s_addr = our_inet_addr(outputAddressStr);
  outputAddress2.s_addr = our_inet_addr(outputAddressStr2);
  Port const outputPortAudio(rtpOutPortNumAudio);
  Port const outputPortVideo(rtpOutPortNumVideo);
  Port const outputPortAudio2(rtpOutPortNumAudio2);
  Port const outputPortVideo2(rtpOutPortNumVideo2);
  Groupsock outputGroupsockAudio(*env, outputAddress, outputPortAudio, outputTTL);
  Groupsock outputGroupsockVideo(*env, outputAddress, outputPortVideo, outputTTL);
  Groupsock outputGroupsockAudio2(*env, outputAddress2, outputPortAudio2, outputTTL);
  Groupsock outputGroupsockVideo2(*env, outputAddress2, outputPortVideo2, outputTTL);

  // Then create a liveMedia 'sink' object, encapsulating this groupsock:
  MediaSink* sinkAudio1 = MPEG4GenericRTPSink::createNew( *env, &outputGroupsockAudio, rtpPayloadFormatAudio,
                                                          rtpTimestampFrequencyAudio, sdpMediaTypeString, mpeg4Mode, configString, 2);
//  MediaSink* sinkVideo1 = H264VideoRTPSink::createNew( *env, &outputGroupsockVideo, rtpPayloadFormatVideo, ProfileLevelID, SDP_String);

  MediaSink* sinkAudio2 = MPEG4GenericRTPSink::createNew( *env, &outputGroupsockAudio2, rtpPayloadFormatAudio,
                                                          rtpTimestampFrequencyAudio, sdpMediaTypeString, mpeg4Mode, configString, 2);
//  MediaSink* sinkVideo2 = H264VideoRTPSink::createNew( *env, &outputGroupsockVideo2, rtpPayloadFormatVideo, ProfileLevelID, SDP_String);

  //______________ Now, start playing, feeding the sink object from the source: ______________________________________________
  sinkAudio1->startPlaying(*sa1,   NULL, NULL);
  sinkAudio2->startPlaying(*sa2,   NULL, NULL);

//  sinkVideo1->startPlaying(*sv1, NULL, NULL);
//  sinkVideo2->startPlaying(*sv2, NULL, NULL);

  env->taskScheduler().doEventLoop();                      // does not return

  return 0 ;                              // only to prevent compiler warning
  }
