~ubuntu-branches/ubuntu/saucy/resiprocate/saucy-proposed

« back to all changes in this revision

Viewing changes to resip/recon/ConversationManager.cxx

  • Committer: Package Import Robot
  • Author(s): Daniel Pocock
  • Date: 2012-05-17 19:29:59 UTC
  • Revision ID: package-import@ubuntu.com-20120517192959-vv00m77isztdy64q
Tags: upstream-1.8.2
ImportĀ upstreamĀ versionĀ 1.8.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// sipX includes
 
2
#include <sdp/SdpCodec.h>
 
3
#include <os/OsConfigDb.h>
 
4
#include <mp/MpCodecFactory.h>
 
5
#include <mp/MprBridge.h>
 
6
#include <mp/MpResourceTopology.h>
 
7
#include <mi/CpMediaInterfaceFactoryFactory.h>
 
8
#include <mi/CpMediaInterface.h>
 
9
 
 
10
// resip includes
 
11
#include <rutil/Log.hxx>
 
12
#include <rutil/Logger.hxx>
 
13
#include <rutil/Lock.hxx>
 
14
#include <rutil/Random.hxx>
 
15
#include <resip/dum/DialogUsageManager.hxx>
 
16
#include <resip/dum/ClientInviteSession.hxx>
 
17
#include <resip/dum/ServerInviteSession.hxx>
 
18
#include <resip/dum/ClientSubscription.hxx>
 
19
#include <resip/dum/ServerOutOfDialogReq.hxx>
 
20
 
 
21
#include "ReconSubsystem.hxx"
 
22
#include "UserAgent.hxx"
 
23
#include "ConversationManager.hxx"
 
24
#include "ConversationManagerCmds.hxx"
 
25
#include "Conversation.hxx"
 
26
#include "Participant.hxx"
 
27
#include "BridgeMixer.hxx"
 
28
#include "DtmfEvent.hxx"
 
29
#include <rutil/WinLeakCheck.hxx>
 
30
 
 
31
#if defined(WIN32) && !defined(__GNUC__)
 
32
#pragma warning( disable : 4355 )
 
33
#endif
 
34
 
 
35
using namespace recon;
 
36
using namespace resip;
 
37
using namespace std;
 
38
 
 
39
#define RESIPROCATE_SUBSYSTEM ReconSubsystem::RECON
 
40
 
 
41
ConversationManager::ConversationManager(bool localAudioEnabled, MediaInterfaceMode mediaInterfaceMode) 
 
42
: mUserAgent(0),
 
43
  mCurrentConversationHandle(1),
 
44
  mCurrentParticipantHandle(1),
 
45
  mLocalAudioEnabled(localAudioEnabled),
 
46
  mMediaInterfaceMode(mediaInterfaceMode),
 
47
  mMediaFactory(0),
 
48
  mBridgeMixer(0),
 
49
  mSipXTOSValue(0)
 
50
{
 
51
#ifdef _DEBUG
 
52
   UtlString codecPaths[] = {".", "../../../../sipXtapi/sipXmediaLib/bin"};
 
53
#else
 
54
   UtlString codecPaths[] = {"."};
 
55
#endif
 
56
   int codecPathsNum = sizeof(codecPaths)/sizeof(codecPaths[0]);
 
57
   OsStatus rc = CpMediaInterfaceFactory::addCodecPaths(codecPathsNum, codecPaths);
 
58
   assert(OS_SUCCESS == rc);
 
59
 
 
60
   if(mMediaInterfaceMode == sipXConversationMediaInterfaceMode)
 
61
   {
 
62
      OsConfigDb sipXconfig;
 
63
      sipXconfig.set("PHONESET_MAX_ACTIVE_CALLS_ALLOWED",300);  // This controls the maximum number of flowgraphs allowed - default is 16
 
64
      mMediaFactory = sipXmediaFactoryFactory(&sipXconfig, 0, 0, 0, mLocalAudioEnabled);
 
65
   }
 
66
   else
 
67
   {
 
68
      mMediaFactory = sipXmediaFactoryFactory(NULL, 0, 0, 0, mLocalAudioEnabled);
 
69
   }
 
70
 
 
71
   // Create MediaInterface
 
72
   MpCodecFactory *pCodecFactory = MpCodecFactory::getMpCodecFactory();
 
73
   unsigned int count = 0;
 
74
   const MppCodecInfoV1_1 **codecInfoArray;
 
75
   pCodecFactory->getCodecInfoArray(count, codecInfoArray);
 
76
 
 
77
   if(count == 0)
 
78
   {
 
79
      ErrLog( << "No codec plugins found.  Cannot start.");
 
80
      exit(-1);
 
81
   }
 
82
 
 
83
   InfoLog( << "Loaded codecs are:");
 
84
   for(unsigned int i =0; i < count; i++)
 
85
   {
 
86
      InfoLog( << "  " << codecInfoArray[i]->codecName 
 
87
               << "(" << codecInfoArray[i]->codecManufacturer << ") " 
 
88
               << codecInfoArray[i]->codecVersion 
 
89
               << " MimeSubtype: " << codecInfoArray[i]->mimeSubtype 
 
90
               << " Rate: " << codecInfoArray[i]->sampleRate
 
91
               << " Channels: " << codecInfoArray[i]->numChannels);
 
92
   }
 
93
 
 
94
   if(mMediaInterfaceMode == sipXGlobalMediaInterfaceMode)
 
95
   {
 
96
      createMediaInterfaceAndMixer(mLocalAudioEnabled /* giveFocus?*/,    // This is the one and only media interface - give it focus
 
97
                                   0,
 
98
                                   mMediaInterface, 
 
99
                                   &mBridgeMixer);      
 
100
   }
 
101
}
 
102
 
 
103
ConversationManager::~ConversationManager()
 
104
{
 
105
   assert(mConversations.empty());
 
106
   assert(mParticipants.empty());
 
107
   delete mBridgeMixer;
 
108
   if(mMediaInterface) mMediaInterface.reset();  // Make sure inteface is destroyed before factory
 
109
   sipxDestroyMediaFactoryFactory();
 
110
}
 
111
 
 
112
void
 
113
ConversationManager::setUserAgent(UserAgent* userAgent)
 
114
{
 
115
   mUserAgent = userAgent;
 
116
 
 
117
   // Note: This is not really required, since we are managing the port allocation - but no harm done
 
118
   // Really not needed now - since FlowManager integration
 
119
   //mMediaFactory->getFactoryImplementation()->setRtpPortRange(mUserAgent->getUserAgentMasterProfile()->rtpPortRangeMin(), 
 
120
   //                                                           mUserAgent->getUserAgentMasterProfile()->rtpPortRangeMax());
 
121
 
 
122
   initRTPPortFreeList();
 
123
}
 
124
 
 
125
void
 
126
ConversationManager::shutdown()
 
127
{
 
128
   // Destroy each Conversation
 
129
   ConversationMap tempConvs = mConversations;  // Create copy for safety, since ending conversations can immediately remove themselves from map
 
130
   ConversationMap::iterator i;
 
131
   for(i = tempConvs.begin(); i != tempConvs.end(); i++)
 
132
   {
 
133
      InfoLog(<< "Destroying conversation: " << i->second->getHandle());
 
134
      i->second->destroy();
 
135
   }
 
136
 
 
137
   // End each Participant
 
138
   ParticipantMap tempParts = mParticipants;  
 
139
   ParticipantMap::iterator j;
 
140
   int j2=0;
 
141
   for(j = tempParts.begin(); j != tempParts.end(); j++, j2++)
 
142
   {
 
143
      InfoLog(<< "Destroying participant: " << j->second->getParticipantHandle());
 
144
      j->second->destroyParticipant();
 
145
   }
 
146
}
 
147
 
 
148
ConversationHandle 
 
149
ConversationManager::createConversation(bool broadcastOnly)
 
150
{
 
151
   ConversationHandle convHandle = getNewConversationHandle();
 
152
 
 
153
   CreateConversationCmd* cmd = new CreateConversationCmd(this, convHandle, broadcastOnly);
 
154
   post(cmd);
 
155
   return convHandle;
 
156
}
 
157
 
 
158
void 
 
159
ConversationManager::destroyConversation(ConversationHandle convHandle)
 
160
{
 
161
   DestroyConversationCmd* cmd = new DestroyConversationCmd(this, convHandle);
 
162
   post(cmd);
 
163
}
 
164
 
 
165
void 
 
166
ConversationManager::joinConversation(ConversationHandle sourceConvHandle, ConversationHandle destConvHandle)
 
167
{
 
168
   JoinConversationCmd* cmd = new JoinConversationCmd(this, sourceConvHandle, destConvHandle);
 
169
   post(cmd);
 
170
}
 
171
 
 
172
ParticipantHandle 
 
173
ConversationManager::createRemoteParticipant(ConversationHandle convHandle, const NameAddr& destination, ParticipantForkSelectMode forkSelectMode)
 
174
{
 
175
   ParticipantHandle partHandle = getNewParticipantHandle();
 
176
 
 
177
   CreateRemoteParticipantCmd* cmd = new CreateRemoteParticipantCmd(this, partHandle, convHandle, destination, forkSelectMode);
 
178
   post(cmd);
 
179
 
 
180
   return partHandle;
 
181
}
 
182
 
 
183
ParticipantHandle 
 
184
ConversationManager::createMediaResourceParticipant(ConversationHandle convHandle, const Uri& mediaUrl)
 
185
{
 
186
   ParticipantHandle partHandle = getNewParticipantHandle();
 
187
 
 
188
   CreateMediaResourceParticipantCmd* cmd = new CreateMediaResourceParticipantCmd(this, partHandle, convHandle, mediaUrl);
 
189
   post(cmd);
 
190
 
 
191
   return partHandle;
 
192
}
 
193
 
 
194
ParticipantHandle 
 
195
ConversationManager::createLocalParticipant()
 
196
{
 
197
   ParticipantHandle partHandle = 0;
 
198
   if(mLocalAudioEnabled)
 
199
   {
 
200
      partHandle = getNewParticipantHandle();
 
201
 
 
202
      CreateLocalParticipantCmd* cmd = new CreateLocalParticipantCmd(this, partHandle);
 
203
      post(cmd);
 
204
   }
 
205
   else
 
206
   {
 
207
      WarningLog(<< "createLocalParticipant called when local audio support is disabled.");
 
208
   }
 
209
 
 
210
   return partHandle;
 
211
}
 
212
 
 
213
void 
 
214
ConversationManager::destroyParticipant(ParticipantHandle partHandle)
 
215
{
 
216
   DestroyParticipantCmd* cmd = new DestroyParticipantCmd(this, partHandle);
 
217
   post(cmd);
 
218
}
 
219
 
 
220
void 
 
221
ConversationManager::addParticipant(ConversationHandle convHandle, ParticipantHandle partHandle)
 
222
{
 
223
   AddParticipantCmd* cmd = new AddParticipantCmd(this, convHandle, partHandle);
 
224
   post(cmd);
 
225
}
 
226
 
 
227
void 
 
228
ConversationManager::removeParticipant(ConversationHandle convHandle, ParticipantHandle partHandle)
 
229
{
 
230
   RemoveParticipantCmd* cmd = new RemoveParticipantCmd(this, convHandle, partHandle);
 
231
   post(cmd);
 
232
}
 
233
 
 
234
void
 
235
ConversationManager::moveParticipant(ParticipantHandle partHandle, ConversationHandle sourceConvHandle, ConversationHandle destConvHandle)
 
236
{
 
237
   MoveParticipantCmd* cmd = new MoveParticipantCmd(this, partHandle, sourceConvHandle, destConvHandle);
 
238
   post(cmd);
 
239
}
 
240
 
 
241
void 
 
242
ConversationManager::modifyParticipantContribution(ConversationHandle convHandle, ParticipantHandle partHandle, unsigned int inputGain, unsigned int outputGain)
 
243
{
 
244
   ModifyParticipantContributionCmd* cmd = new ModifyParticipantContributionCmd(this, convHandle, partHandle, inputGain, outputGain);
 
245
   post(cmd);
 
246
}
 
247
 
 
248
void 
 
249
ConversationManager::outputBridgeMatrix()
 
250
{
 
251
   if(mMediaInterfaceMode == sipXGlobalMediaInterfaceMode)
 
252
   {
 
253
      OutputBridgeMixWeightsCmd* cmd = new OutputBridgeMixWeightsCmd(this);
 
254
      post(cmd);
 
255
   }
 
256
   else
 
257
   {
 
258
      WarningLog(<< "ConversationManager::outputBridgeMatrix not supported in current Media Interface Mode");
 
259
   }
 
260
}
 
261
 
 
262
void 
 
263
ConversationManager::alertParticipant(ParticipantHandle partHandle, bool earlyFlag)
 
264
{
 
265
   AlertParticipantCmd* cmd = new AlertParticipantCmd(this, partHandle, earlyFlag);
 
266
   post(cmd);
 
267
}
 
268
 
 
269
void 
 
270
ConversationManager::answerParticipant(ParticipantHandle partHandle)
 
271
{
 
272
   AnswerParticipantCmd* cmd = new AnswerParticipantCmd(this, partHandle);
 
273
   post(cmd);
 
274
}
 
275
 
 
276
void 
 
277
ConversationManager::rejectParticipant(ParticipantHandle partHandle, unsigned int rejectCode)
 
278
{
 
279
   RejectParticipantCmd* cmd = new RejectParticipantCmd(this, partHandle, rejectCode);
 
280
   post(cmd);
 
281
}
 
282
 
 
283
void 
 
284
ConversationManager::redirectParticipant(ParticipantHandle partHandle, const NameAddr& destination)
 
285
{
 
286
   RedirectParticipantCmd* cmd = new RedirectParticipantCmd(this, partHandle, destination);
 
287
   post(cmd);
 
288
}
 
289
 
 
290
void 
 
291
ConversationManager::redirectToParticipant(ParticipantHandle partHandle, ParticipantHandle destPartHandle)
 
292
{
 
293
   RedirectToParticipantCmd* cmd = new RedirectToParticipantCmd(this, partHandle, destPartHandle);
 
294
   post(cmd);
 
295
}
 
296
 
 
297
ConversationHandle 
 
298
ConversationManager::getNewConversationHandle()
 
299
{
 
300
   Lock lock(mConversationHandleMutex);
 
301
   return mCurrentConversationHandle++; 
 
302
}
 
303
 
 
304
void 
 
305
ConversationManager::registerConversation(Conversation *conversation)
 
306
{
 
307
   mConversations[conversation->getHandle()] = conversation;
 
308
}
 
309
 
 
310
void 
 
311
ConversationManager::unregisterConversation(Conversation *conversation)
 
312
{
 
313
   mConversations.erase(conversation->getHandle());
 
314
}
 
315
 
 
316
ParticipantHandle 
 
317
ConversationManager::getNewParticipantHandle()
 
318
{
 
319
   Lock lock(mParticipantHandleMutex);
 
320
   return mCurrentParticipantHandle++; 
 
321
}
 
322
 
 
323
void 
 
324
ConversationManager::registerParticipant(Participant *participant)
 
325
{
 
326
   mParticipants[participant->getParticipantHandle()] = participant;
 
327
}
 
328
 
 
329
void 
 
330
ConversationManager::unregisterParticipant(Participant *participant)
 
331
{
 
332
   InfoLog(<< "participant unregistered, handle=" << participant->getParticipantHandle());
 
333
   mParticipants.erase(participant->getParticipantHandle());
 
334
}
 
335
 
 
336
void 
 
337
ConversationManager::post(resip::Message *msg)
 
338
{
 
339
   mUserAgent->getDialogUsageManager().post(msg);
 
340
}
 
341
 
 
342
void 
 
343
ConversationManager::post(resip::ApplicationMessage& message, unsigned int ms)
 
344
{
 
345
    mUserAgent->post(message, ms);
 
346
}
 
347
 
 
348
void 
 
349
ConversationManager::initRTPPortFreeList()
 
350
{
 
351
   mRTPPortFreeList.clear();
 
352
   for(unsigned int i = mUserAgent->getUserAgentMasterProfile()->rtpPortRangeMin(); i <= mUserAgent->getUserAgentMasterProfile()->rtpPortRangeMax();)
 
353
   {
 
354
      mRTPPortFreeList.push_back(i);
 
355
      i=i+2;  // only add even ports - note we are assuming rtpPortRangeMin is even
 
356
   }
 
357
}
 
358
 
 
359
unsigned int 
 
360
ConversationManager::allocateRTPPort()
 
361
{
 
362
   unsigned int port = 0;
 
363
   if(!mRTPPortFreeList.empty())
 
364
   {
 
365
      port = mRTPPortFreeList.front();
 
366
      mRTPPortFreeList.pop_front();
 
367
   }
 
368
   return port;
 
369
}
 
370
 
 
371
void
 
372
ConversationManager::freeRTPPort(unsigned int port)
 
373
{
 
374
   assert(port >= mUserAgent->getUserAgentMasterProfile()->rtpPortRangeMin() && port <= mUserAgent->getUserAgentMasterProfile()->rtpPortRangeMax());
 
375
   mRTPPortFreeList.push_back(port);
 
376
}
 
377
 
 
378
void 
 
379
ConversationManager::buildSdpOffer(ConversationProfile* profile, SdpContents& offer)
 
380
{
 
381
   // copy over session capabilities
 
382
   offer = profile->sessionCaps();
 
383
 
 
384
   // Set sessionid and version for this offer
 
385
   UInt64 currentTime = Timer::getTimeMicroSec();
 
386
   offer.session().origin().getSessionId() = currentTime;
 
387
   offer.session().origin().getVersion() = currentTime;  
 
388
 
 
389
   // Set local port in offer
 
390
   // for now we only allow 1 audio media
 
391
   assert(offer.session().media().size() == 1);
 
392
   assert(offer.session().media().front().name() == "audio");
 
393
}
 
394
 
 
395
void
 
396
ConversationManager::setSpeakerVolume(int volume)
 
397
{
 
398
   OsStatus status =  mMediaFactory->getFactoryImplementation()->setSpeakerVolume(volume);
 
399
   if(status != OS_SUCCESS)
 
400
   {
 
401
      WarningLog(<< "setSpeakerVolume failed: status=" << status);
 
402
   }
 
403
}
 
404
 
 
405
void 
 
406
ConversationManager::setMicrophoneGain(int gain)
 
407
{
 
408
   OsStatus status =  mMediaFactory->getFactoryImplementation()->setMicrophoneGain(gain);
 
409
   if(status != OS_SUCCESS)
 
410
   {
 
411
      WarningLog(<< "setMicrophoneGain failed: status=" << status);
 
412
   }
 
413
}
 
414
 
 
415
void 
 
416
ConversationManager::muteMicrophone(bool mute)
 
417
{
 
418
   OsStatus status =  mMediaFactory->getFactoryImplementation()->muteMicrophone(mute? TRUE : FALSE);
 
419
   if(status != OS_SUCCESS)
 
420
   {
 
421
      WarningLog(<< "muteMicrophone failed: status=" << status);
 
422
   }
 
423
}
 
424
 
 
425
void 
 
426
ConversationManager::enableEchoCancel(bool enable)
 
427
{
 
428
   OsStatus status =  mMediaFactory->getFactoryImplementation()->setAudioAECMode(enable ? MEDIA_AEC_CANCEL : MEDIA_AEC_DISABLED);
 
429
   if(status != OS_SUCCESS)
 
430
   {
 
431
      WarningLog(<< "enableEchoCancel failed: status=" << status);
 
432
   }
 
433
   if(mMediaInterfaceMode == sipXGlobalMediaInterfaceMode)  // Note for sipXConversationMediaInterfaceMode - setting will apply on next conversation given focus
 
434
   {
 
435
      mMediaInterface->getInterface()->defocus();   // required to apply changes
 
436
      mMediaInterface->getInterface()->giveFocus();
 
437
   }
 
438
}
 
439
 
 
440
void 
 
441
ConversationManager::enableAutoGainControl(bool enable)
 
442
{
 
443
   OsStatus status =  mMediaFactory->getFactoryImplementation()->enableAGC(enable ? TRUE : FALSE);
 
444
   if(status != OS_SUCCESS)
 
445
   {
 
446
      WarningLog(<< "enableAutoGainControl failed: status=" << status);
 
447
   }
 
448
   if(mMediaInterfaceMode == sipXGlobalMediaInterfaceMode)  // Note for sipXConversationMediaInterfaceMode - setting will apply on next conversation given focus
 
449
   {
 
450
      mMediaInterface->getInterface()->defocus();   // required to apply changes
 
451
      mMediaInterface->getInterface()->giveFocus();
 
452
   }
 
453
}
 
454
 
 
455
void 
 
456
ConversationManager::enableNoiseReduction(bool enable)
 
457
{
 
458
   OsStatus status =  mMediaFactory->getFactoryImplementation()->setAudioNoiseReductionMode(enable ? MEDIA_NOISE_REDUCTION_MEDIUM /* arbitrary */ : MEDIA_NOISE_REDUCTION_DISABLED);
 
459
   if(status != OS_SUCCESS)
 
460
   {
 
461
      WarningLog(<< "enableAutoGainControl failed: status=" << status);
 
462
   }
 
463
   if(mMediaInterfaceMode == sipXGlobalMediaInterfaceMode)  // Note for sipXConversationMediaInterfaceMode - setting will apply on next conversation given focus
 
464
   {
 
465
      mMediaInterface->getInterface()->defocus();   // required to apply changes
 
466
      mMediaInterface->getInterface()->giveFocus();
 
467
   }
 
468
}
 
469
 
 
470
Participant* 
 
471
ConversationManager::getParticipant(ParticipantHandle partHandle)
 
472
{
 
473
   ParticipantMap::iterator i = mParticipants.find(partHandle);
 
474
   if(i != mParticipants.end())
 
475
   {
 
476
      return i->second;
 
477
   }
 
478
   else
 
479
   {
 
480
      return 0;
 
481
   }
 
482
}
 
483
 
 
484
Conversation* 
 
485
ConversationManager::getConversation(ConversationHandle convHandle)
 
486
{
 
487
   ConversationMap::iterator i = mConversations.find(convHandle);
 
488
   if(i != mConversations.end())
 
489
   {
 
490
      return i->second;
 
491
   }
 
492
   else
 
493
   {
 
494
      return 0;
 
495
   }
 
496
}
 
497
 
 
498
void 
 
499
ConversationManager::addBufferToMediaResourceCache(const resip::Data& name, const resip::Data& buffer, int type)
 
500
{
 
501
   mMediaResourceCache.addToCache(name, buffer, type);
 
502
}
 
503
 
 
504
void 
 
505
ConversationManager::buildSessionCapabilities(const resip::Data& ipaddress, unsigned int numCodecIds, 
 
506
                                              unsigned int codecIds[], resip::SdpContents& sessionCaps)
 
507
{
 
508
   sessionCaps = SdpContents::Empty;  // clear out passed in SdpContents
 
509
 
 
510
   // Check if ipaddress is V4 or V6
 
511
   bool v6 = false;
 
512
   if(!ipaddress.empty())
 
513
   {
 
514
      Tuple testTuple(ipaddress, 0, UDP);
 
515
      if(testTuple.ipVersion() == V6)
 
516
      {
 
517
         v6 = true;
 
518
      }
 
519
   }
 
520
 
 
521
   // Create Session Capabilities 
 
522
   // Note:  port, sessionId and version will be replaced in actual offer/answer
 
523
   // Build s=, o=, t=, and c= lines
 
524
   SdpContents::Session::Origin origin("-", 0 /* sessionId */, 0 /* version */, v6 ? SdpContents::IP6 : SdpContents::IP4, ipaddress.empty() ? "0.0.0.0" : ipaddress);   // o=   
 
525
   SdpContents::Session session(0, origin, "-" /* s= */);
 
526
   session.connection() = SdpContents::Session::Connection(v6 ? SdpContents::IP6 : SdpContents::IP4, ipaddress.empty() ? "0.0.0.0" : ipaddress);  // c=
 
527
   session.addTime(SdpContents::Session::Time(0, 0));
 
528
 
 
529
   MpCodecFactory *pCodecFactory = MpCodecFactory::getMpCodecFactory();
 
530
   SdpCodecList codecList;
 
531
   pCodecFactory->addCodecsToList(codecList);
 
532
   codecList.bindPayloadTypes();
 
533
 
 
534
   //UtlString output;
 
535
   //codecList.toString(output);
 
536
   //InfoLog( << "Codec List: " << output.data());
 
537
 
 
538
   // Auto-Create Session Codec Capabilities
 
539
   // Note:  port, and potentially payloadid will be replaced in actual offer/answer
 
540
 
 
541
   // Build Codecs and media offering
 
542
   SdpContents::Session::Medium medium("audio", 0, 1, "RTP/AVP");
 
543
 
 
544
   bool firstCodecAdded = false;
 
545
   for(unsigned int idIter = 0; idIter < numCodecIds; idIter++)
 
546
   {
 
547
      const SdpCodec* sdpcodec = codecList.getCodec((SdpCodec::SdpCodecTypes)codecIds[idIter]);
 
548
      if(sdpcodec)
 
549
      {
 
550
         UtlString mediaType;
 
551
         sdpcodec->getMediaType(mediaType);
 
552
         // Ensure this codec is an audio codec
 
553
         if(mediaType.compareTo("audio", UtlString::ignoreCase) == 0)
 
554
         {
 
555
            UtlString mimeSubType;
 
556
            sdpcodec->getEncodingName(mimeSubType);
 
557
            //mimeSubType.toUpper();
 
558
            
 
559
            SdpContents::Session::Codec codec(mimeSubType.data(), sdpcodec->getSampleRate());
 
560
            codec.payloadType() = sdpcodec->getCodecPayloadFormat();
 
561
 
 
562
            // Check for telephone-event and add fmtp manually
 
563
            if(mimeSubType.compareTo("telephone-event", UtlString::ignoreCase) == 0)
 
564
            {
 
565
               codec.parameters() = Data("0-15");
 
566
            }
 
567
            else
 
568
            {
 
569
               UtlString fmtpField;
 
570
               sdpcodec->getSdpFmtpField(fmtpField);
 
571
               if(fmtpField.length() != 0)
 
572
               {
 
573
                  codec.parameters() = Data(fmtpField.data());
 
574
               }
 
575
            }
 
576
 
 
577
            DebugLog(<< "Added codec to session capabilites: id=" << codecIds[idIter] 
 
578
                    << " type=" << mimeSubType.data()
 
579
                    << " rate=" << sdpcodec->getSampleRate()
 
580
                    << " plen=" << sdpcodec->getPacketLength()
 
581
                    << " payloadid=" << sdpcodec->getCodecPayloadFormat()
 
582
                    << " fmtp=" << codec.parameters());
 
583
 
 
584
            medium.addCodec(codec);
 
585
            if(!firstCodecAdded)
 
586
            {
 
587
               firstCodecAdded = true;
 
588
 
 
589
               // 20 ms of speech per frame (note G711 has 10ms samples, so this is 2 samples per frame)
 
590
               // Note:  There are known problems with SDP and the ptime attribute.  For now we will choose an
 
591
               // appropriate ptime from the first codec
 
592
               medium.addAttribute("ptime", Data(sdpcodec->getPacketLength() / 1000));  
 
593
            }
 
594
         }
 
595
      }
 
596
   }
 
597
 
 
598
   session.addMedium(medium);
 
599
   sessionCaps.session() = session;
 
600
}
 
601
 
 
602
void 
 
603
ConversationManager::notifyMediaEvent(ConversationHandle conversationHandle, int mediaConnectionId, MediaEvent::MediaEventType eventType)
 
604
{
 
605
   assert(eventType == MediaEvent::PLAY_FINISHED);
 
606
 
 
607
   if(conversationHandle == 0) // sipXGlobalMediaInterfaceMode
 
608
   {
 
609
      if(eventType == MediaEvent::PLAY_FINISHED)
 
610
      {
 
611
         // Using sipXGlobalMediaInterfaceMode it is only possible to have one active media participant
 
612
         // actually playing a file (or from cache) at a time, so for now it is sufficient to have
 
613
         // this event indicate that any active media participants (playing a file/cache) should be destroyed.
 
614
         ParticipantMap::iterator it;
 
615
         for(it = mParticipants.begin(); it != mParticipants.end();)
 
616
         {
 
617
            MediaResourceParticipant* mrPart = dynamic_cast<MediaResourceParticipant*>(it->second);
 
618
            it++;  // increment iterator here, since destroy may end up calling unregisterParticipant
 
619
            if(mrPart)
 
620
            {
 
621
               if(mrPart->getResourceType() == MediaResourceParticipant::File ||
 
622
                  mrPart->getResourceType() == MediaResourceParticipant::Cache)
 
623
               {
 
624
                  mrPart->destroyParticipant();
 
625
               }
 
626
            }
 
627
         }
 
628
      }
 
629
   }
 
630
   else
 
631
   {
 
632
      Conversation* conversation = getConversation(conversationHandle);
 
633
      if(conversation)
 
634
      {
 
635
         conversation->notifyMediaEvent(mediaConnectionId, eventType);
 
636
      }
 
637
   }
 
638
}
 
639
 
 
640
void 
 
641
ConversationManager::notifyDtmfEvent(ConversationHandle conversationHandle, int mediaConnectionId, int dtmf, int duration, bool up)
 
642
{
 
643
   if(conversationHandle == 0) // sipXGlobalMediaInterfaceMode
 
644
   {
 
645
      ParticipantMap::iterator i = mParticipants.begin();
 
646
      for(; i != mParticipants.end(); i++)
 
647
      {
 
648
         RemoteParticipant* remoteParticipant = dynamic_cast<RemoteParticipant*>(i->second);
 
649
         if(remoteParticipant)
 
650
         {
 
651
            if(remoteParticipant->getMediaConnectionId() == mediaConnectionId)
 
652
            {
 
653
               onDtmfEvent(remoteParticipant->getParticipantHandle(), dtmf, duration, up);
 
654
            }
 
655
         }
 
656
      }
 
657
   }
 
658
   else
 
659
   {
 
660
      Conversation* conversation = getConversation(conversationHandle);
 
661
      if(conversation)
 
662
      {
 
663
         conversation->notifyDtmfEvent(mediaConnectionId, dtmf, duration, up);
 
664
      }
 
665
   }
 
666
}
 
667
 
 
668
void 
 
669
ConversationManager::createMediaInterfaceAndMixer(bool giveFocus, 
 
670
                                                  ConversationHandle ownerConversationHandle,
 
671
                                                  SharedPtr<MediaInterface>& mediaInterface, 
 
672
                                                  BridgeMixer** bridgeMixer)
 
673
{
 
674
   UtlString localRtpInterfaceAddress("127.0.0.1");  // Will be overridden in RemoteParticipantDialogSet, when connection is created anyway
 
675
 
 
676
   // Note:  STUN and TURN capabilities of the sipX media stack are not used - the FlowManager is responsible for STUN/TURN
 
677
   mediaInterface = SharedPtr<MediaInterface>(new MediaInterface(*this, ownerConversationHandle, mMediaFactory->createMediaInterface(NULL, 
 
678
            localRtpInterfaceAddress, 
 
679
            0,     /* numCodecs - not required at this point */
 
680
            0,     /* codecArray - not required at this point */ 
 
681
            NULL,  /* local */
 
682
            mSipXTOSValue,  /* TOS Options */
 
683
            NULL,  /* STUN Server Address */
 
684
            0,     /* STUN Options */
 
685
            25,    /* STUN Keepalive period (seconds) */
 
686
            NULL,  /* TURN Server Address */
 
687
            0,     /* TURN Port */
 
688
            NULL,  /* TURN User */
 
689
            NULL,  /* TURN Password */
 
690
            25,    /* TURN Keepalive period (seconds) */
 
691
            false))); /* enable ICE? */
 
692
 
 
693
   // Register the NotificationDispatcher class (derived from OsMsgDispatcher)
 
694
   // as the sipX notification dispatcher
 
695
   mediaInterface->getInterface()->setNotificationDispatcher(mediaInterface.get());
 
696
 
 
697
   // Turn on notifications for all resources...
 
698
   mediaInterface->getInterface()->setNotificationsEnabled(true);
 
699
 
 
700
   if(giveFocus)
 
701
   {
 
702
      mediaInterface->getInterface()->giveFocus();
 
703
   }
 
704
 
 
705
   *bridgeMixer = new BridgeMixer(*(mediaInterface->getInterface()));
 
706
}
 
707
 
 
708
void
 
709
ConversationManager::onNewSession(ClientInviteSessionHandle h, InviteSession::OfferAnswerType oat, const SipMessage& msg)
 
710
{
 
711
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onNewSession(h, oat, msg);
 
712
}
 
713
 
 
714
void
 
715
ConversationManager::onNewSession(ServerInviteSessionHandle h, InviteSession::OfferAnswerType oat, const SipMessage& msg)
 
716
{
 
717
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onNewSession(h, oat, msg);
 
718
}
 
719
 
 
720
void
 
721
ConversationManager::onFailure(ClientInviteSessionHandle h, const SipMessage& msg)
 
722
{
 
723
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onFailure(h, msg);
 
724
}
 
725
      
 
726
void
 
727
ConversationManager::onEarlyMedia(ClientInviteSessionHandle h, const SipMessage& msg, const SdpContents& sdp)
 
728
{
 
729
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onEarlyMedia(h, msg, sdp);
 
730
}
 
731
 
 
732
void
 
733
ConversationManager::onProvisional(ClientInviteSessionHandle h, const SipMessage& msg)
 
734
{
 
735
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onProvisional(h, msg);
 
736
}
 
737
 
 
738
void
 
739
ConversationManager::onConnected(ClientInviteSessionHandle h, const SipMessage& msg)
 
740
{
 
741
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onConnected(h, msg);
 
742
}
 
743
 
 
744
void
 
745
ConversationManager::onConnected(InviteSessionHandle h, const SipMessage& msg)
 
746
{
 
747
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onConnected(h, msg);
 
748
}
 
749
 
 
750
void
 
751
ConversationManager::onConnectedConfirmed(InviteSessionHandle h, const SipMessage &msg)
 
752
{
 
753
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onConnectedConfirmed(h, msg);
 
754
}
 
755
 
 
756
void
 
757
ConversationManager::onStaleCallTimeout(ClientInviteSessionHandle h)
 
758
{
 
759
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onStaleCallTimeout(h);
 
760
}
 
761
 
 
762
void
 
763
ConversationManager::onTerminated(InviteSessionHandle h, InviteSessionHandler::TerminatedReason reason, const SipMessage* msg)
 
764
{
 
765
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onTerminated(h, reason, msg);
 
766
}
 
767
 
 
768
void
 
769
ConversationManager::onRedirected(ClientInviteSessionHandle h, const SipMessage& msg)
 
770
{
 
771
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onRedirected(h, msg);
 
772
}
 
773
 
 
774
void
 
775
ConversationManager::onAnswer(InviteSessionHandle h, const SipMessage& msg, const SdpContents& sdp)
 
776
{
 
777
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onAnswer(h, msg, sdp);
 
778
}
 
779
 
 
780
void
 
781
ConversationManager::onOffer(InviteSessionHandle h, const SipMessage& msg, const SdpContents& sdp)
 
782
{         
 
783
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onOffer(h, msg, sdp);
 
784
}
 
785
 
 
786
void
 
787
ConversationManager::onOfferRequired(InviteSessionHandle h, const SipMessage& msg)
 
788
{
 
789
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onOfferRequired(h, msg);
 
790
}
 
791
 
 
792
void
 
793
ConversationManager::onOfferRejected(InviteSessionHandle h, const SipMessage* msg)
 
794
{
 
795
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onOfferRejected(h, msg);
 
796
}
 
797
 
 
798
void
 
799
ConversationManager::onOfferRequestRejected(InviteSessionHandle h, const SipMessage& msg)
 
800
{
 
801
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onOfferRequestRejected(h, msg);
 
802
}
 
803
 
 
804
void
 
805
ConversationManager::onRemoteSdpChanged(InviteSessionHandle h, const SipMessage& msg, const SdpContents& sdp)
 
806
{
 
807
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onRemoteSdpChanged(h, msg, sdp);
 
808
}
 
809
 
 
810
void
 
811
ConversationManager::onInfo(InviteSessionHandle h, const SipMessage& msg)
 
812
{
 
813
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onInfo(h, msg);
 
814
}
 
815
 
 
816
void
 
817
ConversationManager::onInfoSuccess(InviteSessionHandle h, const SipMessage& msg)
 
818
{
 
819
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onInfoSuccess(h, msg);
 
820
}
 
821
 
 
822
void
 
823
ConversationManager::onInfoFailure(InviteSessionHandle h, const SipMessage& msg)
 
824
{
 
825
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onInfoFailure(h, msg);
 
826
}
 
827
 
 
828
void
 
829
ConversationManager::onRefer(InviteSessionHandle h, ServerSubscriptionHandle ssh, const SipMessage& msg)
 
830
{
 
831
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onRefer(h, ssh, msg);
 
832
}
 
833
 
 
834
void
 
835
ConversationManager::onReferAccepted(InviteSessionHandle h, ClientSubscriptionHandle csh, const SipMessage& msg)
 
836
{
 
837
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onReferAccepted(h, csh, msg);
 
838
}
 
839
 
 
840
void
 
841
ConversationManager::onReferRejected(InviteSessionHandle h, const SipMessage& msg)
 
842
{
 
843
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onReferRejected(h, msg);
 
844
}
 
845
 
 
846
void
 
847
ConversationManager::onReferNoSub(InviteSessionHandle h, const SipMessage& msg)
 
848
{
 
849
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onReferNoSub(h, msg);
 
850
}
 
851
 
 
852
void
 
853
ConversationManager::onMessage(InviteSessionHandle h, const SipMessage& msg)
 
854
{
 
855
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onMessage(h, msg);
 
856
}
 
857
 
 
858
void
 
859
ConversationManager::onMessageSuccess(InviteSessionHandle h, const SipMessage& msg)
 
860
{
 
861
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onMessageSuccess(h, msg);
 
862
}
 
863
 
 
864
void
 
865
ConversationManager::onMessageFailure(InviteSessionHandle h, const SipMessage& msg)
 
866
{
 
867
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onMessageFailure(h, msg);
 
868
}
 
869
 
 
870
void
 
871
ConversationManager::onForkDestroyed(ClientInviteSessionHandle h)
 
872
{
 
873
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onForkDestroyed(h);
 
874
}
 
875
 
 
876
////////////////////////////////////////////////////////////////////////////////
 
877
// DialogSetHandler ///////////////////////////////////////////////////
 
878
////////////////////////////////////////////////////////////////////////////////
 
879
void 
 
880
ConversationManager::onTrying(AppDialogSetHandle h, const SipMessage& msg)
 
881
{
 
882
   RemoteParticipantDialogSet *remoteParticipantDialogSet = dynamic_cast<RemoteParticipantDialogSet *>(h.get());
 
883
   if(remoteParticipantDialogSet)
 
884
   {
 
885
      remoteParticipantDialogSet->onTrying(h, msg);
 
886
   }
 
887
   else
 
888
   {
 
889
      InfoLog(<< "onTrying(AppDialogSetHandle): " << msg.brief());
 
890
   }
 
891
}
 
892
 
 
893
void 
 
894
ConversationManager::onNonDialogCreatingProvisional(AppDialogSetHandle h, const SipMessage& msg)
 
895
{
 
896
   RemoteParticipantDialogSet *remoteParticipantDialogSet = dynamic_cast<RemoteParticipantDialogSet *>(h.get());
 
897
   if(remoteParticipantDialogSet)
 
898
   {
 
899
      remoteParticipantDialogSet->onNonDialogCreatingProvisional(h, msg);
 
900
   }
 
901
   else
 
902
   {
 
903
      InfoLog(<< "onNonDialogCreatingProvisional(AppDialogSetHandle): " << msg.brief());
 
904
   }
 
905
}
 
906
 
 
907
////////////////////////////////////////////////////////////////////////////////
 
908
// ClientSubscriptionHandler ///////////////////////////////////////////////////
 
909
////////////////////////////////////////////////////////////////////////////////
 
910
void
 
911
ConversationManager::onUpdatePending(ClientSubscriptionHandle h, const SipMessage& msg, bool outOfOrder)
 
912
{
 
913
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onUpdatePending(h, msg, outOfOrder);
 
914
}
 
915
 
 
916
void
 
917
ConversationManager::onUpdateActive(ClientSubscriptionHandle h, const SipMessage& msg, bool outOfOrder)
 
918
{
 
919
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onUpdateActive(h, msg, outOfOrder);
 
920
}
 
921
 
 
922
void
 
923
ConversationManager::onUpdateExtension(ClientSubscriptionHandle h, const SipMessage& msg, bool outOfOrder)
 
924
{
 
925
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onUpdateExtension(h, msg, outOfOrder);
 
926
}
 
927
 
 
928
void
 
929
ConversationManager::onTerminated(ClientSubscriptionHandle h, const SipMessage* msg)
 
930
{
 
931
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onTerminated(h, msg);
 
932
}
 
933
 
 
934
void
 
935
ConversationManager::onNewSubscription(ClientSubscriptionHandle h, const SipMessage& msg)
 
936
{
 
937
   dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onNewSubscription(h, msg);
 
938
}
 
939
 
 
940
int 
 
941
ConversationManager::onRequestRetry(ClientSubscriptionHandle h, int retryMinimum, const SipMessage& msg)
 
942
{
 
943
   return dynamic_cast<RemoteParticipant *>(h->getAppDialog().get())->onRequestRetry(h, retryMinimum, msg);
 
944
 
 
945
}
 
946
 
 
947
////////////////////////////////////////////////////////////////////////////////
 
948
// ServerSubscriptionHandler ///////////////////////////////////////////////////
 
949
////////////////////////////////////////////////////////////////////////////////
 
950
void 
 
951
ConversationManager::onNewSubscription(ServerSubscriptionHandle, const SipMessage& msg)
 
952
{
 
953
   InfoLog(<< "onNewSubscription(ServerSubscriptionHandle): " << msg.brief());
 
954
}
 
955
 
 
956
void 
 
957
ConversationManager::onNewSubscriptionFromRefer(ServerSubscriptionHandle ss, const SipMessage& msg)
 
958
{
 
959
   InfoLog(<< "onNewSubscriptionFromRefer(ServerSubscriptionHandle): " << msg.brief());
 
960
   // Received an out-of-dialog refer request with implicit subscription
 
961
   try
 
962
   {
 
963
      if(msg.exists(h_ReferTo))
 
964
      {
 
965
         // Check if TargetDialog header is present
 
966
         if(msg.exists(h_TargetDialog))
 
967
         {
 
968
            pair<InviteSessionHandle, int> presult;
 
969
            presult = mUserAgent->getDialogUsageManager().findInviteSession(msg.header(h_TargetDialog));
 
970
            if(!(presult.first == InviteSessionHandle::NotValid())) 
 
971
            {         
 
972
               RemoteParticipant* participantToRefer = (RemoteParticipant*)presult.first->getAppDialog().get();
 
973
 
 
974
               participantToRefer->onRefer(presult.first, ss, msg);
 
975
               return;
 
976
            }
 
977
         }
 
978
 
 
979
         // Create new Participant
 
980
         RemoteParticipantDialogSet *participantDialogSet = new RemoteParticipantDialogSet(*this);
 
981
         RemoteParticipant *participant = participantDialogSet->createUACOriginalRemoteParticipant(getNewParticipantHandle());  
 
982
 
 
983
         // Set pending OOD info in Participant - causes accept or reject to be called later
 
984
         participant->setPendingOODReferInfo(ss, msg);
 
985
 
 
986
         // Notify application
 
987
         ConversationProfile* profile = dynamic_cast<ConversationProfile*>(ss->getUserProfile().get());
 
988
         assert(profile);
 
989
         onRequestOutgoingParticipant(participant->getParticipantHandle(), msg, *profile);
 
990
      }
 
991
      else
 
992
      {
 
993
         WarningLog (<< "Received refer w/out a Refer-To: " << msg.brief());
 
994
         ss->send(ss->reject(400));
 
995
      }
 
996
   }
 
997
   catch(BaseException &e)
 
998
   {
 
999
      WarningLog(<< "onNewSubscriptionFromRefer exception: " << e);
 
1000
   }
 
1001
   catch(...)
 
1002
   {
 
1003
      WarningLog(<< "onNewSubscriptionFromRefer unknown exception");
 
1004
   }
 
1005
}
 
1006
 
 
1007
void 
 
1008
ConversationManager::onRefresh(ServerSubscriptionHandle, const SipMessage& msg)
 
1009
{
 
1010
   InfoLog(<< "onRefresh(ServerSubscriptionHandle): " << msg.brief());
 
1011
}
 
1012
 
 
1013
void 
 
1014
ConversationManager::onTerminated(ServerSubscriptionHandle)
 
1015
{
 
1016
   InfoLog(<< "onTerminated(ServerSubscriptionHandle)");
 
1017
}
 
1018
 
 
1019
void 
 
1020
ConversationManager::onReadyToSend(ServerSubscriptionHandle, SipMessage&)
 
1021
{
 
1022
}
 
1023
 
 
1024
void 
 
1025
ConversationManager::onNotifyRejected(ServerSubscriptionHandle, const SipMessage& msg)
 
1026
{
 
1027
   WarningLog(<< "onNotifyRejected(ServerSubscriptionHandle): " << msg.brief());
 
1028
}
 
1029
 
 
1030
void 
 
1031
ConversationManager::onError(ServerSubscriptionHandle, const SipMessage& msg)
 
1032
{
 
1033
   WarningLog(<< "onError(ServerSubscriptionHandle): " << msg.brief());
 
1034
}
 
1035
 
 
1036
void 
 
1037
ConversationManager::onExpiredByClient(ServerSubscriptionHandle, const SipMessage& sub, SipMessage& notify)
 
1038
{
 
1039
   InfoLog(<< "onExpiredByClient(ServerSubscriptionHandle): " << notify.brief());
 
1040
}
 
1041
 
 
1042
void 
 
1043
ConversationManager::onExpired(ServerSubscriptionHandle, SipMessage& msg)
 
1044
{
 
1045
   InfoLog(<< "onExpired(ServerSubscriptionHandle): " << msg.brief());
 
1046
}
 
1047
 
 
1048
bool 
 
1049
ConversationManager::hasDefaultExpires() const
 
1050
{
 
1051
   return true;
 
1052
}
 
1053
 
 
1054
UInt32 
 
1055
ConversationManager::getDefaultExpires() const
 
1056
{
 
1057
   return 60;
 
1058
}
 
1059
 
 
1060
////////////////////////////////////////////////////////////////////////////////
 
1061
// OutOfDialogHandler //////////////////////////////////////////////////////////
 
1062
////////////////////////////////////////////////////////////////////////////////
 
1063
void 
 
1064
ConversationManager::onSuccess(ClientOutOfDialogReqHandle, const SipMessage& msg)
 
1065
{
 
1066
   InfoLog(<< "onSuccess(ClientOutOfDialogReqHandle): " << msg.brief());
 
1067
}
 
1068
 
 
1069
void 
 
1070
ConversationManager::onFailure(ClientOutOfDialogReqHandle, const SipMessage& msg)
 
1071
{
 
1072
   InfoLog(<< "onFailure(ClientOutOfDialogReqHandle): " << msg.brief());
 
1073
}
 
1074
 
 
1075
void 
 
1076
ConversationManager::onReceivedRequest(ServerOutOfDialogReqHandle ood, const SipMessage& msg)
 
1077
{
 
1078
   InfoLog(<< "onReceivedRequest(ServerOutOfDialogReqHandle): " << msg.brief());
 
1079
 
 
1080
   switch(msg.method())
 
1081
   {
 
1082
   case OPTIONS:
 
1083
   {
 
1084
      SharedPtr<SipMessage> optionsAnswer = ood->answerOptions();
 
1085
 
 
1086
      // Attach an offer to the options request
 
1087
      SdpContents sdp;
 
1088
      buildSdpOffer(mUserAgent->getIncomingConversationProfile(msg).get(), sdp);
 
1089
      optionsAnswer->setContents(&sdp);
 
1090
      ood->send(optionsAnswer);
 
1091
      break;
 
1092
   }
 
1093
   case REFER:
 
1094
   {
 
1095
      // Received an OOD refer request with no refer subscription
 
1096
      try
 
1097
      {
 
1098
         if(msg.exists(h_ReferTo))
 
1099
         {
 
1100
            // Check if TargetDialog header is present
 
1101
            if(msg.exists(h_TargetDialog))
 
1102
            {
 
1103
               pair<InviteSessionHandle, int> presult;
 
1104
               presult = mUserAgent->getDialogUsageManager().findInviteSession(msg.header(h_TargetDialog));
 
1105
               if(!(presult.first == InviteSessionHandle::NotValid())) 
 
1106
               {         
 
1107
                  RemoteParticipant* participantToRefer = (RemoteParticipant*)presult.first->getAppDialog().get();
 
1108
 
 
1109
                  // Accept the Refer
 
1110
                  ood->send(ood->accept(202 /* Refer Accepted */));
 
1111
 
 
1112
                  participantToRefer->doReferNoSub(msg);
 
1113
                  return;
 
1114
               }
 
1115
            }
 
1116
 
 
1117
            // Create new Participant 
 
1118
            RemoteParticipantDialogSet *participantDialogSet = new RemoteParticipantDialogSet(*this);
 
1119
            RemoteParticipant *participant = participantDialogSet->createUACOriginalRemoteParticipant(getNewParticipantHandle());  
 
1120
 
 
1121
            // Set pending OOD info in Participant - causes accept or reject to be called later
 
1122
            participant->setPendingOODReferInfo(ood, msg);
 
1123
 
 
1124
            // Notify application
 
1125
            ConversationProfile* profile = dynamic_cast<ConversationProfile*>(ood->getUserProfile().get());
 
1126
            assert(profile);
 
1127
            onRequestOutgoingParticipant(participant->getParticipantHandle(), msg, *profile);
 
1128
         }
 
1129
         else
 
1130
         {
 
1131
            WarningLog (<< "onReceivedRequest(ServerOutOfDialogReqHandle): Received refer w/out a Refer-To: " << msg.brief());
 
1132
            ood->send(ood->reject(400));
 
1133
         }
 
1134
      }
 
1135
      catch(BaseException &e)
 
1136
      {
 
1137
         WarningLog(<< "onReceivedRequest(ServerOutOfDialogReqHandle): exception " << e);
 
1138
      }
 
1139
      catch(...)
 
1140
      {
 
1141
         WarningLog(<< "onReceivedRequest(ServerOutOfDialogReqHandle): unknown exception");
 
1142
      }
 
1143
 
 
1144
      break;
 
1145
   }
 
1146
   default:
 
1147
      break;
 
1148
   }
 
1149
}
 
1150
 
 
1151
////////////////////////////////////////////////////////////////////////////////
 
1152
// RedirectHandler /////////////////////////////////////////////////////////////
 
1153
////////////////////////////////////////////////////////////////////////////////
 
1154
void 
 
1155
ConversationManager::onRedirectReceived(AppDialogSetHandle, const SipMessage& msg)
 
1156
{
 
1157
   InfoLog(<< "onRedirectReceived(AppDialogSetHandle): " << msg.brief());
 
1158
}
 
1159
 
 
1160
bool 
 
1161
ConversationManager::onTryingNextTarget(AppDialogSetHandle, const SipMessage& msg)
 
1162
{
 
1163
   InfoLog(<< "onTryingNextTarget(AppDialogSetHandle): " << msg.brief());
 
1164
   // Always allow redirection for now
 
1165
   return true;
 
1166
}
 
1167
 
 
1168
 
 
1169
/* ====================================================================
 
1170
 
 
1171
 Copyright (c) 2007-2008, Plantronics, Inc.
 
1172
 All rights reserved.
 
1173
 
 
1174
 Redistribution and use in source and binary forms, with or without
 
1175
 modification, are permitted provided that the following conditions are 
 
1176
 met:
 
1177
 
 
1178
 1. Redistributions of source code must retain the above copyright 
 
1179
    notice, this list of conditions and the following disclaimer. 
 
1180
 
 
1181
 2. Redistributions in binary form must reproduce the above copyright
 
1182
    notice, this list of conditions and the following disclaimer in the
 
1183
    documentation and/or other materials provided with the distribution. 
 
1184
 
 
1185
 3. Neither the name of Plantronics nor the names of its contributors 
 
1186
    may be used to endorse or promote products derived from this 
 
1187
    software without specific prior written permission. 
 
1188
 
 
1189
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 
1190
 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 
1191
 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
 
1192
 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
 
1193
 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 
1194
 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
 
1195
 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
 
1196
 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
 
1197
 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
 
1198
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
 
1199
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
1200
 
 
1201
 ==================================================================== */