blob: a3e28611ababb8a5958ec86d18d3ebc5352bdab0 [file] [log] [blame]
Emeric Vigier2f625822012-08-06 11:09:52 -04001// 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
38/**
39 * @file rtp.h
40 *
41 * @short Generic and audio/video profile specific RTP interface of
42 * ccRTP.
43 *
44 * The classes and types in this header provide general RTP
45 * functionality (following RFC 3550) as well as audio/video RTP
46 * profile specific functionality (following RFC 3551).
47 **/
48
49#ifndef CCXX_RTP_RTP_H_
50#define CCXX_RTP_RTP_H_
51
52#include <ccrtp/cqueue.h>
53#include <ccrtp/channel.h>
54
55#ifdef CCXX_NAMESPACES
56namespace ost {
57#endif
58
59/**
60 * @defgroup sessions RTP sessions.
61 * @{
62 **/
63
64/**
65 * @class RTPSessionBase
66 *
67 * Generic RTP protocol stack for exchange of realtime data. This
68 * stack uses the concept of packet send and receive queues to schedule
69 * and buffer outgoing packets and to arrange or reorder incoming packets
70 * as they arrive.
71 *
72 * This is a template class that allows customization of two aspects:
73 * the underlying network and the control protocol. The RTPDataChannel
74 * and RTCPChannel template parameters specify the socket types to
75 * use. The ServiceQueue template parameter specify which packet queue
76 * is used.
77 *
78 * RTPSessionBase objects do not have any threading policy, thus
79 * allowing to customize this aspect in derived classes (see
80 * SingleThreadRTPSession or RTPSessionPoolBase).
81 *
82 * @author David Sugar <dyfet@ostel.com>
83 * @short RTP protocol stack based on Common C++.
84 **/
85 template <class RTPDataChannel = DualRTPUDPIPv4Channel,
86 class RTCPChannel = DualRTPUDPIPv4Channel,
87 class ServiceQueue = AVPQueue>
88 class __EXPORT TRTPSessionBase : public ServiceQueue
89 {
90 public:
91 /**
92 * Builds a session waiting for packets in a host address.
93 *
94 * @param ia Network address this socket is to be bound.
95 * @param dataPort Transport port the data socket is to be bound.
96 * @param controlPort Transport port the control socket is to be bound.
97 * @param membersSize Initial size of the membership table.
98 * @param app Application this session is associated to.
99 * */
100 TRTPSessionBase(const InetHostAddress& ia, tpport_t dataPort,
101 tpport_t controlPort, uint32 membersSize,
102 RTPApplication& app) :
103 ServiceQueue(membersSize,app)
104 { build(ia,dataPort,controlPort); }
105
106 /**
107 * Builds a session with the specified ssrc identifier for the
108 * local source.
109 *
110 * @param ssrc SSRC identifier for the local source.
111 * @param ia Network address this socket is to be bound.
112 * @param dataPort Transport port the data socket is to be bound.
113 * @param controlPort Transport port the control socket is to be bound.
114 * @param membersSize Initial size of the membership table.
115 * @param app Application this session is associated to.
116 **/
117 TRTPSessionBase(uint32 ssrc,
118 const InetHostAddress& ia,
119 tpport_t dataPort, tpport_t controlPort,
120 uint32 membersSize, RTPApplication& app):
121 ServiceQueue(ssrc,membersSize,app)
122 { build(ia,dataPort,controlPort); }
123
124 /**
125 * Builds a session waiting for packets in a multicast address.
126 * TODO: ssrc constructor for multicast!
127 *
128 * @param ia Multicast address this socket is to be bound.
129 * @param dataPort Transport port the data socket is to be bound.
130 * @param controlPort Transport port the control socket is to be bound.
131 * @param membersSize Initial size of the membership table.
132 * @param app Application this session is associated to.
133 * @param iface Index (from 0 to n) of network interface to join to
134 * multicast group.
135 **/
136 TRTPSessionBase(const InetMcastAddress& ia, tpport_t dataPort,
137 tpport_t controlPort, uint32 membersSize,
138 RTPApplication& app, uint32 iface) :
139 ServiceQueue(membersSize,app)
140 { build(ia,dataPort,controlPort,iface); }
141
142 /**
143 * Builds a session waiting for packets in a multicast
144 * address, with the specified ssrc identifier for the local
145 * source.
146 *
147 * @param ssrc SSRC identifier for the local source.
148 * @param ia Multicast address this socket is to be bound.
149 * @param dataPort Transport port the data socket is to be bound.
150 * @param controlPort Transport port the control socket is to be bound.
151 * @param membersSize Initial size of the membership table.
152 * @param app Application this session is associated to.
153 * @param iface Index (from 0 to n) of network interface to join to
154 * multicast group.
155 **/
156 TRTPSessionBase(uint32 ssrc,
157 const InetMcastAddress& ia, tpport_t dataPort,
158 tpport_t controlPort, uint32 membersSize,
159 RTPApplication& app, uint32 iface) :
160 ServiceQueue(ssrc,membersSize,app)
161 { build(ia,dataPort,controlPort,iface); }
162
163 virtual size_t dispatchBYE(const std::string &str)
164 {
165 return QueueRTCPManager::dispatchBYE(str);
166 }
167
168 /**
169 * Set the value of the TTL field in the sent packets.
170 *
171 * @param ttl Time To Live
172 * @return error code from the socket operation
173 */
174 inline Socket::Error
175 setMcastTTL(uint8 ttl)
176 {
177 Socket::Error error = dso->setMulticast(true);
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
187 ~TRTPSessionBase()
188 {
189 endSocket();
190 }
191
192 inline RTPDataChannel *getDSO(void)
193 {return dso;}
194
195 protected:
196 /**
197 * @param timeout maximum timeout to wait, in microseconds
198 */
199 inline bool
200 isPendingData(microtimeout_t timeout)
201 { return dso->isPendingRecv(timeout); }
202
203 InetHostAddress
204 getDataSender(tpport_t *port = NULL) const
205 { return dso->getSender(port); }
206
207 inline size_t
208 getNextDataPacketSize() const
209 { return dso->getNextPacketSize(); }
210
211 /**
212 * Receive data from the data channel/socket.
213 *
214 * @param buffer Memory region to read to.
215 * @param len Maximum number of octets to get.
216 * @param na Source network address.
217 * @param tp Source transport port.
218 * @return Number of octets actually read.
219 */
220 inline size_t
221 recvData(unsigned char* buffer, size_t len,
222 InetHostAddress& na, tpport_t& tp)
223 { na = dso->getSender(tp); return dso->recv(buffer, len); }
224
225 inline void
226 setDataPeer(const InetAddress &host, tpport_t port)
227 { dso->setPeer(host,port); }
228
229
230 /**
231 * @param buffer memory region to write from
232 * @param len number of octets to write
233 */
234 inline size_t
235 sendData(const unsigned char* const buffer, size_t len)
236 { return dso->send(buffer, len); }
237
238 inline SOCKET getDataRecvSocket() const
239 { return dso->getRecvSocket(); }
240
241 /**
242 * @param timeout maximum timeout to wait, in microseconds
243 * @return whether there are packets waiting to be picked
244 */
245 inline bool
246 isPendingControl(microtimeout_t timeout)
247 { return cso->isPendingRecv(timeout); }
248
249 InetHostAddress
250 getControlSender(tpport_t *port = NULL) const
251 { return cso->getSender(port); }
252
253 /**
254 * Receive data from the control channel/socket.
255 *
256 * @param buffer Buffer where to get data.
257 * @param len Maximum number of octets to get.
258 * @param na Source network address.
259 * @param tp Source transport port.
260 * @return Number of octets actually read.
261 **/
262 inline size_t
263 recvControl(unsigned char *buffer, size_t len,
264 InetHostAddress& na, tpport_t& tp)
265 { na = cso->getSender(tp); return cso->recv(buffer,len); }
266
267 inline void
268 setControlPeer(const InetAddress &host, tpport_t port)
269 { cso->setPeer(host,port); }
270
271 /**
272 * @return number of octets actually written
273 * @param buffer
274 * @param len
275 */
276 inline size_t
277 sendControl(const unsigned char* const buffer, size_t len)
278 { return cso->send(buffer,len); }
279
280 inline SOCKET getControlRecvSocket() const
281 { return cso->getRecvSocket(); }
282
283 /**
284 * Join a multicast group.
285 *
286 * @param ia address of the multicast group
287 * @return error code from the socket operation
288 */
289 inline Socket::Error
290 joinGroup(const InetMcastAddress& ia, uint32 iface)
291 {
292 Socket::Error error = dso->setMulticast(true);
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);
299 return error;
300 }
301 error = cso->join(ia,iface);
302 if ( error ) {
303 dso->drop(ia);
304 return error;
305 }
306 return Socket::errSuccess;
307 }
308
309 /**
310 * Leave a multicast group.
311 *
312 * @param ia address of the multicast group
313 * @return error code from the socket operation
314 */
315 inline Socket::Error
316 leaveGroup(const InetMcastAddress& ia)
317 {
318 Socket::Error error = dso->setMulticast(false);
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
328 endSocket()
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
344 build(const InetHostAddress& ia, tpport_t dataPort,
345 tpport_t controlPort)
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
359 build(const InetMcastAddress& ia, tpport_t dataPort,
360 tpport_t controlPort, uint32 iface)
361 {
362 if ( 0 == controlPort ) {
363 dataBasePort = even_port(dataPort);
364 controlBasePort = dataBasePort + 1;
365 } else {
366 dataBasePort = dataPort;
367 controlBasePort = controlPort;
368 }
369 dso = new RTPDataChannel(InetHostAddress("0.0.0.0"),dataBasePort);
370 cso = new RTCPChannel(InetHostAddress("0.0.0.0"),controlBasePort);
371 joinGroup(ia,iface);
372 }
373
374 /**
375 * Ensure a port number is odd. If it is an even number, return
376 * the next lower (odd) port number.
377 *
378 * @param port number to filter
379 * @return filtered (odd) port number
380 */
381 inline tpport_t
382 odd_port(tpport_t port)
383 { return (port & 0x01)? (port) : (port - 1); }
384
385 /**
386 * Ensure a port number is even. If it is an odd number, return
387 * the next lower (even) port number.
388 *
389 * @param port number to filter
390 * @return filtered (even) port number
391 */
392 inline tpport_t
393 even_port(tpport_t port)
394 { return (port & 0x01)? (port - 1) : (port); }
395
396 tpport_t dataBasePort;
397 tpport_t controlBasePort;
398
399 protected:
400 RTPDataChannel* dso;
401 RTCPChannel* cso;
402 friend class RTPSessionBaseHandler;
403 };
404
405/**
406 * @class SingleThreadRTPSession
407 *
408 * This template class adds the threading aspect to the RTPSessionBase
409 * template in one of the many possible ways. It inherits from a
410 * single execution thread that schedules sending of outgoing packets
411 * and receipt of incoming packets.
412 *
413 * @author Federico Montesino Pouzols <fedemp@altern.org>
414 **/
415 template
416 <class RTPDataChannel = DualRTPUDPIPv4Channel,
417 class RTCPChannel = DualRTPUDPIPv4Channel,
418 class ServiceQueue = AVPQueue>
419 class __EXPORT SingleThreadRTPSession :
420 protected Thread,
421 public TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>
422 {
423 public:
424 SingleThreadRTPSession(const InetHostAddress& ia,
425 tpport_t dataPort = DefaultRTPDataPort,
426 tpport_t controlPort = 0,
427 int pri = 0,
428 uint32 memberssize =
429 MembershipBookkeeping::defaultMembersHashSize,
430 RTPApplication& app = defaultApplication()
431#if defined(_MSC_VER) && _MSC_VER >= 1300
432 );
433#else
434 ):
435 Thread(pri),
436 TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>
437 (ia,dataPort,controlPort,memberssize,app)
438 { }
439#endif
440
441 SingleThreadRTPSession(uint32 ssrc, const InetHostAddress& ia,
442 tpport_t dataPort = DefaultRTPDataPort,
443 tpport_t controlPort = 0,
444 int pri = 0,
445 uint32 memberssize =
446 MembershipBookkeeping::defaultMembersHashSize,
447 RTPApplication& app = defaultApplication()
448#if defined(_MSC_VER) && _MSC_VER >= 1300
449 );
450#else
451 ):
452 Thread(pri),
453 TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>
454 (ssrc, ia,dataPort,controlPort,memberssize,app)
455{ }
456#endif
457
458SingleThreadRTPSession(const InetMcastAddress& ia,
459 tpport_t dataPort = DefaultRTPDataPort,
460 tpport_t controlPort = 0,
461 int pri = 0,
462 uint32 memberssize =
463 MembershipBookkeeping::defaultMembersHashSize,
464 RTPApplication& app = defaultApplication(),
465 uint32 iface = 0
466#if defined(_MSC_VER) && _MSC_VER >= 1300
467 );
468#else
469 ):
470 Thread(pri),
471 TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>
472 (ia,dataPort,controlPort,memberssize,app,iface)
473 { }
474#endif
475
476SingleThreadRTPSession(uint32 ssrc, const InetMcastAddress& ia,
477 tpport_t dataPort = DefaultRTPDataPort,
478 tpport_t controlPort = 0,
479 int pri = 0,
480 uint32 memberssize =
481 MembershipBookkeeping::defaultMembersHashSize,
482 RTPApplication& app = defaultApplication(),
483 uint32 iface = 0
484#if defined(_MSC_VER) && _MSC_VER >= 1300
485 );
486#else
487 ):
488 Thread(pri),
489 TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>
490 (ssrc,ia,dataPort,controlPort,memberssize,app,iface)
491{ }
492#endif
493
494
495~SingleThreadRTPSession()
496{
497 if (isRunning()) {
498 disableStack(); Thread::join();
499 }
500}
501
502#if defined(_MSC_VER) && _MSC_VER >= 1300
503virtual void startRunning();
504#else
505/**
506 * Activate stack and start service thread.
507 **/
508void
509startRunning()
510{ enableStack(); Thread::start(); }
511#endif
512
513
514protected:
515inline void disableStack(void)
516{TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::disableStack();}
517
518inline void enableStack(void)
519{TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::enableStack();}
520
521inline microtimeout_t getSchedulingTimeout(void)
522{return TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::getSchedulingTimeout();}
523
524inline void controlReceptionService(void)
525{TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::controlReceptionService();}
526
527inline void controlTransmissionService(void)
528{TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::controlTransmissionService();}
529
530inline timeval getRTCPCheckInterval(void)
531{return TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::getRTCPCheckInterval();}
532
533inline size_t dispatchDataPacket(void)
534{return TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::dispatchDataPacket();}
535
536#if defined(_MSC_VER) && _MSC_VER >= 1300
537virtual void run(void);
538
539virtual void timerTick(void);
540
541virtual bool isPendingData(microtimeout_t timeout);
542#else
543
544virtual void timerTick(void)
545{return;}
546
547virtual bool isPendingData(microtimeout_t timeout)
548{return TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::isPendingData(timeout);}
549
550/**
551 * Single runnable method for this RTP stacks, schedules
552 * outgoing and incoming RTP data and RTCP packets.
553 **/
554virtual void run(void)
555{
556 microtimeout_t timeout = 0;
557 while ( ServiceQueue::isActive() ) {
558 if ( timeout < 1000 ){ // !(timeout/1000)
559 timeout = getSchedulingTimeout();
560 }
561 setCancel(cancelDeferred);
562 controlReceptionService();
563 controlTransmissionService();
564 setCancel(cancelImmediate);
565 microtimeout_t maxWait =
566 timeval2microtimeout(getRTCPCheckInterval());
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
593inline size_t takeInDataPacket(void)
594{return TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::takeInDataPacket();}
595
596inline size_t dispatchBYE(const std::string &str)
597{return TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::dispatchBYE(str);}
598};
599
600/**
601 * @typedef RTPSession
602 *
603 * Uses two pairs of sockets for RTP data and RTCP
604 * transmission/reception.
605 *
606 * @short UDP/IPv4 RTP Session scheduled by one thread of execution.
607 **/
608typedef SingleThreadRTPSession<> RTPSession;
609
610/**
611 * @typedef RTPSocket
612 *
613 * Alias for RTPSession.
614 **/
615typedef RTPSession RTPSocket;
616
617/**
618 * @typedef SymmetricRTPSession
619 *
620 * Uses one pair of sockets, (1) for RTP data and (2) for RTCP
621 * transmission/reception.
622 *
623 * @short Symmetric UDP/IPv4 RTP session scheduled by one thread of execution.
624 **/
625typedef SingleThreadRTPSession<SymmetricRTPChannel,
626 SymmetricRTPChannel> SymmetricRTPSession;
627
628#ifdef CCXX_IPV6
629
630/**
631 * @class RTPSessionBaseIPV6
632 *
633 * Generic RTP protocol stack for exchange of realtime data. This
634 * stack uses the concept of packet send and receive queues to schedule
635 * and buffer outgoing packets and to arrange or reorder incoming packets
636 * as they arrive.
637 *
638 * This is a template class that allows customization of two aspects:
639 * the underlying network and the control protocol. The RTPDataChannel
640 * and RTCPChannel template parameters specify the socket types to
641 * use. The ServiceQueue template parameter specify which packet queue
642 * is used.
643 *
644 * RTPSessionBase objects do not have any threading policy, thus
645 * allowing to customize this aspect in derived classes (see
646 * SingleThreadRTPSession or RTPSessionPoolBase).
647 *
648 * @author David Sugar <dyfet@ostel.com>
649 * @short RTP protocol stack based on Common C++.
650 **/
651template <class RTPDataChannel = DualRTPUDPIPv6Channel,
652 class RTCPChannel = DualRTPUDPIPv6Channel,
653 class ServiceQueue = AVPQueue>
654class __EXPORT TRTPSessionBaseIPV6 : public ServiceQueue
655{
656public:
657/**
658 * Builds a session waiting for packets in a host address.
659 *
660 * @param ia Network address this socket is to be bound.
661 * @param dataPort Transport port the data socket is to be bound.
662 * @param controlPort Transport port the control socket is to be bound.
663 * @param membersSize Initial size of the membership table.
664 * @param app Application this session is associated to.
665 * */
666TRTPSessionBaseIPV6(const IPV6Host& ia, tpport_t dataPort,
667 tpport_t controlPort, uint32 membersSize,
668 RTPApplication& app) :
669 ServiceQueue(membersSize,app)
670{ build(ia,dataPort,controlPort); }
671
672 /**
673 * Builds a session with the specified ssrc identifier for the
674 * local source.
675 *
676 * @param ssrc SSRC identifier for the local source.
677 * @param ia Network address this socket is to be bound.
678 * @param dataPort Transport port the data socket is to be bound.
679 * @param controlPort Transport port the control socket is to be bound.
680 * @param membersSize Initial size of the membership table.
681 * @param app Application this session is associated to.
682 **/
683 TRTPSessionBaseIPV6(uint32 ssrc,
684 const IPV6Host& ia,
685 tpport_t dataPort, tpport_t controlPort,
686 uint32 membersSize, RTPApplication& app):
687 ServiceQueue(ssrc,membersSize,app)
688 { build(ia,dataPort,controlPort); }
689
690 /**
691 * Builds a session waiting for packets in a multicast address.
692 * TODO: ssrc constructor for multicast!
693 *
694 * @param ia Multicast address this socket is to be bound.
695 * @param dataPort Transport port the data socket is to be bound.
696 * @param controlPort Transport port the control socket is to be bound.
697 * @param membersSize Initial size of the membership table.
698 * @param app Application this session is associated to.
699 * @param iface Index (from 0 to n) of network interface to join to
700 * multicast group.
701 **/
702 TRTPSessionBaseIPV6(const IPV6Multicast& ia, tpport_t dataPort,
703 tpport_t controlPort, uint32 membersSize,
704 RTPApplication& app, uint32 iface) :
705 ServiceQueue(membersSize,app)
706 { build(ia,dataPort,controlPort,iface); }
707
708 /**
709 * Builds a session waiting for packets in a multicast
710 * address, with the specified ssrc identifier for the local
711 * source.
712 *
713 * @param ssrc SSRC identifier for the local source.
714 * @param ia Multicast address this socket is to be bound.
715 * @param dataPort Transport port the data socket is to be bound.
716 * @param controlPort Transport port the control socket is to be bound.
717 * @param membersSize Initial size of the membership table.
718 * @param app Application this session is associated to.
719 * @param iface Index (from 0 to n) of network interface to join to
720 * multicast group.
721 **/
722 TRTPSessionBaseIPV6(uint32 ssrc,
723 const IPV6Multicast& ia, tpport_t dataPort,
724 tpport_t controlPort, uint32 membersSize,
725 RTPApplication& app, uint32 iface) :
726 ServiceQueue(ssrc,membersSize,app)
727 { build(ia,dataPort,controlPort,iface); }
728
729 virtual size_t dispatchBYE(const std::string &str)
730 {
731 return QueueRTCPManager::dispatchBYE(str);
732 }
733
734 inline virtual
735 ~TRTPSessionBaseIPV6()
736 {
737 endSocket();
738 }
739
740 inline RTPDataChannel *getDSO(void)
741 {return dso;}
742
743protected:
744 /**
745 * @param timeout maximum timeout to wait, in microseconds
746 */
747 inline bool
748 isPendingData(microtimeout_t timeout)
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
759 /**
760 * Receive data from the data channel/socket.
761 *
762 * @param buffer Memory region to read to.
763 * @param len Maximum number of octets to get.
764 * @param na Source network address.
765 * @param tp Source transport port.
766 * @return Number of octets actually read.
767 */
768 inline size_t
769 recvData(unsigned char* buffer, size_t len,
770 IPV6Host& na, tpport_t& tp)
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
777 /**
778 * @param buffer memory region to write from
779 * @param len number of octets to write
780 */
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
788 /**
789 * @param timeout maximum timeout to wait, in microseconds
790 * @return whether there are packets waiting to be picked
791 */
792 inline bool
793 isPendingControl(microtimeout_t timeout)
794 { return cso->isPendingRecv(timeout); }
795
796 inline IPV6Host
797 getControlSender(tpport_t *port = NULL) const
798 { return cso->getSender(port); }
799
800 /**
801 * Receive data from the control channel/socket.
802 *
803 * @param buffer Buffer where to get data.
804 * @param len Maximum number of octets to get.
805 * @param na Source network address.
806 * @param tp Source transport port.
807 * @return Number of octets actually read.
808 **/
809 inline size_t
810 recvControl(unsigned char *buffer, size_t len,
811 IPV6Host& na, tpport_t& tp)
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
818 /**
819 * @return number of octets actually written
820 * @param buffer
821 * @param len
822 */
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
841private:
842 void
843 build(const IPV6Host& ia, tpport_t dataPort,
844 tpport_t controlPort)
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,
859 tpport_t controlPort, uint32 iface)
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
873 /**
874 * Join a multicast group.
875 *
876 * @param ia address of the multicast group
877 * @return error code from the socket operation
878 */
879 inline Socket::Error
880 joinGroup(const IPV6Multicast& ia, uint32 iface)
881 {
882 Socket::Error error = dso->setMulticast(true);
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);
889 return error;
890 }
891 error = cso->join(ia,iface);
892 if ( error ) {
893 dso->drop(ia);
894 return error;
895 }
896 return Socket::errSuccess;
897 }
898
899 /**
900 * Leave a multicast group.
901 *
902 * @param ia address of the multicast group
903 * @return error code from the socket operation
904 */
905 inline Socket::Error
906 leaveGroup(const IPV6Multicast& ia)
907 {
908 Socket::Error error = dso->setMulticast(false);
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
917 /**
918 * Set the value of the TTL field in the sent packets.
919 *
920 * @param ttl Time To Live
921 * @return error code from the socket operation
922 */
923 inline Socket::Error
924 setMcastTTL(uint8 ttl)
925 {
926 Socket::Error error = dso->setMulticast(true);
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
935 /**
936 * Ensure a port number is odd. If it is an even number, return
937 * the next lower (odd) port number.
938 *
939 * @param port number to filter
940 * @return filtered (odd) port number
941 */
942 inline tpport_t
943 odd_port(tpport_t port)
944 { return (port & 0x01)? (port) : (port - 1); }
945
946 /**
947 * Ensure a port number is even. If it is an odd number, return
948 * the next lower (even) port number.
949 *
950 * @param port number to filter
951 * @return filtered (even) port number
952 */
953 inline tpport_t
954 even_port(tpport_t port)
955 { return (port & 0x01)? (port - 1) : (port); }
956
957 tpport_t dataBasePort;
958 tpport_t controlBasePort;
959
960protected:
961 RTPDataChannel* dso;
962 RTCPChannel* cso;
963 friend class RTPSessionBaseHandler;
964};
965
966/**
967 * @class SingleThreadRTPSessionIPV6
968 *
969 * This template class adds the threading aspect to the RTPSessionBase
970 * template in one of the many possible ways. It inherits from a
971 * single execution thread that schedules sending of outgoing packets
972 * and receipt of incoming packets.
973 *
974 * @author David Sugar <dyfet@gnutelephony.org>
975 **/
976template
977<class RTPDataChannel = DualRTPUDPIPv6Channel,
978 class RTCPChannel = DualRTPUDPIPv6Channel,
979 class ServiceQueue = AVPQueue>
980class __EXPORT SingleThreadRTPSessionIPV6 :
981 protected Thread,
982 public TRTPSessionBaseIPV6<RTPDataChannel,RTCPChannel,ServiceQueue>
983{
984public:
985 SingleThreadRTPSessionIPV6(const IPV6Host& ia,
986 tpport_t dataPort = DefaultRTPDataPort,
987 tpport_t controlPort = 0,
988 int pri = 0,
989 uint32 memberssize =
990 MembershipBookkeeping::defaultMembersHashSize,
991 RTPApplication& app = defaultApplication()
992#if defined(_MSC_VER) && _MSC_VER >= 1300
993 );
994#else
995 ):
996 Thread(pri),
997 TRTPSessionBaseIPV6<RTPDataChannel,RTCPChannel,ServiceQueue>
998 (ia,dataPort,controlPort,memberssize,app)
999{ }
1000#endif
1001
1002SingleThreadRTPSessionIPV6(const IPV6Multicast& ia,
1003 tpport_t dataPort = DefaultRTPDataPort,
1004 tpport_t controlPort = 0,
1005 int pri = 0,
1006 uint32 memberssize =
1007 MembershipBookkeeping::defaultMembersHashSize,
1008 RTPApplication& app = defaultApplication(),
1009 uint32 iface = 0
1010#if defined(_MSC_VER) && _MSC_VER >= 1300
1011 );
1012#else
1013 ):
1014 Thread(pri),
1015 TRTPSessionBaseIPV6<RTPDataChannel,RTCPChannel,ServiceQueue>
1016 (ia,dataPort,controlPort,memberssize,app,iface)
1017{ }
1018#endif
1019
1020~SingleThreadRTPSessionIPV6()
1021{
1022 if (isRunning()) {
1023 disableStack(); Thread::join();
1024 }
1025}
1026
1027#if defined(_MSC_VER) && _MSC_VER >= 1300
1028virtual void startRunning();
1029#else
1030/**
1031 * Activate stack and start service thread.
1032 **/
1033void
1034startRunning()
1035{ enableStack(); Thread::start(); }
1036#endif
1037
1038
1039protected:
1040inline void enableStack(void)
1041{TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::enableStack();}
1042
1043inline void disableStack(void)
1044{TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::disableStack();}
1045
1046inline microtimeout_t getSchedulingTimeout(void)
1047{return TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::getSchedulingTimeout();}
1048
1049inline void controlReceptionService(void)
1050{TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::controlReceptionService();}
1051
1052inline void controlTransmissionService(void)
1053{TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::controlTransmissionService();}
1054
1055inline timeval getRTCPCheckInterval(void)
1056{return TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::getRTCPCheckInterval();}
1057
1058inline size_t dispatchDataPacket(void)
1059{return TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::dispatchDataPacket();}
1060
1061#if defined(_MSC_VER) && _MSC_VER >= 1300
1062virtual void run(void);
1063
1064virtual void timerTick(void);
1065
1066virtual bool isPendingData(microtimeout_t timeout);
1067#else
1068
1069virtual void timerTick(void)
1070{return;}
1071
1072virtual bool isPendingData(microtimeout_t timeout)
1073{return TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::isPendingData(timeout);}
1074
1075/**
1076 * Single runnable method for this RTP stacks, schedules
1077 * outgoing and incoming RTP data and RTCP packets.
1078 **/
1079virtual void run(void)
1080{
1081 microtimeout_t timeout = 0;
1082 while ( ServiceQueue::isActive() ) {
1083 if ( timeout < 1000 ){ // !(timeout/1000)
1084 timeout = getSchedulingTimeout();
1085 }
1086 setCancel(cancelDeferred);
1087 controlReceptionService();
1088 controlTransmissionService();
1089 setCancel(cancelImmediate);
1090 microtimeout_t maxWait =
1091 timeval2microtimeout(getRTCPCheckInterval());
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.");
1111 Thread::exit();
1112}
1113
1114#endif
1115
1116inline size_t takeInDataPacket(void)
1117{return TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::takeInDataPacket();}
1118
1119inline size_t dispatchBYE(const std::string &str)
1120{return TRTPSessionBase<RTPDataChannel,RTCPChannel,ServiceQueue>::dispatchBYE(str);}
1121};
1122
1123/**
1124 * @typedef RTPSession
1125 *
1126 * Uses two pairs of sockets for RTP data and RTCP
1127 * transmission/reception.
1128 *
1129 * @short UDP/IPv6 RTP Session scheduled by one thread of execution.
1130 **/
1131typedef SingleThreadRTPSessionIPV6<> RTPSessionIPV6;
1132
1133/**
1134 * @typedef RTPSocket
1135 *
1136 * Alias for RTPSession.
1137 **/
1138typedef RTPSessionIPV6 RTPSocketIPV6;
1139
1140/**
1141 * @typedef SymmetricRTPSession
1142 *
1143 * Uses one pair of sockets, (1) for RTP data and (2) for RTCP
1144 * transmission/reception.
1145 *
1146 * @short Symmetric UDP/IPv6 RTP session scheduled by one thread of execution.
1147 **/
1148 typedef SingleThreadRTPSessionIPV6<SymmetricRTPChannelIPV6,
1149 SymmetricRTPChannelIPV6> SymmetricRTPSessionIPV6;
1150
1151
1152#endif
1153
1154/** @}*/ // sessions
1155
1156#ifdef CCXX_NAMESPACES
1157}
1158#endif
1159
1160#endif //CCXX_RTP_RTP_H_
1161
1162/** EMACS **
1163 * Local variables:
1164 * mode: c++
1165 * c-basic-offset: 8
1166 * End:
1167 */