1 // Copyright (C) 1999-2005 Open Source Telecom Corporation.
2 //
3 // This program is free software; you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation; either version 2 of the License, or
6 // (at your option) any later version.
7 //
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 //
17 // As a special exception, you may use this file as part of a free software
18 // library without restriction. Specifically, if other files instantiate
19 // templates or use macros or inline functions from this file, or you compile
20 // this file and link it with other files to produce an executable, this
21 // file does not by itself cause the resulting executable to be covered by
22 // the GNU General Public License. This exception does not however
23 // invalidate any other reasons why the executable file might be covered by
24 // the GNU General Public License.
25 //
26 // This exception applies only to the code released under the name GNU
27 // ccRTP. If you copy code from other releases into a copy of GNU
28 // ccRTP, as the General Public License permits, the exception does
29 // not apply to the code that you add in this way. To avoid misleading
30 // anyone as to the status of such modified files, you must delete
31 // this exception notice from them.
32 //
33 // If you write modifications of your own for GNU ccRTP, it is your choice
34 // whether to permit this exception to apply to your modifications.
35 // If you do not wish that, delete this exception notice.
36 //
37
49 #ifndef CCXX_RTP_RTP_H_
50 #define CCXX_RTP_RTP_H_
51
54
55 #ifdef CCXX_NAMESPACES
56 namespace ost {
57 #endif
58
89 {
90 public:
101 tpport_t controlPort, uint32 membersSize,
104 { build(ia,dataPort,controlPort); }
105
122 { build(ia,dataPort,controlPort); }
123
137 tpport_t controlPort, uint32 membersSize,
140 { build(ia,dataPort,controlPort,iface); }
141
158 tpport_t controlPort, uint32 membersSize,
161 { build(ia,dataPort,controlPort,iface); }
162
164 {
166 }
167
176 {
178 if ( error )
return error;
179 error = dso->setTimeToLive(ttl);
180 if ( error )
return error;
181 error = cso->setMulticast(true);
182 if ( error )
return error;
183 return cso->setTimeToLive(ttl);
184 }
185
186 inline virtual
188 {
189 endSocket();
190 }
191
193 {return dso;}
194
195 protected:
199 inline bool
201 { return dso->isPendingRecv(timeout); }
202
205 { return dso->getSender(port); }
206
207 inline size_t
209 { return dso->getNextPacketSize(); }
210
220 inline size_t
223 { na = dso->getSender(tp); return dso->recv(buffer, len); }
224
225 inline void
227 { dso->setPeer(host,port); }
228
229
234 inline size_t
235 sendData(
const unsigned char*
const buffer,
size_t len)
236 { return dso->send(buffer, len); }
237
239 { return dso->getRecvSocket(); }
240
245 inline bool
247 { return cso->isPendingRecv(timeout); }
248
251 { return cso->getSender(port); }
252
262 inline size_t
265 { na = cso->getSender(tp); return cso->recv(buffer,len); }
266
267 inline void
269 { cso->setPeer(host,port); }
270
276 inline size_t
278 { return cso->send(buffer,len); }
279
281 { return cso->getRecvSocket(); }
282
291 {
293 if ( error )
return error;
294 error = dso->join(ia,iface);
295 if ( error )
return error;
296 error = cso->setMulticast(true);
297 if ( error ) {
298 dso->drop(ia);
300 }
301 error = cso->join(ia,iface);
302 if ( error ) {
303 dso->drop(ia);
305 }
307 }
308
317 {
319 if ( error )
return error;
320 error = dso->leaveGroup(ia);
321 if ( error )
return error;
322 error = cso->setMulticast(false);
323 if ( error )
return error;
324 return cso->leaveGroup(ia);
325 }
326
327 inline void
329 {
330 if (dso) {
331 dso->endSocket();
332 delete dso;
333 }
334 dso = NULL;
335 if (cso) {
336 cso->endSocket();
337 delete cso;
338 }
339 cso = NULL;
340 }
341
342 private:
343 void
346 {
347 if ( 0 == controlPort ) {
348 dataBasePort = even_port(dataPort);
349 controlBasePort = dataBasePort + 1;
350 } else {
351 dataBasePort = dataPort;
352 controlBasePort = controlPort;
353 }
354 dso = new RTPDataChannel(ia,dataBasePort);
355 cso = new RTCPChannel(ia,controlBasePort);
356 }
357
358 void
361 {
362 if ( 0 == controlPort ) {
363 dataBasePort = even_port(dataPort);
364 controlBasePort = dataBasePort + 1;
365 } else {
366 dataBasePort = dataPort;
367 controlBasePort = controlPort;
368 }
371 joinGroup(ia,iface);
372 }
373
383 { return (port & 0x01)? (port) : (port - 1); }
384
394 { return (port & 0x01)? (port - 1) : (port); }
395
398
399 protected:
403 };
404
415 template
422 {
423 public:
427 int pri = 0,
428 uint32 memberssize =
431 #if defined(_MSC_VER) && _MSC_VER >= 1300
432 );
433 #else
434 ):
437 (ia,dataPort,controlPort,memberssize,app)
438 { }
439 #endif
440
444 int pri = 0,
445 uint32 memberssize =
448 #if defined(_MSC_VER) && _MSC_VER >= 1300
449 );
450 #else
451 ):
454 (ssrc, ia,dataPort,controlPort,memberssize,app)
455 { }
456 #endif
457
461 int pri = 0,
462 uint32 memberssize =
465 uint32 iface = 0
466 #if defined(_MSC_VER) && _MSC_VER >= 1300
467 );
468 #else
469 ):
472 (ia,dataPort,controlPort,memberssize,app,iface)
473 { }
474 #endif
475
479 int pri = 0,
480 uint32 memberssize =
483 uint32 iface = 0
484 #if defined(_MSC_VER) && _MSC_VER >= 1300
485 );
486 #else
487 ):
490 (ssrc,ia,dataPort,controlPort,memberssize,app,iface)
491 { }
492 #endif
493
494
496 {
497 if (isRunning()) {
499 }
500 }
501
502 #if defined(_MSC_VER) && _MSC_VER >= 1300
503 virtual void startRunning();
504 #else
505
508 void
511 #endif
512
513
514 protected:
517
520
523
526
529
532
535
536 #if defined(_MSC_VER) && _MSC_VER >= 1300
537 virtual void run(void);
538
539 virtual void timerTick(void);
540
542 #else
543
545 {return;}
546
549
555 {
557 while ( ServiceQueue::isActive() ) {
558 if ( timeout < 1000 ){ // !(timeout/1000)
559 timeout = getSchedulingTimeout();
560 }
561 setCancel(cancelDeferred);
562 controlReceptionService();
563 controlTransmissionService();
564 setCancel(cancelImmediate);
567 // make sure the scheduling timeout is
568 // <= the check interval for RTCP
569 // packets
570 timeout = (timeout > maxWait)? maxWait : timeout;
571 if ( timeout < 1000 ) { // !(timeout/1000)
572 setCancel(cancelDeferred);
573 dispatchDataPacket();
574 setCancel(cancelImmediate);
575 timerTick();
576 } else {
577 if ( isPendingData(timeout/1000) ) {
578 setCancel(cancelDeferred);
579 if (ServiceQueue::isActive()) { // take in only if active
580 takeInDataPacket();
581 }
582 setCancel(cancelImmediate);
583 }
584 timeout = 0;
585 }
586 }
587 dispatchBYE("GNU ccRTP stack finishing.");
588 // Thread::exit();
589 }
590
591 #endif
592
595
598 };
599
609
616
627
628 #ifdef CCXX_IPV6
629
651 template <class RTPDataChannel = DualRTPUDPIPv6Channel,
652 class RTCPChannel = DualRTPUDPIPv6Channel,
655 {
656 public:
666 TRTPSessionBaseIPV6(
const IPV6Host& ia,
tpport_t dataPort,
667 tpport_t controlPort, uint32 membersSize,
670 { build(ia,dataPort,controlPort); }
671
683 TRTPSessionBaseIPV6(uint32 ssrc,
684 const IPV6Host& ia,
688 { build(ia,dataPort,controlPort); }
689
702 TRTPSessionBaseIPV6(
const IPV6Multicast& ia,
tpport_t dataPort,
703 tpport_t controlPort, uint32 membersSize,
706 { build(ia,dataPort,controlPort,iface); }
707
722 TRTPSessionBaseIPV6(uint32 ssrc,
723 const IPV6Multicast& ia,
tpport_t dataPort,
724 tpport_t controlPort, uint32 membersSize,
727 { build(ia,dataPort,controlPort,iface); }
728
729 virtual size_t dispatchBYE(const std::string &str)
730 {
732 }
733
734 inline virtual
735 ~TRTPSessionBaseIPV6()
736 {
737 endSocket();
738 }
739
740 inline RTPDataChannel *getDSO(void)
741 {return dso;}
742
743 protected:
747 inline bool
749 { return dso->isPendingRecv(timeout); }
750
751 inline IPV6Host
752 getDataSender(
tpport_t *port = NULL)
const
753 { return dso->getSender(port); }
754
755 inline size_t
756 getNextDataPacketSize() const
757 { return dso->getNextPacketSize(); }
758
768 inline size_t
769 recvData(unsigned char* buffer, size_t len,
771 { na = dso->getSender(tp); return dso->recv(buffer, len); }
772
773 inline void
774 setDataPeerIPV6(
const IPV6Host &host,
tpport_t port)
775 { dso->setPeer(host,port); }
776
781 inline size_t
782 sendDataIPV6(const unsigned char* const buffer, size_t len)
783 { return dso->send(buffer, len); }
784
785 inline SOCKET getDataRecvSocket()
const
786 { return dso->getRecvSocket(); }
787
792 inline bool
794 { return cso->isPendingRecv(timeout); }
795
796 inline IPV6Host
797 getControlSender(
tpport_t *port = NULL)
const
798 { return cso->getSender(port); }
799
809 inline size_t
810 recvControl(unsigned char *buffer, size_t len,
812 { na = cso->getSender(tp); return cso->recv(buffer,len); }
813
814 inline void
815 setControlPeerIPV6(
const IPV6Host &host,
tpport_t port)
816 { cso->setPeer(host,port); }
817
823 inline size_t
824 sendControl(const unsigned char* const buffer, size_t len)
825 { return cso->send(buffer,len); }
826
827 inline SOCKET getControlRecvSocket()
const
828 { return cso->getRecvSocket(); }
829
830 inline void
831 endSocket()
832 {
833 dso->endSocket();
834 cso->endSocket();
835 if (dso) delete dso;
836 dso = NULL;
837 if (cso) delete cso;
838 cso = NULL;
839 }
840
841 private:
842 void
843 build(
const IPV6Host& ia,
tpport_t dataPort,
845 {
846 if ( 0 == controlPort ) {
847 dataBasePort = even_port(dataPort);
848 controlBasePort = dataBasePort + 1;
849 } else {
850 dataBasePort = dataPort;
851 controlBasePort = controlPort;
852 }
853 dso = new RTPDataChannel(ia,dataBasePort);
854 cso = new RTCPChannel(ia,controlBasePort);
855 }
856
857 void
858 build(
const IPV6Multicast& ia,
tpport_t dataPort,
860 {
861 if ( 0 == controlPort ) {
862 dataBasePort = even_port(dataPort);
863 controlBasePort = dataBasePort + 1;
864 } else {
865 dataBasePort = dataPort;
866 controlBasePort = controlPort;
867 }
868 dso = new RTPDataChannel(IPV6Host("0.0.0.0"),dataBasePort);
869 cso = new RTCPChannel(IPV6Host("0.0.0.0"),controlBasePort);
870 joinGroup(ia,iface);
871 }
872
880 joinGroup(const IPV6Multicast& ia, uint32 iface)
881 {
883 if ( error )
return error;
884 error = dso->join(ia,iface);
885 if ( error )
return error;
886 error = cso->setMulticast(true);
887 if ( error ) {
888 dso->drop(ia);
890 }
891 error = cso->join(ia,iface);
892 if ( error ) {
893 dso->drop(ia);
895 }
897 }
898
906 leaveGroup(const IPV6Multicast& ia)
907 {
909 if ( error )
return error;
910 error = dso->leaveGroup(ia);
911 if ( error )
return error;
912 error = cso->setMulticast(false);
913 if ( error )
return error;
914 return cso->leaveGroup(ia);
915 }
916
924 setMcastTTL(uint8 ttl)
925 {
927 if ( error )
return error;
928 error = dso->setTimeToLive(ttl);
929 if ( error )
return error;
930 error = cso->setMulticast(true);
931 if ( error )
return error;
932 return cso->setTimeToLive(ttl);
933 }
934
944 { return (port & 0x01)? (port) : (port - 1); }
945
955 { return (port & 0x01)? (port - 1) : (port); }
956
959
960 protected:
961 RTPDataChannel* dso;
962 RTCPChannel* cso;
964 };
965
976 template
977 <class RTPDataChannel = DualRTPUDPIPv6Channel,
978 class RTCPChannel = DualRTPUDPIPv6Channel,
980 class __EXPORT SingleThreadRTPSessionIPV6 :
982 public TRTPSessionBaseIPV6<RTPDataChannel,RTCPChannel,ServiceQueue>
983 {
984 public:
985 SingleThreadRTPSessionIPV6(const IPV6Host& ia,
988 int pri = 0,
989 uint32 memberssize =
992 #if defined(_MSC_VER) && _MSC_VER >= 1300
993 );
994 #else
995 ):
997 TRTPSessionBaseIPV6<RTPDataChannel,RTCPChannel,ServiceQueue>
998 (ia,dataPort,controlPort,memberssize,app)
999 { }
1000 #endif
1001
1002 SingleThreadRTPSessionIPV6(const IPV6Multicast& ia,
1005 int pri = 0,
1006 uint32 memberssize =
1009 uint32 iface = 0
1010 #if defined(_MSC_VER) && _MSC_VER >= 1300
1011 );
1012 #else
1013 ):
1015 TRTPSessionBaseIPV6<RTPDataChannel,RTCPChannel,ServiceQueue>
1016 (ia,dataPort,controlPort,memberssize,app,iface)
1017 { }
1018 #endif
1019
1020 ~SingleThreadRTPSessionIPV6()
1021 {
1022 if (isRunning()) {
1024 }
1025 }
1026
1027 #if defined(_MSC_VER) && _MSC_VER >= 1300
1028 virtual void startRunning();
1029 #else
1030
1033 void
1034 startRunning()
1036 #endif
1037
1038
1039 protected:
1040 inline void enableStack(void)
1042
1043 inline void disableStack(void)
1045
1048
1049 inline void controlReceptionService(void)
1051
1052 inline void controlTransmissionService(void)
1054
1055 inline timeval getRTCPCheckInterval(void)
1057
1058 inline size_t dispatchDataPacket(void)
1060
1061 #if defined(_MSC_VER) && _MSC_VER >= 1300
1062 virtual void run(void);
1063
1064 virtual void timerTick(void);
1065
1067 #else
1068
1069 virtual void timerTick(void)
1070 {return;}
1071
1074
1079 virtual void run(void)
1080 {
1082 while ( ServiceQueue::isActive() ) {
1083 if ( timeout < 1000 ){ // !(timeout/1000)
1084 timeout = getSchedulingTimeout();
1085 }
1086 setCancel(cancelDeferred);
1087 controlReceptionService();
1088 controlTransmissionService();
1089 setCancel(cancelImmediate);
1092 // make sure the scheduling timeout is
1093 // <= the check interval for RTCP
1094 // packets
1095 timeout = (timeout > maxWait)? maxWait : timeout;
1096 if ( timeout < 1000 ) { // !(timeout/1000)
1097 setCancel(cancelDeferred);
1098 dispatchDataPacket();
1099 setCancel(cancelImmediate);
1100 timerTick();
1101 } else {
1102 if ( isPendingData(timeout/1000) ) {
1103 setCancel(cancelDeferred);
1104 takeInDataPacket();
1105 setCancel(cancelImmediate);
1106 }
1107 timeout = 0;
1108 }
1109 }
1110 dispatchBYE("GNU ccRTP stack finishing.");
1112 }
1113
1114 #endif
1115
1116 inline size_t takeInDataPacket(void)
1118
1119 inline size_t dispatchBYE(const std::string &str)
1121 };
1122
1131 typedef SingleThreadRTPSessionIPV6<> RTPSessionIPV6;
1132
1138 typedef RTPSessionIPV6 RTPSocketIPV6;
1139
1148 typedef SingleThreadRTPSessionIPV6<SymmetricRTPChannelIPV6,
1149 SymmetricRTPChannelIPV6> SymmetricRTPSessionIPV6;
1150
1151
1152 #endif
1153 // sessions
1155
1156 #ifdef CCXX_NAMESPACES
1157 }
1158 #endif
1159
1160 #endif //CCXX_RTP_RTP_H_
1161
void setControlPeer(const InetAddress &host, tpport_t port)
An RTP application, holding identifying RTCP SDES item values.
void build(const InetHostAddress &ia, tpport_t dataPort, tpport_t controlPort)
~SingleThreadRTPSession()
RTPSession RTPSocket
Alias for RTPSession.
SingleThreadRTPSession(const InetMcastAddress &ia, tpport_t dataPort=DefaultRTPDataPort, tpport_t controlPort=0, int pri=0, uint32 memberssize=MembershipBookkeeping::defaultMembersHashSize, RTPApplication &app=defaultApplication(), uint32 iface=0)
InetHostAddress getControlSender(tpport_t *port=NULL) const
DualRTPChannel< RTPBaseUDPIPv4Socket > DualRTPUDPIPv4Channel
__EXPORT AppLog & error(AppLog &sl)
Manipulator for error level.
virtual void timerTick(void)
uint32 microtimeout_t
Time interval expressed in microseconds.
void controlReceptionService(void)
TRTPSessionBase(uint32 ssrc, const InetMcastAddress &ia, tpport_t dataPort, tpport_t controlPort, uint32 membersSize, RTPApplication &app, uint32 iface)
Builds a session waiting for packets in a multicast address, with the specified ssrc identifier for t...
unsigned short tpport_t
Transport Protocol Ports.
Socket::Error setMcastTTL(uint8 ttl)
Set the value of the TTL field in the sent packets.
microtimeout_t timeval2microtimeout(const timeval &t)
Convert a time interval, expressed as a timeval value into a microseconds counter.
size_t dispatchBYE(const std::string &str)
int start(Semaphore *start=0)
When a new thread is created, it does not begin immediate execution.
size_t sendData(const unsigned char *const buffer, size_t len)
void setDataPeer(const InetAddress &host, tpport_t port)
tpport_t even_port(tpport_t port)
Ensure a port number is even.
SingleRTPChannel SymmetricRTPChannel
Actually, RTP with a single channel can be called 'Symmetric RTP'.
void build(const InetMcastAddress &ia, tpport_t dataPort, tpport_t controlPort, uint32 iface)
SOCKET getDataRecvSocket() const
size_t dispatchDataPacket(void)
InetHostAddress getDataSender(tpport_t *port=NULL) const
virtual bool isPendingData(microtimeout_t timeout)
bool isPendingControl(microtimeout_t timeout)
void join(void)
Blocking call which unlocks when thread terminates.
Socket::Error joinGroup(const InetMcastAddress &ia, uint32 iface)
Join a multicast group.
Definition of socket classes for different underlying transport and/or network protocols that can be ...
SOCKET getControlRecvSocket() const
tpport_t odd_port(tpport_t port)
Ensure a port number is odd.
size_t takeInDataPacket(void)
A UDP/IPv4 socket class targetted at RTP stacks.
SingleThreadRTPSession(const InetHostAddress &ia, tpport_t dataPort=DefaultRTPDataPort, tpport_t controlPort=0, int pri=0, uint32 memberssize=MembershipBookkeeping::defaultMembersHashSize, RTPApplication &app=defaultApplication())
virtual size_t dispatchBYE(const std::string &str)
size_t recvControl(unsigned char *buffer, size_t len, InetHostAddress &na, tpport_t &tp)
Receive data from the control channel/socket.
void startRunning()
Activate stack and start service thread.
SingleThreadRTPSession RTPSession
Uses two pairs of sockets for RTP data and RTCP transmission/reception.
bool isPendingData(microtimeout_t timeout)
static const size_t defaultMembersHashSize
virtual void run(void)
Single runnable method for this RTP stacks, schedules outgoing and incoming RTP data and RTCP packets...
size_t recvData(unsigned char *buffer, size_t len, InetHostAddress &na, tpport_t &tp)
Receive data from the data channel/socket.
Generic RTCP control queues.
TRTPSessionBase(uint32 ssrc, const InetHostAddress &ia, tpport_t dataPort, tpport_t controlPort, uint32 membersSize, RTPApplication &app)
Builds a session with the specified ssrc identifier for the local source.
TRTPSessionBase(const InetMcastAddress &ia, tpport_t dataPort, tpport_t controlPort, uint32 membersSize, RTPApplication &app, uint32 iface)
Builds a session waiting for packets in a multicast address.
const tpport_t DefaultRTPDataPort
registered default RTP data transport port
SingleThreadRTPSession(uint32 ssrc, const InetHostAddress &ia, tpport_t dataPort=DefaultRTPDataPort, tpport_t controlPort=0, int pri=0, uint32 memberssize=MembershipBookkeeping::defaultMembersHashSize, RTPApplication &app=defaultApplication())
Socket::Error leaveGroup(const InetMcastAddress &ia)
Leave a multicast group.
size_t sendControl(const unsigned char *const buffer, size_t len)
This template class adds the threading aspect to the RTPSessionBase template in one of the many possi...
void exit(void)
Used to properly exit from a Thread derived run() or initial() method.
Every thread of execution in an application is created by instantiating an object of a class derived ...
timeval getRTCPCheckInterval(void)
size_t getNextDataPacketSize() const
SingleThreadRTPSession< SymmetricRTPChannel, SymmetricRTPChannel > SymmetricRTPSession
Uses one pair of sockets, (1) for RTP data and (2) for RTCP transmission/reception.
SingleThreadRTPSession(uint32 ssrc, const InetMcastAddress &ia, tpport_t dataPort=DefaultRTPDataPort, tpport_t controlPort=0, int pri=0, uint32 memberssize=MembershipBookkeeping::defaultMembersHashSize, RTPApplication &app=defaultApplication(), uint32 iface=0)
virtual ~TRTPSessionBase()
TRTPSessionBase(const InetHostAddress &ia, tpport_t dataPort, tpport_t controlPort, uint32 membersSize, RTPApplication &app)
Builds a session waiting for packets in a host address.
__EXPORT RTPApplication & defaultApplication()
Get the RTPApplication object for the "default" application (the only one used by common applications...
microtimeout_t getSchedulingTimeout(void)
RTPDataChannel * getDSO(void)
size_t dispatchBYE(const std::string &reason)
This method is used to send an RTCP BYE packet.
void controlTransmissionService(void)
This class, an RTP/RTCP queue, adds audio/video profile (AVP) specific methods to the generic RTCP se...