reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
SipXMediaResourceParticipant.cxx
Go to the documentation of this file.
1#include "SipXBridgeMixer.hxx"
2#include "ReconSubsystem.hxx"
5#include "Conversation.hxx"
6#include "UserAgent.hxx"
7
8#include <rutil/Log.hxx>
9#include <rutil/Logger.hxx>
12
15
16// sipX includes
17#include <CpTopologyGraphInterface.h>
18#include <mp/dtmflib.h>
19#include <mp/MprFromFile.h>
20// The ssrc_t typedef from MprEncode.h collides with one from libSrtp - we don't use it in this file, so just undefine it to avoid the compilation error
21#undef ssrc_t
22#include <mp/MprEncode.h>
23#define DISABLE_STREAM_PLAYER
24#ifndef DISABLE_STREAM_PLAYER
25 #include <mp/MpStreamPlayer.h>
26#endif
27#ifndef SIPX_NO_RECORD
28#include <utl/CircularBufferPtr.h>
29#endif
30
31using namespace recon;
32using namespace resip;
33using namespace std;
34
35#define RESIPROCATE_SUBSYSTEM ReconSubsystem::RECON
36
37static const resip::ExtensionParameter p_participantonly("participant-only");
38static const resip::ExtensionParameter p_append("append");
39static const resip::ExtensionParameter p_silencetime("silencetime"); // in milliseconds
40static const resip::ExtensionParameter p_format("format");
41static const resip::ExtensionParameter p_numchannels("numchannels");
42
43
45 ConversationManager& conversationManager,
46 SipXMediaStackAdapter& sipXMediaStackAdapter,
47 const Uri& mediaUrl,
48 const std::shared_ptr<Data>& playAudioBuffer,
49 void* recordingCircularBuffer)
50: Participant(partHandle, ConversationManager::ParticipantType_MediaResource, conversationManager),
51 MediaResourceParticipant(partHandle, conversationManager, mediaUrl, playAudioBuffer),
52 SipXParticipant(partHandle, ConversationManager::ParticipantType_MediaResource, conversationManager, sipXMediaStackAdapter),
53 mStreamPlayer(0),
54 mPortOnBridge(-1),
55#ifndef SIPX_NO_RECORD
56 mRecordingCircularBuffer((CircularBufferPtr*)recordingCircularBuffer)
57#else
58 mRecordingCircularBuffer(nullptr)
59#endif
60{
61 InfoLog(<< "SipXMediaResourceParticipant created, handle=" << mHandle << " url=" << getMediaUrl());
62#ifdef SIPX_NO_RECORD
63 if(recordingCircularBuffer != 0)
64 {
65 ErrLog(<< "recordingCircularBuffer specified but recon is not compiled with support for CircularBuffer");
66 }
67#endif
68}
69
71{
72 getMediaInterface()->unallocateResourceForMediaOperation(getResourceType(), mHandle);
73
74 // Destroy stream player (if created)
75 if(mStreamPlayer)
76 {
77#ifndef DISABLE_STREAM_PLAYER
78 mStreamPlayer->removeListener(this);
79 mStreamPlayer->destroy();
80#endif
81 }
82
83 // Note: Ideally this call would exist in the Participant Base class - but this call requires
84 // dynamic_casts and virtual methods to function correctly during destruction.
85 // If the call is placed in the base Participant class then these things will not
86 // function as desired because a classes type changes as the descructors unwind.
87 // See https://stackoverflow.com/questions/10979250/usage-of-this-in-destructor.
89
90 InfoLog(<< "SipXMediaResourceParticipant destroyed, handle=" << mHandle << " url=" << getMediaUrl());
91}
92
93void
95{
96 // Check if we have allocated a media resource yet or not
97 if (mSipXResourceName.empty())
98 {
99 if (!getMediaInterface()->allocateAvailableResourceForMediaOperation(getResourceType(), mHandle, mSipXResourceName))
100 {
101 WarningLog(<< "SipXMediaResourceParticipant::startResource no available allocation for media participant of type=" << getResourceType());
102 return;
103 }
104 }
105
106 switch(getResourceType())
107 {
108 case Tone:
109 {
110 int toneid;
111 bool isDtmf = false;
112 if(getMediaUrl().host().size() == 1)
113 {
114 toneid = getMediaUrl().host().at(0);
115 isDtmf = true;
116 }
117 else
118 {
119 if(isEqualNoCase(getMediaUrl().host(), dialtoneTone)) toneid = DTMF_TONE_DIALTONE;
120 else if(isEqualNoCase(getMediaUrl().host(), busyTone)) toneid = DTMF_TONE_BUSY;
121 else if(isEqualNoCase(getMediaUrl().host(), ringbackTone)) toneid = DTMF_TONE_RINGBACK;
122 else if(isEqualNoCase(getMediaUrl().host(), ringTone)) toneid = DTMF_TONE_RINGTONE;
123 else if(isEqualNoCase(getMediaUrl().host(), fastbusyTone)) toneid = DTMF_TONE_CALLFAILED;
124 else if(isEqualNoCase(getMediaUrl().host(), backspaceTone)) toneid = DTMF_TONE_BACKSPACE;
125 else if(isEqualNoCase(getMediaUrl().host(), callwaitingTone)) toneid = DTMF_TONE_CALLWAITING;
126 else if(isEqualNoCase(getMediaUrl().host(), holdingTone)) toneid = DTMF_TONE_CALLHELD;
127 else if(isEqualNoCase(getMediaUrl().host(), loudfastbusyTone)) toneid = DTMF_TONE_LOUD_FAST_BUSY;
128 else
129 {
130 WarningLog(<< "SipXMediaResourceParticipant::startResource invalid tone identifier: " << getMediaUrl().host());
131 return;
132 }
133 }
134
135 OsStatus status = OS_FAILED;
136 if(isDtmf && getMediaUrl().exists(p_participantonly))
137 {
139 SipXRemoteParticipant* participant = dynamic_cast<SipXRemoteParticipant*>(getConversationManager().getParticipant(partHandle));
140 if(participant)
141 {
142 StackLog(<< "SipXMediaResourceParticipant::startResource: sending tone to sipX connection: " << participant->getMediaConnectionId());
143#ifdef SIPX_NO_RECORD
144 // Start RFC4733 out-of-band tone
145 UtlString encodeName(DEFAULT_ENCODE_RESOURCE_NAME);
146 MpResourceTopology::replaceNumInName(encodeName, participant->getMediaConnectionId());
147 status = MprEncode::startTone(encodeName, *getMediaInterface()->getInterface()->getMsgQ(), toneid);
148#else
149 status = getMediaInterface()->getInterface()->startChannelOnlyTone(participant->getMediaConnectionId(), toneid);
150#endif
151 // We are NOT using the actual Tone resource from sipX when doing participant only, so we can free the allocation now,
152 // so that multiple participant only tone resources can be started.
153 getMediaInterface()->unallocateResourceForMediaOperation(getResourceType(), mHandle);
154 }
155 else
156 {
157 WarningLog(<< "SipXMediaResourceParticipant::startResource Participant " << partHandle << " no longer exists or invalid");
158 }
159 }
160 else
161 {
162#ifdef SIPX_NO_RECORD
163 status = getMediaInterface()->getInterface()->startTone(toneid, TRUE /* local - unused */, TRUE /* remote - unused */);
164#else
165 // Note: We are passing rfc4733Enabled as false, since sipX will send RFC4733 to all active RTP connections, and they may be in entirely different recon conversations
166 status = getMediaInterface()->getInterface()->startTone(mSipXResourceName.c_str(), toneid, FALSE /* rfc4733Enabled? */);
167#endif
168 }
169 if(status == OS_SUCCESS)
170 {
171 setRunning(true);
172 }
173 else
174 {
175 WarningLog(<< "SipXMediaResourceParticipant::startResource error calling startTone: " << status);
176 }
177 }
178 break;
179
180 case File:
181 {
182 Data filepath = getMediaUrl().host().urlDecoded();
183 filepath.replace("|", ":"); // For Windows filepath processing - convert | to :
184
185 InfoLog(<< "SipXMediaResourceParticipant playing, handle=" << mHandle << " filepath=" << filepath);
186
187 SipXMediaInterface* mediaInterface = getMediaInterface().get();
188#ifdef SIPX_NO_RECORD
189 OsStatus status = mediaInterface->getInterface()->playAudio(filepath.c_str(),
190 isRepeat() ? TRUE : FALSE /* repeast? */,
191 TRUE /* local - unused */, TRUE /* remote - unused */);
192#else
193 OsStatus status = mediaInterface->getInterface()->playAudio(mSipXResourceName.c_str(),
194 filepath.c_str(),
195 isRepeat() ? TRUE : FALSE,
196 TRUE /* autoStopAfterFinish? */,
198#endif
199
200 if(status == OS_SUCCESS)
201 {
202 setRunning(true);
203 }
204 else
205 {
206 WarningLog(<< "SipXMediaResourceParticipant::startResource error calling playAudio: " << status);
207 }
208 }
209 break;
210
211 case Cache:
212 {
213 Data cacheKey = getMediaUrl().host().urlDecoded();
214 cacheKey.replace("|", ":"); // For Windows filepath processing - convert | to :
215
216 InfoLog(<< "SipXMediaResourceParticipant playing, handle=" << mHandle << " cacheKey=" << cacheKey);
217
218 Data* buffer;
219 int type;
220 if (getConversationManager().getBufferFromMediaResourceCache(cacheKey, &buffer, &type))
221 {
222 SipXMediaInterface* mediaInterface = getMediaInterface().get();
223#ifdef SIPX_NO_RECORD
224 OsStatus status = mediaInterface->getInterface()->playBuffer((char*)buffer->data(),
225 buffer->size(),
226 8000, /* rate */
227 type,
228 isRepeat() ? TRUE : FALSE /* repeat? */,
229 TRUE /* local - unused */, TRUE /* remote - unused */);
230#else
231 OsStatus status = mediaInterface->getInterface()->playBuffer(mSipXResourceName.c_str(),
232 (char*)buffer->data(),
233 (unsigned long)buffer->size(),
234 8000, /* rate */
235 type,
236 isRepeat() ? TRUE : FALSE,
237 NULL /* OsProtectedEvent */,
238 TRUE /* autoStopAfterFinish? */,
240#endif
241 if (status == OS_SUCCESS)
242 {
243 setRunning(true);
244 }
245 else
246 {
247 WarningLog(<< "SipXMediaResourceParticipant::startResource error calling playAudio: " << status);
248 }
249 }
250 else
251 {
252 WarningLog(<< "SipXMediaResourceParticipant::startResource media not found in cache, key: " << getMediaUrl().host());
253 }
254 }
255 break;
256
257 case Buffer:
258 {
259 Data audioBufferType = getMediaUrl().host();
260
261 InfoLog(<< "SipXMediaResourceParticipant playing, handle=" << mHandle << " audioBufferType=" << audioBufferType);
262
263 if (resip::isEqualNoCase("RAW_PCM_16", audioBufferType))
264 {
265 Data* buffer = getAudioBuffer().get();
266
267 if (buffer && buffer->size() > 0)
268 {
269 SipXMediaInterface* mediaInterface = getMediaInterface().get();
270#ifdef SIPX_NO_RECORD
271 OsStatus status = mediaInterface->getInterface()->playBuffer((char*)buffer->data(),
272 buffer->size(),
273 8000, /* rate */
274 0, // RAW_PCM_16 = 0 - always correct for SipXMedia: see sipXTapi.h: SIPX_AUDIO_DATA_FORMAT
275 isRepeat() ? TRUE : FALSE /* repeat? */,
276 TRUE /* local - unused */, TRUE /* remote - unused */);
277#else
278 OsStatus status = mediaInterface->getInterface()->playBuffer(mSipXResourceName.c_str(),
279 (char*)buffer->data(),
280 (unsigned long)buffer->size(),
281 8000, /* rate */
282 0, // RAW_PCM_16 = 0 - always correct for SipXMedia: see sipXTapi.h: SIPX_AUDIO_DATA_FORMAT
283 isRepeat() ? TRUE : FALSE,
284 NULL /* OsProtectedEvent */,
285 TRUE /* autoStopAfterFinish? */,
287#endif
288 if (status == OS_SUCCESS)
289 {
290 setRunning(true);
291 }
292 else
293 {
294 WarningLog(<< "SipXMediaResourceParticipant::startResource error calling playAudio: " << status);
295 }
296 }
297 else
298 {
299 WarningLog(<< "SipXMediaResourceParticipant::startResource buffer type, but no audio buffer was provided.");
300 }
301 }
302 else
303 {
304 WarningLog(<< "SipXMediaResourceParticipant::startResource buffer type is not recognized: " << audioBufferType);
305 }
306 }
307 break;
308
309 // Warning: The stream player has been deprecated from the SipX CpTopologyGraphInterface - leaving code in place in case it ever get's
310 // re-implemented. If someone tries to play from Http or Https with sipX it will fail at the createPlayer call below, and
311 // the MediaResourceParticipant will self destruct.
312 case Http:
313 case Https:
314 {
315 int flags = STREAM_SOUND_LOCAL | STREAM_SOUND_REMOTE;
316
317#ifndef DISABLE_STREAM_PLAYER
318 OsStatus status = getMediaInterface()->getInterface()->createPlayer(&mStreamPlayer, Data::from(getMediaUrl()).c_str(), flags);
319 if(status == OS_SUCCESS)
320 {
321 mStreamPlayer->addListener(this);
322 status = mStreamPlayer->realize(FALSE /* block? */);
323 if(status != OS_SUCCESS)
324 {
325 WarningLog(<< "SipXMediaResourceParticipant::startResource error calling StreamPlayer::realize: " << status);
326 }
327 else
328 {
329 setRunning(true);
330 }
331 }
332 else
333 {
334 WarningLog(<< "SipXMediaResourceParticipant::startResource error calling createPlayer: " << status);
335 }
336#endif
337 }
338 break;
339
340 case Record:
342 {
343#ifdef SIPX_NO_RECORD
344 ErrLog(<< "support for Record was not enabled at compile time");
345#else
346 int silenceTimeMs = -1; // disabled
347 if (getMediaUrl().exists(p_silencetime))
348 {
349 silenceTimeMs = getMediaUrl().param(p_silencetime).convertInt();
350 }
351
352 int numChannels = 1;
354 {
355 numChannels = getMediaUrl().param(p_numchannels).convertInt();
356 if (numChannels < 1)
357 {
358 numChannels = 1;
359 }
360 else if (numChannels > 2)
361 {
362 numChannels = 2;
363 }
364 }
365
366 CpMediaInterface::CpAudioFileFormat format = CpMediaInterface::CP_WAVE_PCM_16; // Default recording format
367 Data formatString(recordingFormatWAVPCM16);
368 if (getMediaUrl().exists(p_format))
369 {
370 Data& urlFormatString = getMediaUrl().param(p_format);
371 if (isEqualNoCase(urlFormatString, recordingFormatWAVMULAW))
372 {
373 format = CpMediaInterface::CP_WAVE_MULAW;
374 formatString = recordingFormatWAVMULAW;
375 }
376 else if (isEqualNoCase(urlFormatString, recordingFormatWAVALAW))
377 {
378 format = CpMediaInterface::CP_WAVE_ALAW;
379 formatString = recordingFormatWAVALAW;
380 }
381 else if (isEqualNoCase(urlFormatString, recordingFormatWAVGSM))
382 {
383 format = CpMediaInterface::CP_WAVE_GSM;
384 formatString = recordingFormatWAVGSM;
385 }
386 else if (isEqualNoCase(urlFormatString, recordingFormatOGGOPUS))
387 {
388 format = CpMediaInterface::CP_OGG_OPUS;
389 formatString = recordingFormatOGGOPUS;
390 }
391 }
392
393 SipXMediaInterface* mediaInterface = getMediaInterface().get();
394
395 // If recording to circular buffer, then do that now, and return
396 if (isEqualNoCase(getMediaUrl().host(), "circularbuffer") && mRecordingCircularBuffer)
397 {
398 // Set Watermark level at 5/6 of the circular buffer size
399 unsigned long recordingBufferNotificationWatermark = mRecordingCircularBuffer->getCapacity() / 5 * 4;
400
401 InfoLog(<< "SipXMediaResourceParticipant recording to CircularBuffer, handle=" << mHandle << ", format=" << formatString << ", maxDurationMs=" << getDurationMs() << ", silenceTimeMs=" << silenceTimeMs << ", circularBufferCapacity=" << mRecordingCircularBuffer->getCapacity() << ", recordingBufferNotificationWatermark=" << recordingBufferNotificationWatermark);
402
403 // We are passing the CircularBufferPtr to sipX - it will call release when it's done with the buffer - add it's reference now
404 mRecordingCircularBuffer->addRef();
405
406 OsStatus status = mediaInterface->getInterface()->recordCircularBufferAudio(
407 mSipXResourceName.c_str(),
408 *mRecordingCircularBuffer,
409 format,
410 recordingBufferNotificationWatermark,
411 getDurationMs() /* maxTime Ms */,
412 silenceTimeMs /* silenceLength Ms, -1 to disable */,
413 numChannels,
414 FALSE /* setupMultiChannelMixesAutomatically? */);
415
416 if (status == OS_SUCCESS)
417 {
418 mRecordingCircularBuffer = 0; // The application and sipX control the lifetime of the CircularBuffer, clear out our pointer, so we are not tempted to use it.
419 setRunning(true);
420 }
421 else
422 {
423 mRecordingCircularBuffer->release(); // Failed to handoff ownership to sipX, release the reference we added above
424 mRecordingCircularBuffer = 0;
425 WarningLog(<< "SipXMediaResourceParticipant::startResource error calling recordCircularBufferAudio: " << status);
426 }
427
428 return;
429 }
430
431 Data filepath = getMediaUrl().host().urlDecoded();
432 filepath.replace("|", ":"); // For Windows filepath processing - convert | to :
433
434 bool append = getMediaUrl().exists(p_append);
435
436 InfoLog(<< "SipXMediaResourceParticipant recording, handle=" << mHandle << " filepath=" << filepath << ", format=" << formatString << ", append=" << (append ? "YES" : "NO") << ", maxDurationMs=" << getDurationMs() << ", silenceTimeMs=" << silenceTimeMs);
437
438 // Note: If mediaStackAdapter.extraPlayAndRecordResourcesEnabled is disabled then there is a single multi-channel
439 // recording resource. If enabled, then there are two recording resources, one multichannel
440 // resources and one single channel recording resource. The numChannels parameter is only processed
441 // for the multichannel recording resource. Media URL scheme of "record-mc" is for the multichannel resource
442 // and "record" specifies to use the single channel recorder.
443 //
444 // For the multichannel resource (with numChannels set to 2 on the record operation; all participants are by
445 // default mixed to the left channel. Any participant with RecordChannelNum set to 2 will be mixed to
446 // the right channel.
447 //
448 // Caveats:
449 // 1. There are bugs in sipX with multi-channel GSM WAV recording.
450 // 2. There are bugs in sipX with multi-channel OPUS OGG recording.
451 // 3. Automatic trimming of silence is not supported for OPUS recordings.
452 OsStatus status = mediaInterface->getInterface()->recordAudio(
453 mSipXResourceName.c_str(),
454 filepath.c_str(),
455 format,
456 append /* append? */,
457 numChannels /* numChannels */,
458 getDurationMs() /* maxTime Ms */,
459 silenceTimeMs /* silenceLength Ms, -1 to disable */,
460 FALSE /* setupMixesAutomatically? */);
461 if (status == OS_SUCCESS)
462 {
463 setRunning(true);
464 }
465 else
466 {
467 WarningLog(<< "SipXMediaResourceParticipant::startResource error calling recordAudio: " << status);
468 }
469#endif
470 }
471 break;
472
473 case Invalid:
474 WarningLog(<< "SipXMediaResourceParticipant::startResource invalid resource type: " << getMediaUrl().scheme());
475 break;
476
477 default:
478 resip_assert(false);
479 }
480}
481
482bool
484{
485 bool okToDeleteNow = true;
486
487 if (isRunning())
488 {
489 switch (getResourceType())
490 {
491 case Tone:
492 {
493 OsStatus status = OS_FAILED;
494 bool isDtmf = (getMediaUrl().host().size() == 1);
495 if (isDtmf && getMediaUrl().exists(p_participantonly))
496 {
497 int partHandle = getMediaUrl().param(p_participantonly).convertInt();
498 SipXRemoteParticipant* participant = dynamic_cast<SipXRemoteParticipant*>(getConversationManager().getParticipant(partHandle));
499 if (participant)
500 {
501#ifdef SIPX_NO_RECORD
502 // Stop RFC4733 out-of-band tone
503 UtlString encodeName(DEFAULT_ENCODE_RESOURCE_NAME);
504 MpResourceTopology::replaceNumInName(encodeName, participant->getMediaConnectionId());
505 status = MprEncode::stopTone(encodeName, *getMediaInterface()->getInterface()->getMsgQ());
506#else
507 status = getMediaInterface()->getInterface()->stopChannelOnlyTone(participant->getMediaConnectionId());
508#endif
509 }
510 else
511 {
512 WarningLog(<< "SipXMediaResourceParticipant::stopResource participant " << partHandle << " no longer exists or invalid");
513 }
514 }
515 else
516 {
517#ifdef SIPX_NO_RECORD
518 status = getMediaInterface()->getInterface()->stopTone();
519#else
520 status = getMediaInterface()->getInterface()->stopTone(mSipXResourceName.c_str(), FALSE);
521#endif
522 }
523 if (status != OS_SUCCESS)
524 {
525 WarningLog(<< "SipXMediaResourceParticipant::stopResource error calling stopTone: " << status);
526 }
527 }
528 break;
529 case File:
530 case Cache:
531 case Buffer:
532 {
533#ifdef SIPX_NO_RECORD
534 OsStatus status = getMediaInterface()->getInterface()->stopAudio();
535#else
536 resip_assert(!mSipXResourceName.empty());
537 OsStatus status = getMediaInterface()->getInterface()->stopAudio(mSipXResourceName.c_str());
538#endif
539 if (status != OS_SUCCESS)
540 {
541 WarningLog(<< "SipXMediaResourceParticipant::stopResource error calling stopAudio: " << status);
542 }
543 }
544 break;
545 case Http:
546 case Https:
547 {
548 setRepeat(false); // Required so that player will not just repeat on stopped event
549
550#ifndef DISABLE_STREAM_PLAYER
551 OsStatus status = mStreamPlayer->stop();
552 if (status != OS_SUCCESS)
553 {
554 WarningLog(<< "SipXMediaResourceParticipant::stopResource error calling StreamPlayer::stop: " << status);
555 }
556 else
557 {
558 okToDeleteNow = false; // Wait for play finished event to come in
559 }
560#endif
561 }
562 break;
563 case Record:
565 {
566#ifndef SIPX_NO_RECORD
567 OsStatus status = getMediaInterface()->getInterface()->stopRecordAudio(mSipXResourceName.c_str());
568 if (status != OS_SUCCESS)
569 {
570 WarningLog(<< "SipXMediaResourceParticipant::stopResource error calling stopRecordAudio: " << status);
571 }
572#endif
573 }
574 break;
575 case Invalid:
576 WarningLog(<< "SipXMediaResourceParticipant::stopResource invalid resource type: " << getResourceType());
577 break;
578 default:
579 resip_assert(false);
580 }
581 }
582 return okToDeleteNow;
583}
584
585int
587{
588 if (mPortOnBridge == -1)
589 {
591
592 // Check if we have allocated a media resource yet or not
593 if (mSipXResourceName.empty())
594 {
595 if (!getMediaInterface()->allocateAvailableResourceForMediaOperation(getResourceType(), mHandle, mSipXResourceName))
596 {
597 WarningLog(<< "SipXMediaResourceParticipant::getConnectionPortOnBridge no available allocation for media participant of type=" << getResourceType());
598 return -1;
599 }
600 }
601 if (getResourceType() == Record ||
603 {
604#ifdef SIPX_NO_RECORD
605 ErrLog(<< "support for Record was not enabled at compile time");
606#else
607 getMediaInterface()->getInterface()->getResourceOutputPortOnBridge(mSipXResourceName.c_str(), 0, mPortOnBridge);
608#endif
609 }
610 else
611 {
612 getMediaInterface()->getInterface()->getResourceInputPortOnBridge(mSipXResourceName.c_str(), 0, mPortOnBridge);
613 }
614 InfoLog(<< "SipXMediaResourceParticipant getConnectionPortOnBridge, handle=" << mHandle << ", mPortOnBridge=" << mPortOnBridge);
615 }
616 resip_assert(mPortOnBridge != -1);
617 return mPortOnBridge;
618}
619
620void
622{
623 InfoLog(<< "SipXMediaResourceParticipant::playerRealized: handle=" << mHandle);
624
625#ifndef DISABLE_STREAM_PLAYER
626 if(isPrefetch())
627 {
628 OsStatus status = mStreamPlayer->prefetch(FALSE);
629 if(status != OS_SUCCESS)
630 {
631 WarningLog(<< "SipXMediaResourceParticipant::playerRealized error calling StreamPlayer::prefetch: " << status);
634 }
635 }
636 else
637 {
638 OsStatus status = mStreamPlayer->play(FALSE /*block?*/);
639 if(status != OS_SUCCESS)
640 {
641 WarningLog(<< "SipXMediaResourceParticipant::playerRealized error calling StreamPlayer::play: " << status);
644 }
645 }
646#endif
647}
648
649void
651{
652 InfoLog(<< "SipXMediaResourceParticipant::playerPrefetched: handle=" << mHandle);
653
654#ifndef DISABLE_STREAM_PLAYER
655 OsStatus status = mStreamPlayer->play(FALSE/*block?*/);
656 if(status != OS_SUCCESS)
657 {
658 WarningLog(<< "SipXMediaResourceParticipant::playerPrefetched error calling StreamPlayer::play: " << status);
661 }
662#endif
663}
664
665void
667{
668 InfoLog(<< "SipXMediaResourceParticipant::playerPlaying: handle=" << mHandle);
669}
670
671void
673{
674 InfoLog(<< "SipXMediaResourceParticipant::playerPaused: handle=" << mHandle);
675}
676
677void
679{
680 InfoLog(<< "SipXMediaResourceParticipant::playerStopped: handle=" << mHandle);
681 // We get this event when playing is completed
682 if(isRepeat())
683 {
684
685#ifndef DISABLE_STREAM_PLAYER
686 OsStatus status = mStreamPlayer->rewind(FALSE/*block?*/); // Generate playerPrefetched event
687 if(status != OS_SUCCESS)
688 {
689 WarningLog(<< "SipXMediaResourceParticipant::playerStopped error calling StreamPlayer::rewind: " << status);
692 }
693#endif
694 }
695 else
696 {
699 }
700}
701
702void
704{
705 InfoLog(<< "SipXMediaResourceParticipant::playerFailed: handle=" << mHandle);
708}
709
710
711/* ====================================================================
712
713 Copyright (c) 2021-2023, SIP Spectrum, Inc. http://www.sipspectrum.com
714 Copyright (c) 2021, Daniel Pocock https://danielpocock.com
715 Copyright (c) 2007-2008, Plantronics, Inc.
716 All rights reserved.
717
718 Redistribution and use in source and binary forms, with or without
719 modification, are permitted provided that the following conditions are
720 met:
721
722 1. Redistributions of source code must retain the above copyright
723 notice, this list of conditions and the following disclaimer.
724
725 2. Redistributions in binary form must reproduce the above copyright
726 notice, this list of conditions and the following disclaimer in the
727 documentation and/or other materials provided with the distribution.
728
729 3. Neither the name of Plantronics nor the names of its contributors
730 may be used to endorse or promote products derived from this
731 software without specific prior written permission.
732
733 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
734 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
735 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
736 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
737 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
738 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
739 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
740 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
741 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
742 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
743 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
744
745 ==================================================================== */
#define StackLog(args_)
Definition Logger.hxx:125
#define InfoLog(args_)
Definition Logger.hxx:131
#define WarningLog(args_)
Definition Logger.hxx:134
#define ErrLog(args_)
Definition Logger.hxx:137
#define resip_assert(x)
This file needs to work for both C and C++ code.
static const resip::ExtensionParameter p_participantonly("participant-only")
static const resip::ExtensionParameter p_silencetime("silencetime")
static const resip::ExtensionParameter p_append("append")
static const resip::ExtensionParameter p_numchannels("numchannels")
static const resip::ExtensionParameter p_format("format")
static const struct nv flags[]
Definition adig.c:62
This class is one of two main classes of concern to an application using the UserAgent library.
void post(resip::Message *message)
This class represents a media resource participant.
virtual ConversationManager & getConversationManager()
virtual const std::shared_ptr< resip::Data > & getAudioBuffer()
This is the base class for a RemoteParticipant, LocalParticipant and a MediaResourceParticipant.
virtual void unregisterFromAllConversations()
ParticipantHandle mHandle
CpTopologyGraphInterface * getInterface()
virtual void playerPrefetched(MpPlayerEvent &event)
virtual void playerStopped(MpPlayerEvent &event)
virtual void playerRealized(MpPlayerEvent &event)
SipXMediaResourceParticipant(ParticipantHandle partHandle, ConversationManager &conversationManager, SipXMediaStackAdapter &sipXMediaStackAdapter, const resip::Uri &mediaUrl, const std::shared_ptr< resip::Data > &playAudioBuffer, void *recordingCircularBuffer)
virtual void playerPlaying(MpPlayerEvent &event)
virtual void playerFailed(MpPlayerEvent &event)
virtual void playerPaused(MpPlayerEvent &event)
This class is one of two main classes of concern to an application using the UserAgent library.
This is the base class for a SipXRemoteParticipant, SipXLocalParticipant and a SipXMediaResourceParti...
virtual std::shared_ptr< SipXMediaInterface > getMediaInterface()
This class represent a remote participant.
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
const char * c_str() const
Returns a null-terminated string representing.
Definition Data.cxx:1097
char & at(size_type p)
Returns the character at the specified position.
Definition Data.cxx:988
int replace(const Data &match, const Data &target, int max=INT_MAX)
Replaces up to max occurrences of the bytes match with target.
Definition Data.cxx:1964
unsigned long convertUnsignedLong() const
Definition Data.cxx:1724
bool empty() const noexcept
Checks whether the Data is empty.
Definition Data.hxx:591
Data urlDecoded() const
Performs in-place HTTP URL un-escaping of a Data.
Definition Data.cxx:1341
size_type size() const noexcept
Returns the number of bytes in this Data.
Definition Data.hxx:599
static Data from(const T &x)
Converts from arbitrary other type to Data.
Definition Data.hxx:398
int convertInt() const
Takes the contents of the Data and converts them to an integer.
Definition Data.cxx:1684
const char * data() const noexcept
Returns a pointer to the contents of this Data.
Definition Data.hxx:608
Represents the "SIP-URI" and "SIPS-URI" elements in the RFC 3261 grammar.
Definition Uri.hxx:22
bool exists(const Param< Uri > &paramType) const
Definition Uri.cxx:1701
Data & host()
Definition Uri.hxx:40
const Data & param(const ExtensionParameter &param) const
Const accessor for non-natively-supported parameter types.
static const resip::Data ringTone("ring")
static const resip::Data recordingFormatWAVGSM("WAV_GSM")
static const resip::Data recordingFormatOGGOPUS("OGG_OPUS")
static const resip::Data recordingFormatWAVMULAW("WAV_MULAW")
static const resip::Data backspaceTone("backspace")
static const resip::Data holdingTone("holding")
unsigned int ParticipantHandle
static const resip::Data busyTone("busy")
static const resip::Data fastbusyTone("fastbusy")
static const resip::Data loudfastbusyTone("loudfastbusy")
static const resip::Data recordingFormatWAVALAW("WAV_ALAW")
static const resip::Data recordingFormatWAVPCM16("WAV_PCM16")
static const resip::Data callwaitingTone("callwaiting")
static const resip::Data ringbackTone("ringback")
static const resip::Data dialtoneTone("dialtone")
dcm! – add UnusedChecking(_enum) below;
bool isEqualNoCase(const Data &left, const Data &right)
Definition Data.hxx:1116