| /********** |
| 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 3 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., |
| 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| **********/ |
| // Copyright (c) 1996-2020, Live Networks, Inc. All rights reserved |
| // A demo application that receives a UDP multicast stream, replicates it (using the "StreamReplicator" class), |
| // and retransmits one replica stream to another (multicast or unicast) address & port, |
| // and writes the other replica stream to a file. |
| // |
| // main program |
| |
| #include <liveMedia.hh> |
| #include "BasicUsageEnvironment.hh" |
| #include "GroupsockHelper.hh" |
| |
| UsageEnvironment* env; |
| |
| // To receive a "source-specific multicast" (SSM) stream, uncomment this: |
| //#define USE_SSM 1 |
| |
| void startReplicaUDPSink(StreamReplicator* replicator, char const* outputAddressStr, portNumBits outputPortNum); // forward |
| void startReplicaFileSink(StreamReplicator* replicator, char const* outputFileName); // forward |
| |
| int main(int argc, char** argv) { |
| // Begin by setting up our usage environment: |
| TaskScheduler* scheduler = BasicTaskScheduler::createNew(); |
| env = BasicUsageEnvironment::createNew(*scheduler); |
| |
| // Create a 'groupsock' for the input multicast group,port: |
| char const* inputAddressStr |
| #ifdef USE_SSM |
| = "232.255.42.42"; |
| #else |
| = "239.255.42.42"; |
| #endif |
| struct in_addr inputAddress; |
| inputAddress.s_addr = our_inet_addr(inputAddressStr); |
| |
| Port const inputPort(8888); |
| unsigned char const inputTTL = 0; // we're only reading from this mcast group |
| |
| #ifdef USE_SSM |
| char* sourceAddressStr = "aaa.bbb.ccc.ddd"; |
| // replace this with the real source address |
| struct in_addr sourceFilterAddress; |
| sourceFilterAddress.s_addr = our_inet_addr(sourceAddressStr); |
| |
| Groupsock inputGroupsock(*env, inputAddress, sourceFilterAddress, inputPort); |
| #else |
| Groupsock inputGroupsock(*env, inputAddress, inputPort, inputTTL); |
| #endif |
| |
| // Then create a liveMedia 'source' object, encapsulating this groupsock: |
| FramedSource* source = BasicUDPSource::createNew(*env, &inputGroupsock); |
| |
| // And feed this into a 'stream replicator': |
| StreamReplicator* replicator = StreamReplicator::createNew(*env, source); |
| |
| // Then create a network (UDP) 'sink' object to receive a replica of the input stream, and start it. |
| // If you wish, you can duplicate this line - with different network addresses and ports - to create multiple output UDP streams: |
| startReplicaUDPSink(replicator, "239.255.43.43", 4444); |
| |
| // Then create a file 'sink' object to receive a replica of the input stream, and start it. |
| // If you wish, you can duplicate this line - with a different file name - to create multiple output files: |
| startReplicaFileSink(replicator, "test.out"); |
| |
| // Finally, enter the 'event loop' (which is where most of the 'real work' in a LIVE555-based application gets done): |
| env->taskScheduler().doEventLoop(); // does not return |
| |
| return 0; // only to prevent compiler warning |
| } |
| |
| void startReplicaUDPSink(StreamReplicator* replicator, char const* outputAddressStr, portNumBits outputPortNum) { |
| // Begin by creating an input stream from our replicator: |
| FramedSource* source = replicator->createStreamReplica(); |
| |
| // Create a 'groupsock' for the destination address and port: |
| struct in_addr outputAddress; |
| outputAddress.s_addr = our_inet_addr(outputAddressStr); |
| |
| Port const outputPort(outputPortNum); |
| unsigned char const outputTTL = 255; |
| |
| Groupsock* outputGroupsock = new Groupsock(*env, outputAddress, outputPort, outputTTL); |
| |
| // Then create a liveMedia 'sink' object, encapsulating this groupsock: |
| unsigned const maxPacketSize = 65536; // allow for large UDP packets |
| MediaSink* sink = BasicUDPSink::createNew(*env, outputGroupsock, maxPacketSize); |
| |
| // Now, start playing, feeding the sink object from the source: |
| sink->startPlaying(*source, NULL, NULL); |
| } |
| |
| void startReplicaFileSink(StreamReplicator* replicator, char const* outputFileName) { |
| // Begin by creating an input stream from our replicator: |
| FramedSource* source = replicator->createStreamReplica(); |
| |
| // Then create a 'file sink' object to receive thie replica stream: |
| MediaSink* sink = FileSink::createNew(*env, outputFileName); |
| |
| // Now, start playing, feeding the sink object from the source: |
| sink->startPlaying(*source, NULL, NULL); |
| } |