VideoSIPGW updates (#2201)
* Adds initial documentation for sipgw jibri. Also explains enabling the people search service and the request/response that are made around sipgw jibri service. * Fixes add people dialog to invite users and rooms. No invitation is sent when there is nobody to invite. * Reuse some recording strings, by using arguments. * Make sure web also dispatches CONFERENCE_WILL_JOIN. * Introduces new feature videosipgw. * Fixes lint errors. * Renames methods to use people, chatRooms and videoRooms. * Updates to latest lib-jitsi-meet (dc3397b18b).
This commit is contained in:
parent
28b153facf
commit
7b1b873b6e
|
@ -25,6 +25,7 @@ import {
|
|||
conferenceFailed,
|
||||
conferenceJoined,
|
||||
conferenceLeft,
|
||||
conferenceWillJoin,
|
||||
dataChannelOpened,
|
||||
EMAIL_COMMAND,
|
||||
lockStateChanged,
|
||||
|
@ -1249,6 +1250,7 @@ export default {
|
|||
= connection.initJitsiConference(
|
||||
APP.conference.roomName,
|
||||
this._getConferenceOptions());
|
||||
APP.store.dispatch(conferenceWillJoin(room));
|
||||
this._setLocalAudioVideoStreams(localTracks);
|
||||
this._room = room; // FIXME do not use this
|
||||
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
# Configuring sipgw jibri with jitsi-meet
|
||||
|
||||
This document describes how you can configure jitsi-meet to use sipgw jibri and enable rooms in 'Add people dialog'
|
||||
You will need a working deployment of jibri configured to use a regular sip video device, for more info check out the [jibri documentation](https://github.com/jitsi/jibri/blob/master/README.md).
|
||||
|
||||
This feature is available for non-guests of the system, so this relies on setting in config.js ``enableUserRolesBasedOnToken: true`` and providing a jwt token when accessing the conference.
|
||||
|
||||
* Jicofo configuration:
|
||||
edit /etc/jitsi/jicofo/sip-communicator.properties (or similar), set the appropriate MUC to look for the Jibri Controllers. This should be the same MUC as is referenced in jibri's config.json file. Restart Jicofo after setting this property.
|
||||
|
||||
```
|
||||
org.jitsi.jicofo.jibri.SIP_BREWERY=TheSipBrewery@conference.yourdomain.com
|
||||
```
|
||||
|
||||
* Jitsi Meet configuration:
|
||||
- config.js: add
|
||||
```
|
||||
enableUserRolesBasedOnToken: true,
|
||||
peopleSearchQueryTypes: ['conferenceRooms'],
|
||||
peopleSearchUrl: 'https://api.yourdomain.com/testpath/searchpeople',
|
||||
```
|
||||
- interface_config.js:
|
||||
```
|
||||
ADD_PEOPLE_APP_NAME: 'Jitsi'
|
||||
```
|
||||
|
||||
The combination of the above settings and providing a jwt token will enable a button under invite option which will show the dialog 'Add people'.
|
||||
|
||||
## People search service
|
||||
|
||||
When searching in the dialog, a request for results is made to the `peopleSearchUrl` service.
|
||||
|
||||
The request is in the following format:
|
||||
```
|
||||
https://api.yourdomain.com/testpath/searchpeople?query=testroomname&queryTypes=[%22conferenceRooms%22]&jwt=somejwt
|
||||
```
|
||||
The parameters are:
|
||||
- query - The text entered by the user.
|
||||
- queryTypes - What type of results we want people, rooms, conferenceRooms. This is the value from config.js `peopleSearchQueryTypes`
|
||||
- jwt - The token used by the user to access the conference.
|
||||
|
||||
The response of the service is a json in the following format:
|
||||
```
|
||||
[
|
||||
{
|
||||
"id": "address@sip.domain.com",
|
||||
"name": "Some room name",
|
||||
"type": "videosipgw"
|
||||
},
|
||||
{
|
||||
"id": "address2@sip.domain.com",
|
||||
"name": "Some room name2",
|
||||
"type": "videosipgw"
|
||||
}
|
||||
]
|
||||
```
|
||||
Type should be `videosipgw`, `name` is the name shown to the user and `id` is the sip address to be called by the sipgw jibri.
|
|
@ -420,7 +420,8 @@
|
|||
"off": "Recording stopped",
|
||||
"on": "Recording",
|
||||
"pending": "Recording waiting for a member to join...",
|
||||
"unavailable": "Oops! The recording service is currently unavailable. We're working on resolving the issue. Please try again later.",
|
||||
"serviceName": "Recording service",
|
||||
"unavailable": "Oops! The __serviceName__ is currently unavailable. We're working on resolving the issue. Please try again later.",
|
||||
"unavailableTitle": "Recording unavailable"
|
||||
},
|
||||
"liveStreaming":
|
||||
|
@ -433,11 +434,24 @@
|
|||
"off": "Live Streaming stopped",
|
||||
"on": "Live Streaming",
|
||||
"pending": "Starting Live Stream...",
|
||||
"serviceName": "Live Streaming service",
|
||||
"streamIdRequired": "Please fill in the stream id in order to launch the Live Streaming.",
|
||||
"streamIdHelp": "Where do I find this?",
|
||||
"unavailable": "Oops! The Live Streaming service is currently unavailable. We're working on resolving the issue. Please try again later.",
|
||||
"unavailableTitle": "Live Streaming unavailable"
|
||||
},
|
||||
"videoSIPGW":
|
||||
{
|
||||
"busy": "We're working on freeing resources. Please try again in a few minutes.",
|
||||
"busyTitle": "The Room service is currently busy",
|
||||
"errorInvite": "Conference not established yet. Please try again later.",
|
||||
"errorInviteTitle": "Error inviting room",
|
||||
"errorAlreadyInvited": "__displayName__ already invited",
|
||||
"errorInviteFailedTitle": "Inviting __displayName__ failed",
|
||||
"errorInviteFailed": "We're working on resolving the issue. Please try again later.",
|
||||
"pending": "__displayName__ has been invited",
|
||||
"serviceName": "Room service",
|
||||
"unavailableTitle": "Room service unavailable"
|
||||
},
|
||||
"speakerStats":
|
||||
{
|
||||
"hours": "__count__h",
|
||||
|
|
|
@ -51,6 +51,7 @@ export const RECORDING_TRANSLATION_KEYS = {
|
|||
recordingPendingKey: 'recording.pending',
|
||||
recordingTitle: 'dialog.recording',
|
||||
recordingUnavailable: 'recording.unavailable',
|
||||
recordingUnavailableParams: '$t(recording.serviceName)',
|
||||
recordingUnavailableTitle: 'recording.unavailableTitle'
|
||||
};
|
||||
|
||||
|
@ -71,7 +72,8 @@ export const STREAMING_TRANSLATION_KEYS = {
|
|||
recordingOnKey: 'liveStreaming.on',
|
||||
recordingPendingKey: 'liveStreaming.pending',
|
||||
recordingTitle: 'dialog.liveStreaming',
|
||||
recordingUnavailable: 'liveStreaming.unavailable',
|
||||
recordingUnavailable: 'recording.unavailable',
|
||||
recordingUnavailableParams: '$t(liveStreaming.serviceName)',
|
||||
recordingUnavailableTitle: 'liveStreaming.unavailableTitle'
|
||||
};
|
||||
|
||||
|
@ -531,6 +533,8 @@ const Recording = {
|
|||
default: {
|
||||
APP.UI.messageHandler.showError({
|
||||
descriptionKey: this.recordingUnavailable,
|
||||
descriptionArguments: {
|
||||
serviceName: this.recordingUnavailableParams },
|
||||
titleKey: this.recordingUnavailableTitle
|
||||
});
|
||||
}
|
||||
|
|
|
@ -10991,7 +10991,7 @@
|
|||
}
|
||||
},
|
||||
"lib-jitsi-meet": {
|
||||
"version": "github:jitsi/lib-jitsi-meet#21b07deabccd0b28b6d8eacaa6eee613e018b482",
|
||||
"version": "github:jitsi/lib-jitsi-meet#dc3397b18b3c3c41ee8d17224f9af9318b844c43",
|
||||
"requires": {
|
||||
"async": "0.9.0",
|
||||
"current-executing-script": "0.1.3",
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
"js-md5": "0.6.1",
|
||||
"jssha": "2.2.0",
|
||||
"jwt-decode": "2.2.0",
|
||||
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#21b07deabccd0b28b6d8eacaa6eee613e018b482",
|
||||
"lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#dc3397b18b3c3c41ee8d17224f9af9318b844c43",
|
||||
"lodash": "4.17.4",
|
||||
"nuclear-js": "1.4.0",
|
||||
"postis": "2.2.0",
|
||||
|
|
|
@ -229,10 +229,25 @@ function _conferenceWillJoin(conference: Object) {
|
|||
_addLocalTracksToConference(conference, localTracks);
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: CONFERENCE_WILL_JOIN,
|
||||
conference
|
||||
});
|
||||
dispatch(conferenceWillJoin(conference));
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals the intention of the application to have the local participant
|
||||
* join the specified conference.
|
||||
*
|
||||
* @param {JitsiConference} conference - The {@code JitsiConference} instance
|
||||
* the local participant will (try to) join.
|
||||
* @returns {{
|
||||
* type: CONFERENCE_WILL_JOIN,
|
||||
* conference: JitsiConference
|
||||
* }}
|
||||
*/
|
||||
export function conferenceWillJoin(conference: Object) {
|
||||
return {
|
||||
type: CONFERENCE_WILL_JOIN,
|
||||
conference
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ export const JitsiMediaDevicesEvents = JitsiMeetJS.events.mediaDevices;
|
|||
export const JitsiParticipantConnectionStatus
|
||||
= JitsiMeetJS.constants.participantConnectionStatus;
|
||||
export const JitsiRecordingStatus = JitsiMeetJS.constants.recordingStatus;
|
||||
export const JitsiSIPVideoGWStatus = JitsiMeetJS.constants.sipVideoGW;
|
||||
export const JitsiTrackErrors = JitsiMeetJS.errors.track;
|
||||
export const JitsiTrackEvents = JitsiMeetJS.events.track;
|
||||
|
||||
|
|
|
@ -12,7 +12,8 @@ import { Dialog, hideDialog } from '../../base/dialog';
|
|||
import { translate } from '../../base/i18n';
|
||||
import { MultiSelectAutocomplete } from '../../base/react';
|
||||
|
||||
import { invitePeople, inviteRooms, searchPeople } from '../functions';
|
||||
import { invitePeopleAndChatRooms, searchDirectory } from '../functions';
|
||||
import { inviteVideoRooms } from '../../videosipgw';
|
||||
|
||||
declare var interfaceConfig: Object;
|
||||
|
||||
|
@ -62,6 +63,11 @@ class AddPeopleDialog extends Component<*, *> {
|
|||
*/
|
||||
hideDialog: PropTypes.func,
|
||||
|
||||
/**
|
||||
* Used to invite video rooms.
|
||||
*/
|
||||
inviteVideoRooms: PropTypes.func,
|
||||
|
||||
/**
|
||||
* Invoked to obtain translated strings.
|
||||
*/
|
||||
|
@ -79,7 +85,7 @@ class AddPeopleDialog extends Component<*, *> {
|
|||
} = this.props; // eslint-disable-line no-invalid-this
|
||||
|
||||
return (
|
||||
searchPeople(
|
||||
searchDirectory(
|
||||
_peopleSearchUrl,
|
||||
_jwt,
|
||||
text,
|
||||
|
@ -215,16 +221,17 @@ class AddPeopleDialog extends Component<*, *> {
|
|||
});
|
||||
|
||||
this.props._conference
|
||||
&& inviteRooms(
|
||||
this.props._conference,
|
||||
this.state.inviteItems.filter(
|
||||
i => i.type === 'videosipgw'));
|
||||
&& this.props.inviteVideoRooms(
|
||||
this.props._conference,
|
||||
this.state.inviteItems.filter(
|
||||
i => i.type === 'videosipgw'));
|
||||
|
||||
invitePeople(
|
||||
invitePeopleAndChatRooms(
|
||||
this.props._inviteServiceUrl,
|
||||
this.props._inviteUrl,
|
||||
this.props._jwt,
|
||||
this.state.inviteItems.filter(i => i.type === 'user'))
|
||||
this.state.inviteItems.filter(
|
||||
i => i.type === 'user' || i.type === 'room'))
|
||||
.then(
|
||||
/* onFulfilled */ () => {
|
||||
this.setState({
|
||||
|
@ -355,5 +362,7 @@ function _mapStateToProps(state) {
|
|||
};
|
||||
}
|
||||
|
||||
export default translate(connect(_mapStateToProps, { hideDialog })(
|
||||
export default translate(connect(_mapStateToProps, {
|
||||
hideDialog,
|
||||
inviteVideoRooms })(
|
||||
AddPeopleDialog));
|
||||
|
|
|
@ -22,19 +22,24 @@ export function getInviteOptionPosition(name: string): number {
|
|||
* invitation.
|
||||
* @param {string} inviteUrl - The url to the conference.
|
||||
* @param {string} jwt - The jwt token to pass to the search service.
|
||||
* @param {Immutable.List} people - The list of the "user" type items to invite.
|
||||
* @param {Immutable.List} inviteItems - The list of the "user" or "room"
|
||||
* type items to invite.
|
||||
* @returns {Promise} - The promise created by the request.
|
||||
*/
|
||||
export function invitePeople( // eslint-disable-line max-params
|
||||
export function invitePeopleAndChatRooms( // eslint-disable-line max-params
|
||||
inviteServiceUrl: string,
|
||||
inviteUrl: string,
|
||||
jwt: string,
|
||||
people: Object) {
|
||||
inviteItems: Object) {
|
||||
if (!inviteItems || inviteItems.length === 0) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
$.post(
|
||||
`${inviteServiceUrl}?token=${jwt}`,
|
||||
JSON.stringify({
|
||||
'invited': people,
|
||||
'invited': inviteItems,
|
||||
'url': inviteUrl
|
||||
}),
|
||||
resolve,
|
||||
|
@ -43,33 +48,6 @@ export function invitePeople( // eslint-disable-line max-params
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Invites room participants to the conference through the SIP Jibri service.
|
||||
*
|
||||
* @param {JitsiMeetConference} conference - The conference to which the rooms
|
||||
* will be invited to.
|
||||
* @param {Immutable.List} rooms - The list of the "videosipgw" type items to
|
||||
* invite.
|
||||
* @returns {void}
|
||||
*/
|
||||
export function inviteRooms(
|
||||
conference: { createVideoSIPGWSession: Function },
|
||||
rooms: Object) {
|
||||
for (const room of rooms) {
|
||||
const { id: sipAddress, name: displayName } = room;
|
||||
|
||||
if (sipAddress && displayName) {
|
||||
const newSession
|
||||
= conference.createVideoSIPGWSession(sipAddress, displayName);
|
||||
|
||||
newSession.start();
|
||||
} else {
|
||||
console.error(
|
||||
`No display name or sip number for ${JSON.stringify(room)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if an invite option is enabled in the configuration.
|
||||
*
|
||||
|
@ -92,7 +70,7 @@ export function isInviteOptionEnabled(name: string) {
|
|||
* executed - "conferenceRooms" | "user" | "room".
|
||||
* @returns {Promise} - The promise created by the request.
|
||||
*/
|
||||
export function searchPeople( // eslint-disable-line max-params
|
||||
export function searchDirectory( // eslint-disable-line max-params
|
||||
serviceUrl: string,
|
||||
jwt: string,
|
||||
text: string,
|
||||
|
|
|
@ -145,9 +145,6 @@ class Notification extends Component<*> {
|
|||
render() {
|
||||
const {
|
||||
appearance,
|
||||
description,
|
||||
descriptionArguments,
|
||||
descriptionKey,
|
||||
hideErrorSupportLink,
|
||||
isDismissAllowed,
|
||||
onDismissed,
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* The type of (redux) action which signals that sip GW service change its
|
||||
* availability status.
|
||||
*
|
||||
* {
|
||||
* type: SIP_GW_AVAILABILITY_CHANGED,
|
||||
* status: string
|
||||
* }
|
||||
*/
|
||||
export const SIP_GW_AVAILABILITY_CHANGED
|
||||
= Symbol('SIP_GW_AVAILABILITY_CHANGED');
|
||||
|
||||
/**
|
||||
* The type of the action which signals to invite room participants to the
|
||||
* conference through the SIP Jibri service.
|
||||
*
|
||||
* {
|
||||
* type: SIP_GW_INVITE_ROOMS,
|
||||
* conference: JitsiConference,
|
||||
* rooms: {Immutable.List}
|
||||
* }
|
||||
*/
|
||||
export const SIP_GW_INVITE_ROOMS = Symbol('SIP_GW_INVITE_ROOMS');
|
|
@ -0,0 +1,22 @@
|
|||
/* @flow */
|
||||
|
||||
import { SIP_GW_INVITE_ROOMS } from './actionTypes';
|
||||
|
||||
/**
|
||||
* Invites room participants to the conference through the SIP Jibri service.
|
||||
*
|
||||
* @param {JitsiMeetConference} conference - The conference to which the rooms
|
||||
* will be invited to.
|
||||
* @param {Immutable.List} rooms - The list of the "videosipgw" type items to
|
||||
* invite.
|
||||
* @returns {void}
|
||||
*/
|
||||
export function inviteVideoRooms(
|
||||
conference: Object,
|
||||
rooms: Object) {
|
||||
return {
|
||||
type: SIP_GW_INVITE_ROOMS,
|
||||
conference,
|
||||
rooms
|
||||
};
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
export * from './actions';
|
||||
|
||||
import './middleware';
|
||||
import './reducer';
|
|
@ -0,0 +1,182 @@
|
|||
/* @flow */
|
||||
|
||||
import Logger from 'jitsi-meet-logger';
|
||||
import { CONFERENCE_WILL_JOIN } from '../base/conference';
|
||||
import {
|
||||
SIP_GW_AVAILABILITY_CHANGED,
|
||||
SIP_GW_INVITE_ROOMS
|
||||
} from './actionTypes';
|
||||
import {
|
||||
JitsiConferenceEvents,
|
||||
JitsiSIPVideoGWStatus
|
||||
} from '../base/lib-jitsi-meet';
|
||||
import { MiddlewareRegistry } from '../base/redux';
|
||||
import {
|
||||
Notification,
|
||||
showErrorNotification,
|
||||
showNotification,
|
||||
showWarningNotification
|
||||
} from '../notifications';
|
||||
|
||||
const logger = Logger.getLogger(__filename);
|
||||
|
||||
/**
|
||||
* Middleware that captures conference video sip gw events and stores
|
||||
* the global sip gw availability in redux or show appropriate notification
|
||||
* for sip gw sessions.
|
||||
* Captures invitation actions that create sip gw sessions or display
|
||||
* appropriate error/warning notifications.
|
||||
*
|
||||
* @param {Store} store - The redux store.
|
||||
* @returns {Function}
|
||||
*/
|
||||
MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
||||
const result = next(action);
|
||||
|
||||
switch (action.type) {
|
||||
case CONFERENCE_WILL_JOIN: {
|
||||
const conference = getState()['features/base/conference'].joining;
|
||||
|
||||
conference.on(
|
||||
JitsiConferenceEvents.VIDEO_SIP_GW_AVAILABILITY_CHANGED,
|
||||
(...args) => dispatch(_availabilityChanged(...args)));
|
||||
conference.on(
|
||||
JitsiConferenceEvents.VIDEO_SIP_GW_SESSION_STATE_CHANGED,
|
||||
event => {
|
||||
const toDispatch = _sessionStateChanged(event);
|
||||
|
||||
// sessionStateChanged can decide there is nothing to dispatch
|
||||
if (toDispatch) {
|
||||
dispatch(toDispatch);
|
||||
}
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
case SIP_GW_INVITE_ROOMS: {
|
||||
const { status } = getState()['features/videosipgw'];
|
||||
|
||||
if (status === JitsiSIPVideoGWStatus.STATUS_UNDEFINED) {
|
||||
dispatch(showErrorNotification({
|
||||
descriptionKey: 'recording.unavailable',
|
||||
descriptionArguments: {
|
||||
serviceName: '$t(videoSIPGW.serviceName)'
|
||||
},
|
||||
titleKey: 'videoSIPGW.unavailableTitle'
|
||||
}));
|
||||
|
||||
return;
|
||||
} else if (status === JitsiSIPVideoGWStatus.STATUS_BUSY) {
|
||||
dispatch(showWarningNotification({
|
||||
descriptionKey: 'videoSIPGW.busy',
|
||||
titleKey: 'videoSIPGW.busyTitle'
|
||||
}));
|
||||
|
||||
return;
|
||||
} else if (status !== JitsiSIPVideoGWStatus.STATUS_AVAILABLE) {
|
||||
logger.error(`Unknown sip videogw status ${status}`);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (const room of action.rooms) {
|
||||
const { id: sipAddress, name: displayName } = room;
|
||||
|
||||
if (sipAddress && displayName) {
|
||||
const newSession = action.conference
|
||||
.createVideoSIPGWSession(sipAddress, displayName);
|
||||
|
||||
if (newSession instanceof Error) {
|
||||
const e = newSession;
|
||||
|
||||
if (e) {
|
||||
switch (e.message) {
|
||||
case JitsiSIPVideoGWStatus.ERROR_NO_CONNECTION: {
|
||||
dispatch(showErrorNotification({
|
||||
descriptionKey: 'videoSIPGW.errorInvite',
|
||||
titleKey: 'videoSIPGW.errorInviteTitle'
|
||||
}));
|
||||
|
||||
return;
|
||||
}
|
||||
case JitsiSIPVideoGWStatus.ERROR_SESSION_EXISTS: {
|
||||
dispatch(showWarningNotification({
|
||||
titleKey: 'videoSIPGW.errorAlreadyInvited',
|
||||
titleArguments: { displayName }
|
||||
}));
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.error(
|
||||
'Unknown error trying to create sip videogw session',
|
||||
e);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
newSession.start();
|
||||
} else {
|
||||
logger.error(`No display name or sip number for ${
|
||||
JSON.stringify(room)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
/**
|
||||
* Signals that sip gw availability had changed.
|
||||
*
|
||||
* @param {string} status - The new status of the service.
|
||||
* @returns {{
|
||||
* type: SIP_GW_AVAILABILITY_CHANGED,
|
||||
* status: string
|
||||
* }}
|
||||
* @private
|
||||
*/
|
||||
function _availabilityChanged(status: string) {
|
||||
return {
|
||||
type: SIP_GW_AVAILABILITY_CHANGED,
|
||||
status
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals that a session we created has a change in its status.
|
||||
*
|
||||
* @param {string} event - The event describing the session state change.
|
||||
* @returns {{
|
||||
* type: SHOW_NOTIFICATION
|
||||
* }}|null
|
||||
* @private
|
||||
*/
|
||||
function _sessionStateChanged(
|
||||
event: Object) {
|
||||
switch (event.newState) {
|
||||
case JitsiSIPVideoGWStatus.STATE_PENDING: {
|
||||
return showNotification(
|
||||
Notification, {
|
||||
titleKey: 'videoSIPGW.pending',
|
||||
titleArguments: {
|
||||
displayName: event.displayName
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
case JitsiSIPVideoGWStatus.STATE_FAILED: {
|
||||
return showErrorNotification({
|
||||
titleKey: 'videoSIPGW.errorInviteFailedTitle',
|
||||
titleArguments: {
|
||||
displayName: event.displayName
|
||||
},
|
||||
descriptionKey: 'videoSIPGW.errorInviteFailed'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// nothing to show
|
||||
return null;
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import { ReducerRegistry } from '../base/redux';
|
||||
|
||||
import { SIP_GW_AVAILABILITY_CHANGED } from './actionTypes';
|
||||
|
||||
ReducerRegistry.register(
|
||||
'features/videosipgw', (state = [], action) => {
|
||||
switch (action.type) {
|
||||
case SIP_GW_AVAILABILITY_CHANGED: {
|
||||
return {
|
||||
...state,
|
||||
status: action.status
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
});
|
Loading…
Reference in New Issue