blob: eb12988b21a56e4cfe0a54b617fb2bc5ae7e0c71 [file] [log] [blame]
Emeric Vigier2f625822012-08-06 11:09:52 -04001// Copyright (C) 2001,2002,2003,2004 Federico Montesino Pouzols <fedemp@altern.org>.
Alexandre Lisionddd731e2014-01-31 11:50:08 -05002//
Emeric Vigier2f625822012-08-06 11:09:52 -04003// 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.
Alexandre Lisionddd731e2014-01-31 11:50:08 -05007//
Emeric Vigier2f625822012-08-06 11:09:52 -04008// 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.
Alexandre Lisionddd731e2014-01-31 11:50:08 -050012//
Emeric Vigier2f625822012-08-06 11:09:52 -040013// You should have received a copy of the GNU General Public License
Alexandre Lisionddd731e2014-01-31 11:50:08 -050014// along with this program; if not, write to the Free Software
Emeric Vigier2f625822012-08-06 11:09:52 -040015// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Alexandre Lisionddd731e2014-01-31 11:50:08 -050016//
Emeric Vigier2f625822012-08-06 11:09:52 -040017// 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
Alexandre Lisionddd731e2014-01-31 11:50:08 -050022// the GNU General Public License. This exception does not however
Emeric Vigier2f625822012-08-06 11:09:52 -040023// invalidate any other reasons why the executable file might be covered by
Alexandre Lisionddd731e2014-01-31 11:50:08 -050024// the GNU General Public License.
Emeric Vigier2f625822012-08-06 11:09:52 -040025//
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
Alexandre Lisionddd731e2014-01-31 11:50:08 -050038/**
39 * @file sources.h
Emeric Vigier2f625822012-08-06 11:09:52 -040040 *
41 * @short Sources of synchronization and participants related clases.
42 **/
43
Alexandre Lisionddd731e2014-01-31 11:50:08 -050044#ifndef CCXX_RTP_SOURCES_H_
Emeric Vigier2f625822012-08-06 11:09:52 -040045#define CCXX_RTP_SOURCES_H_
46
47#include <string>
48#include <ccrtp/rtcppkt.h>
49
Alexandre Lisionddd731e2014-01-31 11:50:08 -050050NAMESPACE_COMMONCPP
Emeric Vigier2f625822012-08-06 11:09:52 -040051
52/**
53 * @defgroup sources Participants and synchronization sources.
54 * @{
55 **/
56
57/**
58 * @class SDESItemsHolder
59 *
60 * Holds the SDES items and related information from a participant in
61 * an RTP application. This is a base class for participant classes.
62 *
63 * @author Federico Montesino Pouzols <fedemp@altern.org>
64 **/
65class __EXPORT SDESItemsHolder
66{
67public:
Alexandre Lisionddd731e2014-01-31 11:50:08 -050068 const std::string&
69 getItem(SDESItemType type) const;
Emeric Vigier2f625822012-08-06 11:09:52 -040070
Alexandre Lisionddd731e2014-01-31 11:50:08 -050071 inline const std::string&
72 getPRIVPrefix() const
73 { return sdesItems[SDESItemTypeEND]; }
Emeric Vigier2f625822012-08-06 11:09:52 -040074
Alexandre Lisionddd731e2014-01-31 11:50:08 -050075 void
76 setItem(SDESItemType item, const std::string& val);
77
78 inline void
79 setPRIVPrefix(const std::string& val)
80 { sdesItems[SDESItemTypeEND] = val; }
Emeric Vigier2f625822012-08-06 11:09:52 -040081
82protected:
Alexandre Lisionddd731e2014-01-31 11:50:08 -050083 SDESItemsHolder()
84 { }
85
86 inline virtual ~SDESItemsHolder()
87 { }
88
Emeric Vigier2f625822012-08-06 11:09:52 -040089private:
Alexandre Lisionddd731e2014-01-31 11:50:08 -050090 // SDES items for a participant.
91 // sdesItems[0] (== sdesItems[SDESItemTypeEND]) holds the prefix
92 // value for the PRIV item. The rest of entries hold the
93 // correponding SDES item value.
94 std::string sdesItems[SDESItemTypeLast + 1];
Emeric Vigier2f625822012-08-06 11:09:52 -040095};
96
Alexandre Lisionddd731e2014-01-31 11:50:08 -050097/**
Emeric Vigier2f625822012-08-06 11:09:52 -040098 * @class Participant
99 * @short A class of objects representing remote participants (RTP
100 * applications) in a multimedia session.
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500101 *
Emeric Vigier2f625822012-08-06 11:09:52 -0400102 * Any RTP socket/queue class that directly or indirectly inherits
103 * from QueueRTCPManager (and hence has RTCP support) will represent
104 * participants from which any RTP or RTCP packet has been received
105 * through a Participant object. These Participant objects are
106 * entities such as end systems (user applications, monitors, etc),
107 * RTP mixers and RTP translators.
108 *
109 * Participant objects are identified by a CNAME and provide access to
110 * all known data about the source of RTP/RTCP packets, such as the
111 * CNAME and any other SDES item. Each participant object is related
112 * to one or more synchronization objects (@see SyncSource).
113 *
114 * If an RTP application based on ccRTP receives packets from itself
115 * (for instance, it is included in the destination list), there will
116 * be a Participant object that corresponds to the "local participant"
117 * (RTPApplication) object.
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500118 *
Emeric Vigier2f625822012-08-06 11:09:52 -0400119 * @author Federico Montesino Pouzols <fedemp@altern.org>
120 *
121 * @todo implement reference counting from sources, so that when a
122 * source is destroyed, we know if the Participant should be
123 * destroyed.
124 **/
125class __EXPORT Participant : private SDESItemsHolder
126{
127public:
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500128 /**
129 * Get the value of an SDES item. For instance,
130 * getSDESItem(SDESItemTypeCNAME), return the CNAME of this
131 * Participant.
132 *
133 * @param type type of SDES item to get value of.
134 *
135 * @return value of the SDES item as a string.
136 * @retval empty string when the value is not known (no RTCP
137 * packet with the requested SDES item has been received from this
138 * source).
139 **/
140 const std::string&
141 getSDESItem(SDESItemType type) const
142 { return SDESItemsHolder::getItem(type); }
Emeric Vigier2f625822012-08-06 11:09:52 -0400143
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500144 /**
145 * Get the prefix value for the PRIV SDES item.
146 *
147 * @return PRIV SDES item prefix as a string.
148 * @retval empty string when no PRIV SDES item has been
149 * received from this source.
150 **/
151 inline const std::string&
152 getPRIVPrefix() const
153 { return SDESItemsHolder::getPRIVPrefix(); }
Emeric Vigier2f625822012-08-06 11:09:52 -0400154
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500155 /**
156 * Construct a new participant.
157 *
158 * @param cname Unique CNAME identifier.
159 **/
160 Participant(const std::string& cname);
Emeric Vigier2f625822012-08-06 11:09:52 -0400161
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500162 ~Participant();
Emeric Vigier2f625822012-08-06 11:09:52 -0400163
164private:
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500165 friend class ParticipantHandler;
Emeric Vigier2f625822012-08-06 11:09:52 -0400166
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500167 /**
168 * Set the value of a SDES item.
169 **/
170 inline void
171 setSDESItem(SDESItemType item, const std::string& val)
172 { SDESItemsHolder::setItem(item,val); }
Emeric Vigier2f625822012-08-06 11:09:52 -0400173
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500174 /**
175 * Set prefix value for the PRIV SDES item.
176 **/
177 inline void
178 setPRIVPrefix(const std::string val)
179 { SDESItemsHolder::setPRIVPrefix(val); }
Emeric Vigier2f625822012-08-06 11:09:52 -0400180};
181
182/**
183 * @class SyncSource
184 * @short Synchronization source in an RTP session
185 *
186 * Each synchronization source in an RTP session is identified by a
187 * 32-bit numeric SSRC identifier. Each SyncSource object is related
188 * to a Participant object, which can be retrieved through the
189 * getParticipant() method.
190 *
191 * @author Federico Montesino Pouzols <fedemp@altern.org>
192 **/
193class __EXPORT SyncSource
194{
195public:
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500196 /**
197 * @enum State
198 *
199 * @short Synchronization source states during an RTP session.
200 *
201 * In general, new synchronization sources are not considered
202 * valid until multiple valid data packets or a valid RTCP
203 * compound packet has been received from the new source (@see
204 * IncomingDataQueue::setMinValidPacketSequence()). Thus, the
205 * source will probably be in statePrevalid before reaching
206 * one of the two states that indicate a valid source:
207 * stateActive and stateInactive.
208 *
209 * A valid participant is in stateActive state if RTP and/or
210 * RTCP packets are currently being received from it. If,
211 * after a small number of RTCP report intervals (see
212 * IncomingDataQueue::setSourceExpirationPeriod() ), no
213 * packets are received, it will reach the stateInactive
214 * state. If, after a small number of RTCP report intervals,
215 * no packet is received from an inactive source, it will be
216 * deleted.
217 *
218 * If RTCP is being used, after receiving a BYE RTCP packet
219 * from a synchronization source, it will reach the
220 * stateLeaving state and will be deleted after a delay (see
221 * QueueRTCPManager::setLeavingDelay()).
222 *
223 * Sources in statePrevalid and stateLeaving are not counted
224 * for the number of session members estimation.
225 **/
226 typedef enum {
227 stateUnknown, ///< No valid packet has been received.
228 statePrevalid, ///< Some packets have been
229 ///received, but source validity not
230 ///yet guaranteed.
231 stateActive, ///< We currently receive packets
232 ///(data or control) from this source.
233 stateInactive, ///< Was active in the near past but
234 ///no packet from this source has
235 ///been received lately.
236 stateLeaving ///< An RTCP BYE has been received
237 ///from the source.
238 } State;
Emeric Vigier2f625822012-08-06 11:09:52 -0400239
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500240 /**
241 * @param ssrc SSRC identifier of the source, unique in each
242 * session.
243 */
244 SyncSource(uint32 ssrc);
Emeric Vigier2f625822012-08-06 11:09:52 -0400245
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500246 ~SyncSource();
Emeric Vigier2f625822012-08-06 11:09:52 -0400247
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500248 State
249 getState() const
250 { return state; }
Emeric Vigier2f625822012-08-06 11:09:52 -0400251
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500252 /**
253 * Whether this source sends RTP data packets.
254 **/
255 bool isSender() const
256 { return activeSender; }
Emeric Vigier2f625822012-08-06 11:09:52 -0400257
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500258 uint32 getID() const
259 { return SSRC; }
Emeric Vigier2f625822012-08-06 11:09:52 -0400260
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500261 /**
262 * Get the participant this synchronization source is
263 * asociated to.
264 *
265 * @retval NULL if the stack has not been yet able to identify
266 * the participant this source is associated to.
267 **/
268 inline Participant*
269 getParticipant() const
270 { return participant; }
Emeric Vigier2f625822012-08-06 11:09:52 -0400271
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500272 tpport_t getDataTransportPort() const
273 { return dataTransportPort; }
Emeric Vigier2f625822012-08-06 11:09:52 -0400274
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500275 tpport_t getControlTransportPort() const
276 { return controlTransportPort; }
277
278 const InetAddress& getNetworkAddress() const
279 { return networkAddress; }
Emeric Vigier2f625822012-08-06 11:09:52 -0400280
281protected:
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500282 /**
283 * @param source The RTPSource object being copied
284 */
285 SyncSource(const SyncSource& source);
Emeric Vigier2f625822012-08-06 11:09:52 -0400286
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500287 SyncSource&
288 operator=(const SyncSource& source);
Emeric Vigier2f625822012-08-06 11:09:52 -0400289
290private:
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500291 friend class SyncSourceHandler;
Emeric Vigier2f625822012-08-06 11:09:52 -0400292
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500293 inline void
294 setState(State st)
295 { state = st; }
Emeric Vigier2f625822012-08-06 11:09:52 -0400296
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500297 /**
298 * Mark this source as an active sender.
299 **/
300 inline void
301 setSender(bool active)
302 { activeSender = active; }
Emeric Vigier2f625822012-08-06 11:09:52 -0400303
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500304 inline void
305 setParticipant(Participant& p)
306 { participant = &p; }
Emeric Vigier2f625822012-08-06 11:09:52 -0400307
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500308 void setDataTransportPort(tpport_t p)
309 { dataTransportPort = p; }
Emeric Vigier2f625822012-08-06 11:09:52 -0400310
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500311 void setControlTransportPort(tpport_t p)
312 { controlTransportPort = p; }
Emeric Vigier2f625822012-08-06 11:09:52 -0400313
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500314 void setNetworkAddress(InetAddress addr)
315 { networkAddress = addr; }
Emeric Vigier2f625822012-08-06 11:09:52 -0400316
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500317 inline void
318 setLink(void *l)
319 { link = l; }
Emeric Vigier2f625822012-08-06 11:09:52 -0400320
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500321 void *getLink() const
322 { return link; }
323
324 // validity state of this source
325 State state;
326 // 32-bit SSRC identifier.
327 uint32 SSRC;
328 // A valid source not always is active
Emeric Vigier2f625822012-08-06 11:09:52 -0400329 bool activeSender;
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500330 // The corresponding participant.
331 Participant* participant;
Emeric Vigier2f625822012-08-06 11:09:52 -0400332
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500333 // Network protocol address for data and control connection
334 // (both are assumed to be the same).
335 InetAddress networkAddress;
336 tpport_t dataTransportPort;
337 tpport_t controlTransportPort;
Emeric Vigier2f625822012-08-06 11:09:52 -0400338
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500339 // Pointer to the SyncSourceLink or similar object in the
340 // service queue. Saves a lot of searches in the membership
341 // table.
342 void* link;
Emeric Vigier2f625822012-08-06 11:09:52 -0400343};
344
345/**
346 * @class RTPApplication
347 * @short An RTP application, holding identifying RTCP SDES item
348 * values. Represents local participants.
349 *
350 * An application in the context of RTP: an entity that has a CNAME
351 * (unique identifier in the form of user\@host.domain) as well as
352 * other RTCP SDES items (such as NAME or TOOL), and may open a number
353 * of RTP sessions. Each application is a different source of
354 * synchronization (with a potentially diferent SSRC identifier) in
355 * each RTP session it participates. All the sources of
356 * synchronization from a participant are tied together by means of
357 * the CNAME.
358 *
359 * The definition of this class allows applications based on ccRTP to
360 * implement several "RTP applications" in the same process. Each
361 * object of this class represents a local participant.
362 *
363 * @author Federico Montesino Pouzols <fedemp@altern.org>
364 **/
365class __EXPORT RTPApplication : private SDESItemsHolder
366{
367private:
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500368 struct ParticipantLink;
Emeric Vigier2f625822012-08-06 11:09:52 -0400369
370public:
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500371 /**
372 * Create a new RTP application. If the CNAME string provided
373 * has zero length, it is guessed from the user and machine
374 * name.
375 *
376 * @param cname Local participant canonical name.
377 **/
378 RTPApplication(const std::string& cname);
Emeric Vigier2f625822012-08-06 11:09:52 -0400379
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500380 ~RTPApplication();
Emeric Vigier2f625822012-08-06 11:09:52 -0400381
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500382 inline void
383 setSDESItem(SDESItemType item, const std::string& val)
384 { SDESItemsHolder::setItem(item,val); }
Emeric Vigier2f625822012-08-06 11:09:52 -0400385
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500386 inline void
387 setPRIVPrefix(const std::string& val)
388 { SDESItemsHolder::setPRIVPrefix(val); }
Emeric Vigier2f625822012-08-06 11:09:52 -0400389
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500390 const std::string&
391 getSDESItem(SDESItemType item) const
392 { return SDESItemsHolder::getItem(item); }
Emeric Vigier2f625822012-08-06 11:09:52 -0400393
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500394 inline const std::string&
395 getPRIVPrefix() const
396 { return SDESItemsHolder::getPRIVPrefix(); }
Emeric Vigier2f625822012-08-06 11:09:52 -0400397
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500398 /**
399 * Iterator through the list of participants in this
400 * session. Somehow resembles and standard const_iterator
401 **/
402 class ParticipantsIterator
403 {
404 public:
405 typedef std::forward_iterator_tag iterator_category;
406 typedef Participant value_type;
407 typedef std::ptrdiff_t difference_type;
408 typedef const Participant* pointer;
409 typedef const Participant& reference;
Emeric Vigier2f625822012-08-06 11:09:52 -0400410
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500411 ParticipantsIterator(ParticipantLink* p = NULL) :
412 link(p)
413 { }
Emeric Vigier2f625822012-08-06 11:09:52 -0400414
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500415 ParticipantsIterator(const ParticipantsIterator& pi) :
416 link(pi.link)
417 { }
Emeric Vigier2f625822012-08-06 11:09:52 -0400418
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500419 reference operator*() const
420 { return *(link->getParticipant()); }
Emeric Vigier2f625822012-08-06 11:09:52 -0400421
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500422 pointer operator->() const
423 { return link->getParticipant(); }
Emeric Vigier2f625822012-08-06 11:09:52 -0400424
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500425 ParticipantsIterator& operator++() {
426 link = link->getNext();
427 return *this;
428 }
Emeric Vigier2f625822012-08-06 11:09:52 -0400429
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500430 ParticipantsIterator operator++(int) {
431 ParticipantsIterator result(*this);
432 ++(*this);
433 return result;
434 }
435 friend bool operator==(const ParticipantsIterator& l,
436 const ParticipantsIterator& r)
437 { return l.link == r.link; }
Emeric Vigier2f625822012-08-06 11:09:52 -0400438
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500439 friend bool operator!=(const ParticipantsIterator& l,
440 const ParticipantsIterator& r)
441 { return l.link != r.link; }
442 private:
443 ParticipantLink *link;
444 };
Emeric Vigier2f625822012-08-06 11:09:52 -0400445
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500446 ParticipantsIterator begin()
447 { return ParticipantsIterator(firstPart); }
Emeric Vigier2f625822012-08-06 11:09:52 -0400448
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500449 ParticipantsIterator end()
450 { return ParticipantsIterator(NULL); }
451
452 const Participant*
453 getParticipant(const std::string& cname) const;
454
Emeric Vigier2f625822012-08-06 11:09:52 -0400455private:
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500456 friend class ApplicationHandler;
Emeric Vigier2f625822012-08-06 11:09:52 -0400457
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500458 struct ParticipantLink {
459 ParticipantLink(Participant& p,
460 ParticipantLink* l) :
461 participant(&p), next(l)
462 { }
463 inline ~ParticipantLink() { delete participant; }
464 inline Participant* getParticipant() { return participant; }
465 inline ParticipantLink* getPrev() { return prev; }
466 inline ParticipantLink* getNext() { return next; }
467 inline void setPrev(ParticipantLink* l) { prev = l; }
468 inline void setNext(ParticipantLink* l) { next = l; }
469 Participant* participant;
470 ParticipantLink* next, *prev;
471 };
Emeric Vigier2f625822012-08-06 11:09:52 -0400472
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500473 void
474 addParticipant(Participant& part);
Emeric Vigier2f625822012-08-06 11:09:52 -0400475
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500476 void
477 removeParticipant(ParticipantLink* part);
Emeric Vigier2f625822012-08-06 11:09:52 -0400478
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500479 /**
480 * Find out the local CNAME as user\@host and store it as part
481 * of the internal state of this class.
482 */
483 void
484 findCNAME();
Emeric Vigier2f625822012-08-06 11:09:52 -0400485
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500486 /// Hash table with sources of RTP and RTCP packets.
487 static const size_t defaultParticipantsNum;
488 Participant** participants;
489 /// List of participants, ordered from older to newer.
490 ParticipantLink* firstPart, * lastPart;
Emeric Vigier2f625822012-08-06 11:09:52 -0400491};
492
493/**
494 * Get the RTPApplication object for the "default" application (the
495 * only one used by common applications -those that only implement one
496 * "RTP application"). Note that this application object differs from
497 * all the others that may be defined in that it is automatically
498 * constructed by the ccRTP stack and its CNAME is automatically
499 * assigned (as user\@host), whereas the other application objects'
500 * CNAME is provided to its constructor.
501 **/
502__EXPORT RTPApplication& defaultApplication();
503
504/** @}*/ // sources
505
Alexandre Lisionddd731e2014-01-31 11:50:08 -0500506END_NAMESPACE
Emeric Vigier2f625822012-08-06 11:09:52 -0400507
508#endif //CCXX_RTP_SOURCES_H_
509
510/** EMACS **
511 * Local variables:
512 * mode: c++
513 * c-basic-offset: 8
514 * End:
515 */