media/webrtc/signaling/src/softphonewrapper/CC_SIPCCCall.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:e5f6fc0cbae1
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 #include "CSFLog.h"
6 #include "timecard.h"
7
8 #include "CC_Common.h"
9
10 #include "CC_SIPCCCall.h"
11 #include "CC_SIPCCCallInfo.h"
12 #include "VcmSIPCCBinding.h"
13 #include "CSFVideoTermination.h"
14 #include "CSFAudioTermination.h"
15 #include "CSFAudioControl.h"
16
17 extern "C"
18 {
19 #include "ccapi_call.h"
20 #include "ccapi_call_listener.h"
21 #include "config_api.h"
22 }
23
24 using namespace std;
25 using namespace CSF;
26
27 static const char* logTag = "CC_SIPCCCall";
28
29 CSF_IMPLEMENT_WRAP(CC_SIPCCCall, cc_call_handle_t);
30
31 CC_SIPCCCall::CC_SIPCCCall (cc_call_handle_t aCallHandle) :
32 callHandle(aCallHandle),
33 pMediaData(new CC_SIPCCCallMediaData(nullptr, false, false, -1)),
34 m_lock("CC_SIPCCCall")
35 {
36 CSFLogInfo( logTag, "Creating CC_SIPCCCall %u", callHandle );
37
38 AudioControl * audioControl = VcmSIPCCBinding::getAudioControl();
39
40 if(audioControl)
41 {
42 pMediaData->volume = audioControl->getDefaultVolume();
43 }
44 }
45
46
47 /*
48 CCAPI_CALL_EV_CAPABILITY -- From phone team: "...CCAPI_CALL_EV_CAPABILITY is generated for the capability changes but we decided to
49 suppress it if it's due to state changes. We found it redundant as a state change implicitly implies a
50 capability change. This event will still be generated if the capability changes without a state change.
51 CCAPI_CALL_EV_CALLINFO -- From phone team: "...CCAPI_CALL_EV_CALLINFO is generated for any caller id related changes including
52 called/calling/redirecting name/number etc..."
53 CCAPI_CALL_EV_PLACED_CALLINFO -- From phone team: "CCAPI_CALL_EV_PLACED_CALLINFO was a trigger to update the placed call history and
54 gives the actual number dialed out. I think this event can be deprecated."
55 */
56
57 /*
58 CallState
59
60 REORDER: You get this if you misdial a number.
61 */
62
63 // This function sets the remote window parameters for the call. Note that it currently only tolerates a single
64 // video stream on the call and would need to be updated to handle multiple remote video streams for conferencing.
65 void CC_SIPCCCall::setRemoteWindow (VideoWindowHandle window)
66 {
67 VideoTermination * pVideo = VcmSIPCCBinding::getVideoTermination();
68 pMediaData->remoteWindow = window;
69
70 if (!pVideo)
71 {
72 CSFLogWarn( logTag, "setRemoteWindow: no video provider found");
73 return;
74 }
75
76 for (StreamMapType::iterator entry = pMediaData->streamMap.begin(); entry != pMediaData->streamMap.end(); entry++)
77 {
78 if (entry->second.isVideo)
79 {
80 // first video stream found
81 int streamId = entry->first;
82 pVideo->setRemoteWindow(streamId, pMediaData->remoteWindow);
83
84 return;
85 }
86 }
87 CSFLogInfo( logTag, "setRemoteWindow:no video stream found in call %u", callHandle );
88 }
89
90 int CC_SIPCCCall::setExternalRenderer(VideoFormat vFormat, ExternalRendererHandle renderer)
91 {
92 VideoTermination * pVideo = VcmSIPCCBinding::getVideoTermination();
93 pMediaData->extRenderer = renderer;
94 pMediaData->videoFormat = vFormat;
95
96 if (!pVideo)
97 {
98 CSFLogWarn( logTag, "setExternalRenderer: no video provider found");
99 return -1;
100 }
101
102 for (StreamMapType::iterator entry = pMediaData->streamMap.begin(); entry != pMediaData->streamMap.end(); entry++)
103 {
104 if (entry->second.isVideo)
105 {
106 // first video stream found
107 int streamId = entry->first;
108 return pVideo->setExternalRenderer(streamId, pMediaData->videoFormat, pMediaData->extRenderer);
109 }
110 }
111 CSFLogInfo( logTag, "setExternalRenderer:no video stream found in call %u", callHandle );
112 return -1;
113 }
114
115 void CC_SIPCCCall::sendIFrame()
116 {
117 VideoTermination * pVideo = VcmSIPCCBinding::getVideoTermination();
118
119 if (pVideo)
120 {
121 pVideo->sendIFrame(callHandle);
122 }
123 }
124
125 CC_CallInfoPtr CC_SIPCCCall::getCallInfo ()
126 {
127 cc_callinfo_ref_t callInfo = CCAPI_Call_getCallInfo(callHandle);
128 CC_SIPCCCallInfoPtr callInfoPtr = CC_SIPCCCallInfo::wrap(callInfo);
129 callInfoPtr->setMediaData( pMediaData);
130 return callInfoPtr.get();
131 }
132
133
134 //
135 // Operations - The following function are actions that can be taken the execute an operation on the Call, ie calls
136 // down to pSIPCC to originate a call, end a call etc.
137 //
138
139 bool CC_SIPCCCall::originateCall (cc_sdp_direction_t video_pref, const string & digits)
140 {
141 return (CCAPI_Call_originateCall(callHandle, video_pref, digits.c_str()) == CC_SUCCESS);
142 }
143
144 bool CC_SIPCCCall::answerCall (cc_sdp_direction_t video_pref)
145 {
146 return (CCAPI_Call_answerCall(callHandle, video_pref) == CC_SUCCESS);
147 }
148
149 bool CC_SIPCCCall::hold (cc_hold_reason_t reason)
150 {
151 return (CCAPI_Call_hold(callHandle, reason) == CC_SUCCESS);
152 }
153
154 bool CC_SIPCCCall::resume (cc_sdp_direction_t video_pref)
155 {
156 return (CCAPI_Call_resume(callHandle, video_pref) == CC_SUCCESS);
157 }
158
159 bool CC_SIPCCCall::endCall()
160 {
161 return (CCAPI_Call_endCall(callHandle) == CC_SUCCESS);
162 }
163
164 bool CC_SIPCCCall::sendDigit (cc_digit_t digit)
165 {
166 AudioTermination * pAudio = VcmSIPCCBinding::getAudioTermination();
167 mozilla::MutexAutoLock lock(m_lock);
168
169 // Convert public digit (as enum or char) to RFC2833 form.
170 int digitId = -1;
171 switch(digit)
172 {
173 case '0':
174 digitId = 0;
175 break;
176 case '1':
177 digitId = 1;
178 break;
179 case '2':
180 digitId = 2;
181 break;
182 case '3':
183 digitId = 3;
184 break;
185 case '4':
186 digitId = 4;
187 break;
188 case '5':
189 digitId = 5;
190 break;
191 case '6':
192 digitId = 6;
193 break;
194 case '7':
195 digitId = 7;
196 break;
197 case '8':
198 digitId = 8;
199 break;
200 case '9':
201 digitId = 9;
202 break;
203 case '*':
204 digitId = 10;
205 break;
206 case '#':
207 digitId = 11;
208 break;
209 case 'A':
210 digitId = 12;
211 break;
212 case 'B':
213 digitId = 13;
214 break;
215 case 'C':
216 digitId = 14;
217 break;
218 case 'D':
219 digitId = 15;
220 break;
221 case '+':
222 digitId = 16;
223 break;
224 }
225
226 for (StreamMapType::iterator entry = pMediaData->streamMap.begin(); entry != pMediaData->streamMap.end(); entry++)
227 {
228 if (entry->second.isVideo == false)
229 {
230 // first is the streamId
231 if (pAudio->sendDtmf(entry->first, digitId) != 0)
232 {
233 // We have sent a digit, done.
234 break;
235 }
236 else
237 {
238 CSFLogWarn( logTag, "sendDigit:sendDtmf returned fail");
239 }
240 }
241 }
242 return (CCAPI_Call_sendDigit(callHandle, digit) == CC_SUCCESS);
243 }
244
245 bool CC_SIPCCCall::backspace()
246 {
247 return (CCAPI_Call_backspace(callHandle) == CC_SUCCESS);
248 }
249
250 bool CC_SIPCCCall::redial (cc_sdp_direction_t video_pref)
251 {
252 return (CCAPI_Call_redial(callHandle, video_pref) == CC_SUCCESS);
253 }
254
255 bool CC_SIPCCCall::initiateCallForwardAll()
256 {
257 return (CCAPI_Call_initiateCallForwardAll(callHandle) == CC_SUCCESS);
258 }
259
260 bool CC_SIPCCCall::endConsultativeCall()
261 {
262 return (CCAPI_Call_endConsultativeCall(callHandle) == CC_SUCCESS);
263 }
264
265 bool CC_SIPCCCall::conferenceStart (cc_sdp_direction_t video_pref)
266 {
267 return (CCAPI_Call_conferenceStart(callHandle, video_pref) == CC_SUCCESS);
268 }
269
270 bool CC_SIPCCCall::conferenceComplete (CC_CallPtr otherLeg, cc_sdp_direction_t video_pref)
271 {
272 return (CCAPI_Call_conferenceComplete(callHandle, ((CC_SIPCCCall*)otherLeg.get())->callHandle, video_pref) == CC_SUCCESS);
273 }
274
275 bool CC_SIPCCCall::transferStart (cc_sdp_direction_t video_pref)
276 {
277 return (CCAPI_Call_transferStart(callHandle, video_pref) == CC_SUCCESS);
278 }
279
280 bool CC_SIPCCCall::transferComplete (CC_CallPtr otherLeg,
281 cc_sdp_direction_t video_pref)
282 {
283 return (CCAPI_Call_transferComplete(callHandle, ((CC_SIPCCCall*)otherLeg.get())->callHandle, video_pref) == CC_SUCCESS);
284 }
285
286 bool CC_SIPCCCall::cancelTransferOrConferenceFeature()
287 {
288 return (CCAPI_Call_cancelTransferOrConferenceFeature(callHandle) == CC_SUCCESS);
289 }
290
291 bool CC_SIPCCCall::directTransfer (CC_CallPtr target)
292 {
293 return (CCAPI_Call_directTransfer(callHandle, ((CC_SIPCCCall*)target.get())->callHandle) == CC_SUCCESS);
294 }
295
296 bool CC_SIPCCCall::joinAcrossLine (CC_CallPtr target)
297 {
298 return (CCAPI_Call_joinAcrossLine(callHandle, ((CC_SIPCCCall*)target.get())->callHandle) == CC_SUCCESS);
299 }
300
301 bool CC_SIPCCCall::blfCallPickup (cc_sdp_direction_t video_pref, const string & speed)
302 {
303 return (CCAPI_Call_blfCallPickup(callHandle, video_pref, speed.c_str()) == CC_SUCCESS);
304 }
305
306 bool CC_SIPCCCall::select()
307 {
308 return (CCAPI_Call_select(callHandle) == CC_SUCCESS);
309 }
310
311 bool CC_SIPCCCall::updateVideoMediaCap (cc_sdp_direction_t video_pref)
312 {
313 return (CCAPI_Call_updateVideoMediaCap(callHandle, video_pref) == CC_SUCCESS);
314 }
315
316 bool CC_SIPCCCall::sendInfo (const string & infopackage, const string & infotype, const string & infobody)
317 {
318 return (CCAPI_Call_sendInfo(callHandle, infopackage.c_str(), infotype.c_str(), infobody.c_str()) == CC_SUCCESS);
319 }
320
321 bool CC_SIPCCCall::muteAudio(void)
322 {
323 return setAudioMute(true);
324 }
325
326 bool CC_SIPCCCall::unmuteAudio()
327 {
328 return setAudioMute(false);
329 }
330
331 bool CC_SIPCCCall::muteVideo()
332 {
333 return setVideoMute(true);
334 }
335
336 bool CC_SIPCCCall::unmuteVideo()
337 {
338 return setVideoMute(false);
339 }
340
341 bool CC_SIPCCCall::setAudioMute(bool mute)
342 {
343 bool returnCode = false;
344 AudioTermination * pAudio = VcmSIPCCBinding::getAudioTermination();
345 pMediaData->audioMuteState = mute;
346 // we need to set the mute status of all audio streams in the map
347 {
348 mozilla::MutexAutoLock lock(m_lock);
349 for (StreamMapType::iterator entry = pMediaData->streamMap.begin(); entry != pMediaData->streamMap.end(); entry++)
350 {
351 if (entry->second.isVideo == false)
352 {
353 // first is the streamId
354 if (pAudio->mute(entry->first, mute))
355 {
356 // We have muted at least one stream
357 returnCode = true;
358 }
359 else
360 {
361 CSFLogWarn( logTag, "setAudioMute:audio mute returned fail");
362 }
363 }
364 }
365 }
366
367 if (CCAPI_Call_setAudioMute(callHandle, mute) != CC_SUCCESS)
368 {
369 returnCode = false;
370 }
371
372 return returnCode;
373 }
374
375 bool CC_SIPCCCall::setVideoMute(bool mute)
376 {
377 bool returnCode = false;
378 VideoTermination * pVideo = VcmSIPCCBinding::getVideoTermination();
379 pMediaData->videoMuteState = mute;
380 // we need to set the mute status of all audio streams in the map
381 {
382 mozilla::MutexAutoLock lock(m_lock);
383 for (StreamMapType::iterator entry = pMediaData->streamMap.begin(); entry != pMediaData->streamMap.end(); entry++)
384 {
385 if (entry->second.isVideo == true)
386 {
387 // first is the streamId
388 if (pVideo->mute(entry->first, mute))
389 {
390 // We have muted at least one stream
391 returnCode = true;
392 }
393 else
394 {
395 CSFLogWarn( logTag, "setVideoMute:video mute returned fail");
396 }
397 }
398 }
399 }
400
401 if (CCAPI_Call_setVideoMute(callHandle, mute) != CC_SUCCESS)
402 {
403 returnCode = false;
404 }
405
406 return returnCode;
407 }
408
409 void CC_SIPCCCall::addStream(int streamId, bool isVideo)
410 {
411
412 CSFLogInfo( logTag, "addStream: %d video=%s callhandle=%u",
413 streamId, isVideo ? "TRUE" : "FALSE", callHandle);
414 {
415 mozilla::MutexAutoLock lock(m_lock);
416 pMediaData->streamMap[streamId].isVideo = isVideo;
417 }
418 // The new stream needs to be given any properties that the call has for it.
419 // At the moment the only candidate is the muted state
420 if (isVideo)
421 {
422 #ifndef NO_WEBRTC_VIDEO
423 VideoTermination * pVideo = VcmSIPCCBinding::getVideoTermination();
424
425 // if there is a window for this call apply it to the stream
426 if ( pMediaData->remoteWindow != nullptr)
427 {
428 pVideo->setRemoteWindow(streamId, pMediaData->remoteWindow);
429 }
430 else
431 {
432 CSFLogInfo( logTag, "addStream: remoteWindow is NULL");
433 }
434
435 if(pMediaData->extRenderer != nullptr)
436 {
437 pVideo->setExternalRenderer(streamId, pMediaData->videoFormat, pMediaData->extRenderer);
438 }
439 else
440 {
441 CSFLogInfo( logTag, "addStream: externalRenderer is NULL");
442
443 }
444
445
446 for (StreamMapType::iterator entry = pMediaData->streamMap.begin(); entry != pMediaData->streamMap.end(); entry++)
447 {
448 if (entry->second.isVideo == false)
449 {
450 // first is the streamId
451 pVideo->setAudioStreamId(entry->first);
452 }
453 }
454 if (!pVideo->mute(streamId, pMediaData->videoMuteState))
455 {
456 CSFLogError( logTag, "setting video mute state failed for new stream: %d", streamId);
457 } else
458 {
459 CSFLogError( logTag, "setting video mute state SUCCEEDED for new stream: %d", streamId);
460
461 }
462 #endif
463 }
464 else
465 {
466 AudioTermination * pAudio = VcmSIPCCBinding::getAudioTermination();
467 if (!pAudio->mute(streamId, pMediaData->audioMuteState))
468 {
469 CSFLogError( logTag, "setting audio mute state failed for new stream: %d", streamId);
470 }
471 if (!pAudio->setVolume(streamId, pMediaData->volume))
472 {
473 CSFLogError( logTag, "setting volume state failed for new stream: %d", streamId);
474 }
475 }
476 }
477
478 void CC_SIPCCCall::removeStream(int streamId)
479 {
480 mozilla::MutexAutoLock lock(m_lock);
481
482 if ( pMediaData->streamMap.erase(streamId) != 1)
483 {
484 CSFLogError( logTag, "removeStream stream that was never in the streamMap: %d", streamId);
485 }
486 }
487
488 bool CC_SIPCCCall::setVolume(int volume)
489 {
490 bool returnCode = false;
491
492 AudioTermination * pAudio = VcmSIPCCBinding::getAudioTermination();
493 {
494 mozilla::MutexAutoLock lock(m_lock);
495 for (StreamMapType::iterator entry = pMediaData->streamMap.begin(); entry != pMediaData->streamMap.end(); entry++)
496 {
497 if (entry->second.isVideo == false)
498 {
499 // first is the streamId
500 int streamId = entry->first;
501 if (pAudio->setVolume(streamId, volume))
502 {
503 //We have changed the volume on at least one stream,
504 //so persist the new volume as the call volume,
505 //and report success for the volume change, even if it
506 //fails on other streams
507 pMediaData->volume = volume;
508 returnCode = true;
509 }
510 else
511 {
512 CSFLogWarn( logTag, "setVolume:set volume on stream %d returned fail",
513 streamId);
514 }
515 }
516 }
517 }
518 return returnCode;
519 }
520
521 CC_SIPCCCallMediaDataPtr CC_SIPCCCall::getMediaData()
522 {
523 return pMediaData;
524 }
525
526 void CC_SIPCCCall::originateP2PCall (cc_sdp_direction_t video_pref, const std::string & digits, const std::string & ip)
527 {
528 CCAPI_Config_set_server_address(ip.c_str());
529 CCAPI_Call_originateCall(callHandle, video_pref, digits.c_str());
530 }
531
532 /*
533 * This method works asynchronously, is an onCallEvent with the resulting SDP
534 */
535 void CC_SIPCCCall::createOffer (cc_media_constraints_t *constraints,
536 Timecard *tc) {
537 CCAPI_CreateOffer(callHandle, constraints, tc);
538 }
539 /*
540 * This method works asynchronously, there is onCallEvent with the resulting SDP
541 */
542 void CC_SIPCCCall::createAnswer (cc_media_constraints_t *constraints,
543 Timecard *tc) {
544 CCAPI_CreateAnswer(callHandle, constraints, tc);
545
546 }
547
548 void CC_SIPCCCall::setLocalDescription(cc_jsep_action_t action,
549 const std::string & sdp,
550 Timecard *tc) {
551 CCAPI_SetLocalDescription(callHandle, action, sdp.c_str(), tc);
552 }
553
554 void CC_SIPCCCall::setRemoteDescription(cc_jsep_action_t action,
555 const std::string & sdp,
556 Timecard *tc) {
557 CCAPI_SetRemoteDescription(callHandle, action, sdp.c_str(), tc);
558 }
559
560 void CC_SIPCCCall::setPeerConnection(const std::string& handle)
561 {
562 CSFLogDebug(logTag, "setPeerConnection");
563
564 peerconnection = handle; // Cache this here. we need it to make the CC_SIPCCCallInfo
565 CCAPI_SetPeerConnection(callHandle, handle.c_str());
566 }
567
568 const std::string& CC_SIPCCCall::getPeerConnection() const {
569 return peerconnection;
570 }
571
572 void CC_SIPCCCall::addStream(cc_media_stream_id_t stream_id,
573 cc_media_track_id_t track_id,
574 cc_media_type_t media_type,
575 cc_media_constraints_t *constraints) {
576 CCAPI_AddStream(callHandle, stream_id, track_id, media_type, constraints);
577 }
578
579 void CC_SIPCCCall::removeStream(cc_media_stream_id_t stream_id, cc_media_track_id_t track_id, cc_media_type_t media_type) {
580 CCAPI_RemoveStream(callHandle, stream_id, track_id, media_type);
581 }
582
583 void CC_SIPCCCall::addICECandidate(const std::string & candidate,
584 const std::string & mid,
585 unsigned short level,
586 Timecard *tc) {
587 CCAPI_AddICECandidate(callHandle, candidate.c_str(), mid.c_str(),
588 (cc_level_t) level, tc);
589 }

mercurial