testProgs/testMP3Streamer.cpp

Go to the documentation of this file.
00001 /**********
00002 This library is free software; you can redistribute it and/or modify it under
00003 the terms of the GNU Lesser General Public License as published by the
00004 Free Software Foundation; either version 2.1 of the License, or (at your
00005 option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
00006 
00007 This library is distributed in the hope that it will be useful, but WITHOUT
00008 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00009 FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
00010 more details.
00011 
00012 You should have received a copy of the GNU Lesser General Public License
00013 along with this library; if not, write to the Free Software Foundation, Inc.,
00014 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
00015 **********/
00016 // Copyright (c) 1996-2012, Live Networks, Inc.  All rights reserved
00017 // A test program that streams a MP3 file via RTP/RTCP
00018 // main program
00019 
00020 #include "liveMedia.hh"
00021 #include "GroupsockHelper.hh"
00022 
00023 #include "BasicUsageEnvironment.hh"
00024 
00025 // To stream using 'ADUs' rather than raw MP3 frames, uncomment the following:
00026 //#define STREAM_USING_ADUS 1
00027 // To also reorder ADUs before streaming, uncomment the following:
00028 //#define INTERLEAVE_ADUS 1
00029 // (For more information about ADUs and interleaving,
00030 //  see <http://www.live555.com/rtp-mp3/>)
00031 
00032 // To stream using "source-specific multicast" (SSM), uncomment the following:
00033 //#define USE_SSM 1
00034 #ifdef USE_SSM
00035 Boolean const isSSM = True;
00036 #else
00037 Boolean const isSSM = False;
00038 #endif
00039 
00040 // To set up an internal RTSP server, uncomment the following:
00041 //#define IMPLEMENT_RTSP_SERVER 1
00042 // (Note that this RTSP server works for multicast only)
00043 
00044 #ifdef IMPLEMENT_RTSP_SERVER
00045 RTSPServer* rtspServer;
00046 #endif
00047 
00048 UsageEnvironment* env;
00049 
00050 // A structure to hold the state of the current session.
00051 // It is used in the "afterPlaying()" function to clean up the session.
00052 struct sessionState_t {
00053   FramedSource* source;
00054   RTPSink* sink;
00055   RTCPInstance* rtcpInstance;
00056   Groupsock* rtpGroupsock;
00057   Groupsock* rtcpGroupsock;
00058 } sessionState;
00059 
00060 char const* inputFileName = "test.mp3";
00061 
00062 void play(); // forward
00063 
00064 int main(int argc, char** argv) {
00065   // Begin by setting up our usage environment:
00066   TaskScheduler* scheduler = BasicTaskScheduler::createNew();
00067   env = BasicUsageEnvironment::createNew(*scheduler);
00068 
00069   // Create 'groupsocks' for RTP and RTCP:
00070   char const* destinationAddressStr
00071 #ifdef USE_SSM
00072     = "232.255.42.42";
00073 #else
00074     = "239.255.42.42";
00075   // Note: This is a multicast address.  If you wish to stream using
00076   // unicast instead, then replace this string with the unicast address
00077   // of the (single) destination.  (You may also need to make a similar
00078   // change to the receiver program.)
00079 #endif
00080   const unsigned short rtpPortNum = 6666;
00081   const unsigned short rtcpPortNum = rtpPortNum+1;
00082   const unsigned char ttl = 1; // low, in case routers don't admin scope
00083 
00084   struct in_addr destinationAddress;
00085   destinationAddress.s_addr = our_inet_addr(destinationAddressStr);
00086   const Port rtpPort(rtpPortNum);
00087   const Port rtcpPort(rtcpPortNum);
00088 
00089   sessionState.rtpGroupsock
00090     = new Groupsock(*env, destinationAddress, rtpPort, ttl);
00091   sessionState.rtcpGroupsock
00092     = new Groupsock(*env, destinationAddress, rtcpPort, ttl);
00093 #ifdef USE_SSM
00094   sessionState.rtpGroupsock->multicastSendOnly();
00095   sessionState.rtcpGroupsock->multicastSendOnly();
00096 #endif
00097 
00098   // Create a 'MP3 RTP' sink from the RTP 'groupsock':
00099 #ifdef STREAM_USING_ADUS
00100   unsigned char rtpPayloadFormat = 96; // A dynamic payload format code
00101   sessionState.sink
00102     = MP3ADURTPSink::createNew(*env, sessionState.rtpGroupsock,
00103                                rtpPayloadFormat);
00104 #else
00105   sessionState.sink
00106     = MPEG1or2AudioRTPSink::createNew(*env, sessionState.rtpGroupsock);
00107 #endif
00108 
00109   // Create (and start) a 'RTCP instance' for this RTP sink:
00110   const unsigned estimatedSessionBandwidth = 160; // in kbps; for RTCP b/w share
00111   const unsigned maxCNAMElen = 100;
00112   unsigned char CNAME[maxCNAMElen+1];
00113   gethostname((char*)CNAME, maxCNAMElen);
00114   CNAME[maxCNAMElen] = '\0'; // just in case
00115   sessionState.rtcpInstance
00116     = RTCPInstance::createNew(*env, sessionState.rtcpGroupsock,
00117                               estimatedSessionBandwidth, CNAME,
00118                               sessionState.sink, NULL /* we're a server */,
00119                               isSSM);
00120   // Note: This starts RTCP running automatically
00121 
00122 #ifdef IMPLEMENT_RTSP_SERVER
00123   rtspServer = RTSPServer::createNew(*env);
00124   // Note that this (attempts to) start a server on the default RTSP server
00125   // port: 554.  To use a different port number, add it as an extra
00126   // (optional) parameter to the "RTSPServer::createNew()" call above.
00127   if (rtspServer == NULL) {
00128     *env << "Failed to create RTSP server: " << env->getResultMsg() << "\n";
00129     exit(1);
00130   }
00131   ServerMediaSession* sms
00132     = ServerMediaSession::createNew(*env, "testStream", inputFileName,
00133                 "Session streamed by \"testMP3Streamer\"", isSSM);
00134   sms->addSubsession(PassiveServerMediaSubsession::createNew(*sessionState.sink, sessionState.rtcpInstance));
00135   rtspServer->addServerMediaSession(sms);
00136 
00137   char* url = rtspServer->rtspURL(sms);
00138   *env << "Play this stream using the URL \"" << url << "\"\n";
00139   delete[] url;
00140 #endif
00141 
00142   play();
00143 
00144   env->taskScheduler().doEventLoop(); // does not return
00145   return 0; // only to prevent compiler warning
00146 }
00147 
00148 void afterPlaying(void* clientData); // forward
00149 
00150 void play() {
00151   // Open the file as a 'MP3 file source':
00152   sessionState.source = MP3FileSource::createNew(*env, inputFileName);
00153   if (sessionState.source == NULL) {
00154     *env << "Unable to open file \"" << inputFileName
00155          << "\" as a MP3 file source\n";
00156     exit(1);
00157   }
00158 
00159 #ifdef STREAM_USING_ADUS
00160   // Add a filter that converts the source MP3s to ADUs:
00161   sessionState.source
00162     = ADUFromMP3Source::createNew(*env, sessionState.source);
00163   if (sessionState.source == NULL) {
00164     *env << "Unable to create a MP3->ADU filter for the source\n";
00165     exit(1);
00166   }
00167 
00168 #ifdef INTERLEAVE_ADUS
00169   // Add another filter that interleaves the ADUs before packetizing them:
00170   unsigned char interleaveCycle[] = {0,2,1,3}; // or choose your own order...
00171   unsigned const interleaveCycleSize
00172     = (sizeof interleaveCycle)/(sizeof (unsigned char));
00173   Interleaving interleaving(interleaveCycleSize, interleaveCycle);
00174   sessionState.source
00175     = MP3ADUinterleaver::createNew(*env, interleaving, sessionState.source);
00176   if (sessionState.source == NULL) {
00177     *env << "Unable to create an ADU interleaving filter for the source\n";
00178     exit(1);
00179   }
00180 #endif
00181 #endif
00182 
00183   // Finally, start the streaming:
00184   *env << "Beginning streaming...\n";
00185   sessionState.sink->startPlaying(*sessionState.source, afterPlaying, NULL);
00186 }
00187 
00188 
00189 void afterPlaying(void* /*clientData*/) {
00190   *env << "...done streaming\n";
00191 
00192   sessionState.sink->stopPlaying();
00193 
00194   // End this loop by closing the current source:
00195   Medium::close(sessionState.source);
00196 
00197   // And start another loop:
00198   play();
00199 }

Generated on Thu May 17 07:11:48 2012 for live by  doxygen 1.5.2