1 /*
2 * localep.cxx
3 *
4 * Local EndPoint/Connection.
5 *
6 * Open Phone Abstraction Library (OPAL)
7 *
8 * Copyright (c) 2008 Vox Lucida Pty. Ltd.
9 *
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
14 *
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * The Original Code is Open Phone Abstraction Library.
21 *
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
23 *
24 * Contributor(s): ______________________________________.
25 *
26 * $Revision: 28040 $
27 * $Author: rjongbloed $
28 * $Date: 2012-07-16 01:23:59 -0500 (Mon, 16 Jul 2012) $
29 */
30
31 #include <ptlib.h>
32
33 #ifdef __GNUC__
34 #pragma implementation "localep.h"
35 #endif
36
37 #include <opal/buildopts.h>
38
39 #include <opal/localep.h>
40 #include <opal/call.h>
41
42
43 #define new PNEW
44
45
46 /////////////////////////////////////////////////////////////////////////////
47
OpalLocalEndPoint(OpalManager & mgr,const char * prefix)48 OpalLocalEndPoint::OpalLocalEndPoint(OpalManager & mgr, const char * prefix)
49 : OpalEndPoint(mgr, prefix, CanTerminateCall)
50 , m_deferredAlerting(false)
51 , m_deferredAnswer(false)
52 , m_defaultAudioSynchronicity(e_Synchronous)
53 , m_defaultVideoSourceSynchronicity(e_Synchronous)
54 {
55 PTRACE(3, "LocalEP\tCreated endpoint.");
56 }
57
58
~OpalLocalEndPoint()59 OpalLocalEndPoint::~OpalLocalEndPoint()
60 {
61 PTRACE(4, "LocalEP\tDeleted endpoint.");
62 }
63
64
GetMediaFormats() const65 OpalMediaFormatList OpalLocalEndPoint::GetMediaFormats() const
66 {
67 return manager.GetCommonMediaFormats(false, true);
68 }
69
70
MakeConnection(OpalCall & call,const PString &,void * userData,unsigned int options,OpalConnection::StringOptions * stringOptions)71 PSafePtr<OpalConnection> OpalLocalEndPoint::MakeConnection(OpalCall & call,
72 const PString & /*remoteParty*/,
73 void * userData,
74 unsigned int options,
75 OpalConnection::StringOptions * stringOptions)
76 {
77 return AddConnection(CreateConnection(call, userData, options, stringOptions));
78 }
79
80
CreateConnection(OpalCall & call,void * userData,unsigned options,OpalConnection::StringOptions * stringOptions)81 OpalLocalConnection * OpalLocalEndPoint::CreateConnection(OpalCall & call,
82 void * userData,
83 unsigned options,
84 OpalConnection::StringOptions * stringOptions)
85 {
86 return new OpalLocalConnection(call, *this, userData, options, stringOptions);
87 }
88
89
OnOutgoingSetUp(const OpalLocalConnection &)90 bool OpalLocalEndPoint::OnOutgoingSetUp(const OpalLocalConnection & /*connection*/)
91 {
92 return true;
93 }
94
95
OnOutgoingCall(const OpalLocalConnection &)96 bool OpalLocalEndPoint::OnOutgoingCall(const OpalLocalConnection & /*connection*/)
97 {
98 return true;
99 }
100
101
OnIncomingCall(OpalLocalConnection & connection)102 bool OpalLocalEndPoint::OnIncomingCall(OpalLocalConnection & connection)
103 {
104 if (!m_deferredAnswer)
105 connection.AcceptIncoming();
106 return true;
107 }
108
109
AlertingIncomingCall(const PString & token,OpalConnection::StringOptions * options)110 bool OpalLocalEndPoint::AlertingIncomingCall(const PString & token, OpalConnection::StringOptions * options)
111 {
112 PSafePtr<OpalLocalConnection> connection = GetLocalConnectionWithLock(token, PSafeReadOnly);
113 if (connection == NULL) {
114 PTRACE(2, "LocalEP\tCould not find connection using token \"" << token << '"');
115 return false;
116 }
117
118 if (options != NULL)
119 connection->SetStringOptions(*options, false);
120
121 connection->AlertingIncoming();
122 return true;
123 }
124
125
AcceptIncomingCall(const PString & token,OpalConnection::StringOptions * options)126 bool OpalLocalEndPoint::AcceptIncomingCall(const PString & token, OpalConnection::StringOptions * options)
127 {
128 PSafePtr<OpalLocalConnection> connection = GetLocalConnectionWithLock(token, PSafeReadOnly);
129 if (connection == NULL) {
130 PTRACE(2, "LocalEP\tCould not find connection using token \"" << token << '"');
131 return false;
132 }
133
134 if (options != NULL)
135 connection->SetStringOptions(*options, false);
136
137 connection->AcceptIncoming();
138 return true;
139 }
140
141
RejectIncomingCall(const PString & token,const OpalConnection::CallEndReason & reason)142 bool OpalLocalEndPoint::RejectIncomingCall(const PString & token, const OpalConnection::CallEndReason & reason)
143 {
144 PSafePtr<OpalLocalConnection> connection = GetLocalConnectionWithLock(token, PSafeReadOnly);
145 if (connection == NULL)
146 return false;
147
148 connection->Release(reason);
149 return true;
150 }
151
152
OnUserInput(const OpalLocalConnection &,const PString &)153 bool OpalLocalEndPoint::OnUserInput(const OpalLocalConnection &, const PString &)
154 {
155 return true;
156 }
157
158
OnReadMediaFrame(const OpalLocalConnection &,const OpalMediaStream &,RTP_DataFrame &)159 bool OpalLocalEndPoint::OnReadMediaFrame(const OpalLocalConnection & /*connection*/,
160 const OpalMediaStream & /*mediaStream*/,
161 RTP_DataFrame & /*frame*/)
162 {
163 return false;
164 }
165
166
OnWriteMediaFrame(const OpalLocalConnection &,const OpalMediaStream &,RTP_DataFrame &)167 bool OpalLocalEndPoint::OnWriteMediaFrame(const OpalLocalConnection & /*connection*/,
168 const OpalMediaStream & /*mediaStream*/,
169 RTP_DataFrame & /*frame*/)
170 {
171 return false;
172 }
173
174
OnReadMediaData(const OpalLocalConnection &,const OpalMediaStream &,void * data,PINDEX size,PINDEX & length)175 bool OpalLocalEndPoint::OnReadMediaData(const OpalLocalConnection & /*connection*/,
176 const OpalMediaStream & /*mediaStream*/,
177 void * data,
178 PINDEX size,
179 PINDEX & length)
180 {
181 memset(data, 0, size);
182 length = size;
183 return true;
184 }
185
186
OnWriteMediaData(const OpalLocalConnection &,const OpalMediaStream &,const void *,PINDEX length,PINDEX & written)187 bool OpalLocalEndPoint::OnWriteMediaData(const OpalLocalConnection & /*connection*/,
188 const OpalMediaStream & /*mediaStream*/,
189 const void * /*data*/,
190 PINDEX length,
191 PINDEX & written)
192 {
193 written = length;
194 return true;
195 }
196
197
198 OpalLocalEndPoint::Synchronicity
GetSynchronicity(const OpalMediaFormat & mediaFormat,bool isSource) const199 OpalLocalEndPoint::GetSynchronicity(const OpalMediaFormat & mediaFormat,
200 bool isSource) const
201 {
202 if (mediaFormat.GetMediaType() == OpalMediaType::Audio())
203 return m_defaultAudioSynchronicity;
204
205 if (isSource && mediaFormat.GetMediaType() == OpalMediaType::Audio())
206 return m_defaultVideoSourceSynchronicity;
207
208 return e_Asynchronous;
209 }
210
211
212 /////////////////////////////////////////////////////////////////////////////
213
OpalLocalConnection(OpalCall & call,OpalLocalEndPoint & ep,void * userData,unsigned options,OpalConnection::StringOptions * stringOptions,char tokenPrefix)214 OpalLocalConnection::OpalLocalConnection(OpalCall & call,
215 OpalLocalEndPoint & ep,
216 void * userData,
217 unsigned options,
218 OpalConnection::StringOptions * stringOptions,
219 char tokenPrefix)
220 : OpalConnection(call, ep, ep.GetManager().GetNextToken(tokenPrefix), options, stringOptions)
221 , endpoint(ep)
222 , m_userData(userData)
223 {
224 #if OPAL_PTLIB_DTMF
225 m_sendInBandDTMF = m_detectInBandDTMF = false;
226 #endif
227 PTRACE(4, "LocalCon\tCreated connection with token \"" << callToken << '"');
228 }
229
230
~OpalLocalConnection()231 OpalLocalConnection::~OpalLocalConnection()
232 {
233 PTRACE(4, "LocalCon\tDeleted connection.");
234 }
235
236
OnApplyStringOptions()237 void OpalLocalConnection::OnApplyStringOptions()
238 {
239 OpalConnection::OnApplyStringOptions();
240
241 PSafePtr<OpalConnection> otherConnection = GetOtherPartyConnection();
242 if (otherConnection != NULL && dynamic_cast<OpalLocalConnection*>(&*otherConnection) == NULL) {
243 PTRACE(4, "LocalCon\tPassing string options to " << *otherConnection);
244 otherConnection->SetStringOptions(m_stringOptions, false);
245 }
246 }
247
248
SetUpConnection()249 PBoolean OpalLocalConnection::SetUpConnection()
250 {
251 originating = true;
252
253 // Check if we are A-Party in thsi call, so need to do things differently
254 if (ownerCall.GetConnection(0) == this) {
255 SetPhase(SetUpPhase);
256 if (!OnIncomingConnection(0, NULL)) {
257 Release(EndedByCallerAbort);
258 return false;
259 }
260
261 PTRACE(3, "LocalCon\tOutgoing call routed to " << ownerCall.GetPartyB() << " for " << *this);
262 if (!OnOutgoingSetUp() || !ownerCall.OnSetUp(*this)) {
263 Release(EndedByNoAccept);
264 return false;
265 }
266 }
267 else if (ownerCall.IsEstablished()) {
268 PTRACE(3, "LocalCon\tTransfer of connection in call " << ownerCall);
269 OnApplyStringOptions();
270 AutoStartMediaStreams();
271 OnConnectedInternal();
272 }
273 else {
274 PTRACE(3, "LocalCon\tIncoming call from " << remotePartyName);
275
276 OnApplyStringOptions();
277
278 if (!OnIncoming()) {
279 Release(EndedByLocalBusy);
280 return false;
281 }
282
283 if (!endpoint.IsDeferredAlerting())
284 AlertingIncoming();
285 }
286
287 return true;
288 }
289
290
SetAlerting(const PString & calleeName,PBoolean)291 PBoolean OpalLocalConnection::SetAlerting(const PString & calleeName, PBoolean)
292 {
293 PTRACE(3, "LocalCon\tSetAlerting(" << calleeName << ')');
294 SetPhase(AlertingPhase);
295 remotePartyName = calleeName;
296 return endpoint.OnOutgoingCall(*this);
297 }
298
299
SetConnected()300 PBoolean OpalLocalConnection::SetConnected()
301 {
302 PTRACE(3, "LocalCon\tSetConnected()");
303
304 if (GetMediaStream(PString::Empty(), true) == NULL)
305 AutoStartMediaStreams(); // if no media streams, try and start them
306
307 return OpalConnection::SetConnected();
308 }
309
CreateMediaStream(const OpalMediaFormat & mediaFormat,unsigned sessionID,PBoolean isSource)310 OpalMediaStream * OpalLocalConnection::CreateMediaStream(const OpalMediaFormat & mediaFormat,
311 unsigned sessionID,
312 PBoolean isSource)
313 {
314 return new OpalLocalMediaStream(*this, mediaFormat, sessionID, isSource,
315 endpoint.GetSynchronicity(mediaFormat, isSource));
316 }
317
318
OpenMediaStream(const OpalMediaFormat & mediaFormat,unsigned sessionID,bool isSource)319 OpalMediaStreamPtr OpalLocalConnection::OpenMediaStream(const OpalMediaFormat & mediaFormat, unsigned sessionID, bool isSource)
320 {
321 #if OPAL_VIDEO
322 if ( isSource &&
323 mediaFormat.GetMediaType() == OpalMediaType::Video() &&
324 !ownerCall.IsEstablished() &&
325 !endpoint.GetManager().CanAutoStartTransmitVideo()) {
326 PTRACE(3, "LocalCon\tOpenMediaStream auto start disabled, refusing video open");
327 return NULL;
328 }
329 #endif
330
331 return OpalConnection::OpenMediaStream(mediaFormat, sessionID, isSource);
332 }
333
334
SendUserInputString(const PString & value)335 bool OpalLocalConnection::SendUserInputString(const PString & value)
336 {
337 PTRACE(3, "LocalCon\tSendUserInputString(" << value << ')');
338 return endpoint.OnUserInput(*this, value);
339 }
340
341
OnOutgoingSetUp()342 bool OpalLocalConnection::OnOutgoingSetUp()
343 {
344 return endpoint.OnOutgoingSetUp(*this);
345 }
346
347
OnOutgoing()348 bool OpalLocalConnection::OnOutgoing()
349 {
350 return endpoint.OnOutgoingCall(*this);
351 }
352
353
OnIncoming()354 bool OpalLocalConnection::OnIncoming()
355 {
356 return endpoint.OnIncomingCall(*this);
357 }
358
359
AlertingIncoming()360 void OpalLocalConnection::AlertingIncoming()
361 {
362 if (LockReadWrite()) {
363 if (GetPhase() < AlertingPhase) {
364 SetPhase(AlertingPhase);
365 OnAlerting();
366 }
367 UnlockReadWrite();
368 }
369 }
370
371
AcceptIncoming()372 void OpalLocalConnection::AcceptIncoming()
373 {
374 if (LockReadWrite()) {
375 AlertingIncoming();
376 AutoStartMediaStreams();
377 OnConnectedInternal();
378 UnlockReadWrite();
379 }
380 }
381
382
383 /////////////////////////////////////////////////////////////////////////////
384
OpalLocalMediaStream(OpalLocalConnection & connection,const OpalMediaFormat & mediaFormat,unsigned sessionID,bool isSource,OpalLocalEndPoint::Synchronicity synchronicity)385 OpalLocalMediaStream::OpalLocalMediaStream(OpalLocalConnection & connection,
386 const OpalMediaFormat & mediaFormat,
387 unsigned sessionID,
388 bool isSource,
389 OpalLocalEndPoint::Synchronicity synchronicity)
390 : OpalMediaStream(connection, mediaFormat, sessionID, isSource)
391 , OpalMediaStreamPacing(mediaFormat)
392 , m_synchronicity(synchronicity)
393 {
394 }
395
396
ReadPacket(RTP_DataFrame & frame)397 PBoolean OpalLocalMediaStream::ReadPacket(RTP_DataFrame & frame)
398 {
399 if (!isOpen)
400 return false;
401
402 OpalLocalEndPoint & ep = dynamic_cast<OpalLocalEndPoint &>(connection.GetEndPoint());
403 OpalLocalConnection & conn = dynamic_cast<OpalLocalConnection &>(connection);
404 if (ep.OnReadMediaFrame(conn, *this, frame))
405 return true;
406
407 return OpalMediaStream::ReadPacket(frame);
408 }
409
410
WritePacket(RTP_DataFrame & frame)411 PBoolean OpalLocalMediaStream::WritePacket(RTP_DataFrame & frame)
412 {
413 if (!isOpen)
414 return false;
415
416 OpalLocalEndPoint & ep = dynamic_cast<OpalLocalEndPoint &>(connection.GetEndPoint());
417 OpalLocalConnection & conn = dynamic_cast<OpalLocalConnection &>(connection);
418 if (ep.OnWriteMediaFrame(conn, *this, frame))
419 return true;
420
421 return OpalMediaStream::WritePacket(frame);
422 }
423
424
ReadData(BYTE * data,PINDEX size,PINDEX & length)425 PBoolean OpalLocalMediaStream::ReadData(BYTE * data, PINDEX size, PINDEX & length)
426 {
427 OpalLocalEndPoint & ep = dynamic_cast<OpalLocalEndPoint &>(connection.GetEndPoint());
428 OpalLocalConnection & conn = dynamic_cast<OpalLocalConnection &>(connection);
429 if (!ep.OnReadMediaData(conn, *this, data, size, length))
430 return false;
431
432 if (m_synchronicity == OpalLocalEndPoint::e_SimulateSyncronous)
433 Pace(true, size, marker);
434 return true;
435 }
436
437
WriteData(const BYTE * data,PINDEX length,PINDEX & written)438 PBoolean OpalLocalMediaStream::WriteData(const BYTE * data, PINDEX length, PINDEX & written)
439 {
440 OpalLocalEndPoint & ep = dynamic_cast<OpalLocalEndPoint &>(connection.GetEndPoint());
441 OpalLocalConnection & conn = dynamic_cast<OpalLocalConnection &>(connection);
442 if (!ep.OnWriteMediaData(conn, *this, data, length, written))
443 return false;
444
445 if (m_synchronicity == OpalLocalEndPoint::e_SimulateSyncronous)
446 Pace(false, written, marker);
447 return true;
448 }
449
450
IsSynchronous() const451 PBoolean OpalLocalMediaStream::IsSynchronous() const
452 {
453 return m_synchronicity != OpalLocalEndPoint::e_Asynchronous;
454 }
455
456
457 /////////////////////////////////////////////////////////////////////////////
458