TT#20504 Call: As a Customer, I want to initiate an audio/video call

- Call: Implement ringing state
- Call: Implement pending state
- Call: Implement call cancellation

Change-Id: Ia38f5a7867c1eba6677b71893549a7b21fdd9ef2
changes/60/15160/2
Hans-Peter Herzog 8 years ago committed by Robert Axelsen
parent 4d27a8fd36
commit d3a43fa47a

@ -100,3 +100,67 @@ $border-radius : 50%;
.rtc-button-margin { .rtc-button-margin {
margin: 0 50px 0 0; margin: 0 50px 0 0;
} }
.call-button {
border-radius: 50%;
background-color: #16b603;
color: white;
border-width: 0;
}
.call-button * {
font-size: 22px;
}
.call-button .icon-large {
font-size: 22px;
position: absolute;
bottom: 0px;
left: 2px;
}
.call-button .icon-small {
font-size: 11px;
position: absolute;
top: 2px;
right: 3px;
}
.call-button-cancel {
background-color: red;
}
.call-button-accept {
background-color: forestgreen;
}
.call-icon-cancel {
position: absolute;
transform: rotate(135deg);
font-size: 22px;
top: 2px;
left: 4px;
}
.call-button-cancel.x-btn.x-btn-pressed,
.call-button-cancel-focus,
.call-button-cancel-over {
background-color: darkred;
}
.call-button-accept.x-btn.x-btn-pressed,
.call-button-accept-focus,
.call-button-accept-over {
background-color: darkgreen;
}
#call-local-preview {
width: 100%;
}
.x-panel-body-default {
label.call-number-label {
font-size: 16px;
font-weight: bold;
}
}

@ -1,18 +1,51 @@
Ext.define('NgcpCsc.view.common.rtc.CallPanel', { Ext.define('NgcpCsc.view.common.rtc.CallPanel', {
extend: 'Ext.form.Panel', extend: 'Ext.form.Panel',
alias: 'widget.call-panel', alias: 'widget.call-panel',
layout: 'center', padding: '60 0 0 0',
bind: { bind: {
hidden: '{!callPanel}' hidden: '{!callEnabled}'
}, },
items: [{ items: [{
bind: { layout : {
hidden: '{!outgoingCallPending}' type : 'vbox',
}, align : 'center',
xtype: 'label', pack: 'center',
userCls: 'rtc-outgoing-label',
html: Ngcp.csc.locales.rtc.start_call[localStorage.getItem('languageSelected')] + Ngcp.csc.animations.loading_dots },
bind: {
hidden: '{!outgoingCall}'
}, },
items: [
{
bind: {
text: '{callActionLabel}'
},
xtype: 'label',
margin: '0 0 20 0'
},
{
bind: {
text: '{numberToCall}'
},
xtype: 'label',
margin: '0 0 20 0',
userCls: 'call-number-label',
},
{
xtype: 'button',
text: '',
userCls: 'call-button call-button-cancel call-button-hangup',
overCls: 'call-button-cancel-over',
focusCls: 'call-button-cancel-focus',
width: 40,
height: 40,
html: '<i class="x-fa fa-phone call-icon-cancel"></i>',
listeners: {
click: 'cancelOutgoingCall'
}
}
]},
{ {
bind: { bind: {
hidden: '{!incomingCallPending}' hidden: '{!incomingCallPending}'

@ -27,12 +27,26 @@ Ext.define('NgcpCsc.view.common.rtc.RtcController', {
}, },
initCall: function(mediaType) { initCall: function(mediaType) {
var $ct = this; var $ct = this;
var $vm = this.getViewModel(); var $vm = this.getViewModel();
var callee = $vm.get('numberToCall'); var callee = $vm.get('numberToCall');
var network = $vm.get('rtcEngineNetwork'); var network = $vm.get('rtcEngineNetwork');
var localMediaStream = $vm.get('rtcEngineLocalMediaStream');
if (callee !== '' && callee !== null && callee !== void(0)) { if (callee !== '' && callee !== null && callee !== void(0)) {
if(localMediaStream !== null) {
localMediaStream.stop();
$vm.set('rtcEngineLocalMediaStream', null);
}
this.createMedia(mediaType).then(function (localMediaStream) { this.createMedia(mediaType).then(function (localMediaStream) {
// Todo: attache stream to video element
// if(mediaType === 'video') {
// cdk.MediaElementHelper.attachStreamToDomNode(
// document.getElementById('call-local-preview'),
// localMediaStream
// );
// }
var call = network.call(callee, { localMediaStream: localMediaStream }); var call = network.call(callee, { localMediaStream: localMediaStream });
call.onPending(function () { $ct.outgoingPending(); }) call.onPending(function () { $ct.outgoingPending(); })
.onAccepted(function () { $ct.outgoingAccepted(); }) .onAccepted(function () { $ct.outgoingAccepted(); })
@ -96,7 +110,7 @@ Ext.define('NgcpCsc.view.common.rtc.RtcController', {
vm.set('title', Ext.String.format(Ngcp.csc.locales.rtc.calling[localStorage.getItem('languageSelected')], number)); vm.set('title', Ext.String.format(Ngcp.csc.locales.rtc.calling[localStorage.getItem('languageSelected')], number));
vm.set('thumbnail', record.get('thumbnail') || this.getViewModel().get('defaultThumbnail')); vm.set('thumbnail', record.get('thumbnail') || this.getViewModel().get('defaultThumbnail'));
vm.set('status', Ext.String.format(Ngcp.csc.locales.rtc.calling[localStorage.getItem('languageSelected')] + ' ...', number)); vm.set('status', Ext.String.format(Ngcp.csc.locales.rtc.calling[localStorage.getItem('languageSelected')] + ' ...', number));
vm.set('callEnabled', false); vm.set('callPanelEnabled', false);
vm.set('micEnabled', false); vm.set('micEnabled', false);
vm.set('phoneComposerHidden', true); vm.set('phoneComposerHidden', true);
vm.set('faxComposerHidden', true); vm.set('faxComposerHidden', true);
@ -146,9 +160,6 @@ Ext.define('NgcpCsc.view.common.rtc.RtcController', {
vm.set('callPanelHidden', true); vm.set('callPanelHidden', true);
fieldToFocus = this.lookupReference('smsTextArea'); fieldToFocus = this.lookupReference('smsTextArea');
break; break;
case 'incomingCall':
me.showIncomingCallPendingState();
break;
} }
panel.show().expand(); panel.show().expand();
if (fieldToFocus) { if (fieldToFocus) {
@ -221,7 +232,7 @@ Ext.define('NgcpCsc.view.common.rtc.RtcController', {
setTimeout(function() { setTimeout(function() {
var seconds = minutes = hours = 0; var seconds = minutes = hours = 0;
me.stopRingSound(); me.stopRingSound();
vm.set('callEnabled', true); vm.set('callPanelEnabled', true);
vm.set('micEnabled', true); vm.set('micEnabled', true);
me.startMedia(audioOn, videoOn); me.startMedia(audioOn, videoOn);
@ -264,7 +275,7 @@ Ext.define('NgcpCsc.view.common.rtc.RtcController', {
}, },
toggleCall: function(btn) { toggleCall: function(btn) {
if (btn.pressed) { // this can be also checked against vm.get('callEnabled') if (btn.pressed) { // this can be also checked against vm.get('callPanelEnabled')
this.emulateCall(true, false); this.emulateCall(true, false);
} else { } else {
this.endCall(); this.endCall();
@ -439,22 +450,22 @@ Ext.define('NgcpCsc.view.common.rtc.RtcController', {
var rtcNetwork = rtcClient.getNetworkByTag('sip'); var rtcNetwork = rtcClient.getNetworkByTag('sip');
$vm.set('rtcEngineNetwork', rtcNetwork); $vm.set('rtcEngineNetwork', rtcNetwork);
rtcNetwork.onConnect(function() { rtcNetwork.onConnect(function() {
$vm.set('callEnabled', true); $vm.set('callPanelEnabled', true);
}).onIncomingCall(function(call) { }).onIncomingCall(function(call) {
call.onPending(function(){ $ct.incomingCallPending(); }) $ct.incomingCallPending();
.onRemoteMedia(function(stream){ $ct.incomingRemoteMedia(stream); }) call.onRemoteMedia(function(stream){ $ct.incomingRemoteMedia(stream); })
.onRemoteMediaEnded(function(){ $ct.incomingRemoteMediaEnded(); }) .onRemoteMediaEnded(function(){ $ct.incomingRemoteMediaEnded(); })
.onEnded(function(){ $ct.incomingRemoteMediaEnded() }); .onEnded(function(){ $ct.incomingRemoteMediaEnded() });
}).onDisconnect(function(){ }).onDisconnect(function(){
$vm.set('callEnabled', false); $vm.set('callPanelEnabled', false);
$vm.set('callDisabledReason', rtcNetwork.disconnectReason); $vm.set('callDisabledReason', rtcNetwork.disconnectReason);
}); });
}).onDisconnect(function(){ }).onDisconnect(function(){
$vm.set('callEnabled', false); $vm.set('callPanelEnabled', false);
$vm.set('callDisabledReason', rtcClient.disconnectReason); $vm.set('callDisabledReason', rtcClient.disconnectReason);
}); });
}).catch(function(err){ }).catch(function(err){
$vm.set('callEnabled', false); $vm.set('callPanelEnabled', false);
$vm.set('callDisabledReason', err.message); $vm.set('callDisabledReason', err.message);
console.error(err); console.error(err);
}); });
@ -471,10 +482,12 @@ Ext.define('NgcpCsc.view.common.rtc.RtcController', {
outgoingRingingStart: function() { outgoingRingingStart: function() {
console.log('outgoingCallRingingStart'); console.log('outgoingCallRingingStart');
this.showOutgoingCallRingingState();
}, },
outgoingRingingStop: function() { outgoingRingingStop: function() {
console.log('outgoingCallRingingStop'); console.log('outgoingCallRingingStop');
this.stopRingSound();
}, },
outgoingRemoteMedia: function(stream) { outgoingRemoteMedia: function(stream) {
@ -491,6 +504,8 @@ Ext.define('NgcpCsc.view.common.rtc.RtcController', {
}, },
incomingCallPending: function() { incomingCallPending: function() {
this.getView().show().expand();
this.showIncomingCallPendingState();
console.log('incomingCallPending'); console.log('incomingCallPending');
}, },
@ -510,13 +525,38 @@ Ext.define('NgcpCsc.view.common.rtc.RtcController', {
callEnded: function() { callEnded: function() {
var $ct = this; var $ct = this;
var $vm = $ct.getViewModel(); var $vm = $ct.getViewModel();
var localMediaStream = $vm.get('rtcEngineLocalMediaStream'); },
if(localMediaStream !== null) {
localMediaStream.stop(); cancelOutgoingCall: function() {
$vm.set('rtcEngineLocalMediaStream', null); var call = this.getViewModel().get('rtcEngineCall');
var mediaStream = this.getViewModel().get('rtcEngineLocalMediaStream');
this.getViewModel().set('phoneComposerHidden', false);
this.getViewModel().set('callPending', false);
this.getViewModel().set('callRinging', false);
this.stopRingSound();
if(call !== null) {
call.end();
} }
if(mediaStream !== null) {
mediaStream.stop();
}
},
showOutgoingCallPendingState: function() {
this.getViewModel().set('callPending', true);
this.getViewModel().set('callActionLabel', 'Try to call');
this.getViewModel().set('phoneComposerHidden', true);
}, },
showOutgoingCallRingingState: function() {
this.getViewModel().set('callRinging', true);
this.getViewModel().set('callPending', false);
this.getViewModel().set('callActionLabel', 'Ringing');
this.playRingSound();
},
// parameter state true causes the class for the background color change to
// be added, and parameter state false causes the class to be removed
setRtcpanelTitleColor: function (state) { setRtcpanelTitleColor: function (state) {
// parameter true to change color, and false to revert // parameter true to change color, and false to revert
var rtcpanel = Ext.getCmp('rtcpanel'); var rtcpanel = Ext.getCmp('rtcpanel');
@ -536,20 +576,13 @@ Ext.define('NgcpCsc.view.common.rtc.RtcController', {
sound.currentTime = 0; sound.currentTime = 0;
}, },
showOutgoingCallPendingState: function() { showIncomingCallPendingState: function () {
var vm = this.getViewModel();
vm.set('callPanel', true);
vm.set('outgoingCallPending', true);
vm.set('phoneComposerHidden', true);
},
showIncomingCallPendingState: function (caller, type) {
// @hherzog: I added parameters for caller number and media type for // @hherzog: I added parameters for caller number and media type for
// now, but they can be replaced with cdk method calls in variable // now, but they can be replaced with cdk method calls in variable
// declaration below if you prefer // declaration below if you prefer
var vm = this.getViewModel(); var vm = this.getViewModel();
var caller = caller || '+4312345'; var caller = '+4312345';
var type = type || 'audio'; var type = 'audio';
vm.set('callPanel', true); vm.set('callPanel', true);
vm.set('incomingCallPending', true); vm.set('incomingCallPending', true);
vm.set('phoneComposerHidden', true); vm.set('phoneComposerHidden', true);

@ -16,7 +16,7 @@ Ext.define('NgcpCsc.view.rtc.RtcModel', {
smsComposerHidden: true, smsComposerHidden: true,
phoneKeyboardHidden: true, phoneKeyboardHidden: true,
incomingCallHidden: true, incomingCallHidden: true,
callEnabled: false, callPanelEnabled: false,
connected: false, connected: false,
micEnabled: false, micEnabled: false,
videoEnabled: false, videoEnabled: false,
@ -36,6 +36,9 @@ Ext.define('NgcpCsc.view.rtc.RtcModel', {
rtcEngineClient: null, rtcEngineClient: null,
rtcEngineSession: null, rtcEngineSession: null,
callPanel: true, callPanel: true,
callActionLabel: '',
callPending: false,
callRinging: false,
outgoingCallPending: false, outgoingCallPending: false,
incomingCallPending: false, incomingCallPending: false,
incomingType: '', incomingType: '',
@ -54,7 +57,31 @@ Ext.define('NgcpCsc.view.rtc.RtcModel', {
return get('numberToCall').length < 1; return get('numberToCall').length < 1;
}, },
setuserCls:function(get){ setuserCls:function(get){
return get('callEnabled') ? '' : 'fa-rotate-180'; return get('callPanelEnabled') ? '' : 'fa-rotate-180';
},
callEnabled: {
bind: {
callPending: '{callPending}',
callRinging: '{callRinging}',
incomingCallPending: '{incomingCallPending}'
},
get: function (data) {
return data.callPending || data.callRinging || data.incomingCallPending;
}
},
outgoingCall: {
bind: {
callPending: '{callPending}',
callRinging: '{callRinging}'
},
get: function (data) {
return data.callPending || data.callRinging;
}
},
callLocalPreview: {
get: function (data) {
return data.rtcEngineLocalMediaStream && data.rtcEngineLocalMediaStream.hasVideo();
}
} }
} }
}); });

@ -35,19 +35,29 @@ Ext.define('NgcpCsc.view.common.rtc.composer.Phone', {
xtype: 'container', xtype: 'container',
items: [{ items: [{
xtype: 'button', xtype: 'button',
text: Ngcp.csc.locales.rtc.sendAudio[localStorage.getItem('languageSelected')], text: '',
iconCls: Ngcp.csc.icons.microphone,
margin: '0 10 0 0', margin: '0 10 0 0',
listeners: { listeners: {
click: 'sendAudio' click: 'sendAudio'
} },
userCls: 'call-button call-button-accept',
overCls: 'call-button-accept-over',
focusCls: 'call-button-accept-focus',
width: 40,
height: 40,
html: '<i class="x-fa fa-phone icon-large"></i><i class="x-fa fa-microphone icon-small"></i>'
}, { }, {
xtype: 'button', xtype: 'button',
text: Ngcp.csc.locales.rtc.sendVideo[localStorage.getItem('languageSelected')], text: '',
iconCls: Ngcp.csc.icons.video,
listeners: { listeners: {
click: 'sendVideo' click: 'sendVideo'
} },
userCls: 'call-button call-button-accept',
overCls: 'call-button-accept-over',
focusCls: 'call-button-accept-focus',
width: 40,
height: 40,
html: '<i class="x-fa fa-phone icon-large"></i><i class="x-fa fa-video-camera icon-small"></i>'
}] }]
}] }]
}, { }, {

Loading…
Cancel
Save