Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/components/CallView/CallView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ import VideoVue from './shared/VideoVue.vue'
import ViewerOverlayCallView from './shared/ViewerOverlayCallView.vue'
import { SIMULCAST } from '../../constants.ts'
import BrowserStorage from '../../services/BrowserStorage.js'
import { fetchPeers } from '../../services/callsService.js'
import { fetchPeers } from '../../services/callsService.ts'
import { getTalkConfig } from '../../services/CapabilitiesManager.ts'
import { EventBus } from '../../services/EventBus.ts'
import { useCallViewStore } from '../../stores/callView.ts'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ import LoadingComponent from '../../LoadingComponent.vue'
import SelectPhoneNumber from '../../SelectPhoneNumber.vue'
import DialpadPanel from '../../UIShared/DialpadPanel.vue'
import { CONVERSATION, PARTICIPANT } from '../../../constants.ts'
import { callSIPDialOut } from '../../../services/callsService.js'
import { callSIPDialOut } from '../../../services/callsService.ts'
import { hasTalkFeature } from '../../../services/CapabilitiesManager.ts'
import { createLegacyConversation } from '../../../services/conversationsService.ts'
import { addParticipant } from '../../../services/participantsService.js'
Expand Down
2 changes: 1 addition & 1 deletion src/components/RightSidebar/Participants/Participant.vue
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ import {
callSIPMutePhone,
callSIPSendDTMF,
callSIPUnmutePhone,
} from '../../../services/callsService.js'
} from '../../../services/callsService.ts'
import { hasTalkFeature } from '../../../services/CapabilitiesManager.ts'
import { useActorStore } from '../../../stores/actor.ts'
import { formattedTime } from '../../../utils/formattedTime.ts'
Expand Down
2 changes: 1 addition & 1 deletion src/components/TopBar/CallButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ import IconPhoneOff from 'vue-material-design-icons/PhoneOff.vue'
import IconPhoneOutline from 'vue-material-design-icons/PhoneOutline.vue'
import { useIsInCall } from '../../composables/useIsInCall.js'
import { ATTENDEE, CALL, CONVERSATION, PARTICIPANT } from '../../constants.ts'
import { callSIPDialOut } from '../../services/callsService.js'
import { callSIPDialOut } from '../../services/callsService.ts'
import { hasTalkFeature } from '../../services/CapabilitiesManager.ts'
import { EventBus } from '../../services/EventBus.ts'
import { useActorStore } from '../../stores/actor.ts'
Expand Down
62 changes: 34 additions & 28 deletions src/services/callsService.js → src/services/callsService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import type {
callSIPDialOutResponse,
CallSIPSendCallMessagePayload,
fetchPeersResponse,
} from '../types/index.ts'

import axios from '@nextcloud/axios'
import { generateOcsUrl } from '@nextcloud/router'
import { PARTICIPANT } from '../constants.ts'
Expand All @@ -23,99 +29,99 @@ import {
* media is allowed to be sent, but it is not guaranteed to be sent. For
* example, if WITH_VIDEO is provided but the device does not have a camera.
*
* @param {string} token The token of the call to be joined.
* @param {number} flags The available PARTICIPANT.CALL_FLAG for this participants
* @param {boolean} silent Whether the call should trigger a notifications and
* @param token The token of the call to be joined.
* @param flags The available PARTICIPANT.CALL_FLAG for this participants
* @param silent Whether the call should trigger a notifications and
* sound for other participants or not
* @param {boolean} recordingConsent Whether the participant gave their consent to be recorded
* @param {Array<string>} silentFor List of participants that should not receive a notification about the call
* @return {Promise<number>} The actual flags based on the available media
* @param recordingConsent Whether the participant gave their consent to be recorded
* @param silentFor List of participants that should not receive a notification about the call
* @return The actual flags based on the available media
*/
const joinCall = async function(token, flags, silent, recordingConsent, silentFor) {
const joinCall = async function(token: string, flags: number, silent: boolean, recordingConsent: boolean, silentFor: string[]): Promise<void> {
return signalingJoinCall(token, flags, silent, recordingConsent, silentFor)
}

/**
* Leave a call as participant
*
* @param {string} token The token of the call to be left
* @param {boolean} all Whether to end the meeting for all
* @param token The token of the call to be left
* @param all Whether to end the meeting for all
*/
const leaveCall = async function(token, all = false) {
const leaveCall = async function(token: string, all: boolean = false) {
try {
await signalingLeaveCall(token, all)
} catch (error) {
console.debug('Error while leaving call: ', error)
}
}

const fetchPeers = async function(token, options) {
const fetchPeers = async function(token: string, options: object): fetchPeersResponse {
return await axios.get(generateOcsUrl('apps/spreed/api/v4/call/{token}', { token }), options)
}

/**
* Call participant via SIP DialOut
*
* @param {string} token The token of the conversation
* @param {number} attendeeId The attendee id to call to via SIP
* @param token The token of the conversation
* @param attendeeId The attendee id to call to via SIP
*/
const callSIPDialOut = async function(token, attendeeId) {
const callSIPDialOut = async function(token: string, attendeeId: number): callSIPDialOutResponse {
return axios.post(generateOcsUrl('apps/spreed/api/v4/call/{token}/dialout/{attendeeId}', { token, attendeeId }))
}

/**
* Hang up for phone participant
*
* @param {string} sessionId Session id of receiver
* @param sessionId Session id of receiver
*/
const callSIPHangupPhone = async function(sessionId) {
const callSIPHangupPhone = async function(sessionId: string) {
await callSIPSendCallMessage(sessionId, { type: 'hangup' })
}

/**
* Mute phone participant (prevent from speaking)
*
* @param {string} sessionId Session id of receiver
* @param sessionId Session id of receiver
*/
const callSIPMutePhone = async function(sessionId) {
const callSIPMutePhone = async function(sessionId: string) {
await callSIPSendCallMessage(sessionId, { type: 'mute', audio: PARTICIPANT.SIP_DIALOUT_FLAG.MUTE_MICROPHONE })
}

/**
* Unmute phone participant (allow to speaking and listening)
*
* @param {string} sessionId Session id of receiver
* @param sessionId Session id of receiver
*/
const callSIPUnmutePhone = async function(sessionId) {
const callSIPUnmutePhone = async function(sessionId: string) {
await callSIPSendCallMessage(sessionId, { type: 'mute', audio: PARTICIPANT.SIP_DIALOUT_FLAG.NONE })
}

/**
* Hold a participant (prevent from listening)
*
* @param {string} sessionId Session id of receiver
* @param sessionId Session id of receiver
*/
const callSIPHoldPhone = async function(sessionId) {
const callSIPHoldPhone = async function(sessionId: string) {
await callSIPSendCallMessage(sessionId, { type: 'mute', audio: PARTICIPANT.SIP_DIALOUT_FLAG.MUTE_MICROPHONE | PARTICIPANT.SIP_DIALOUT_FLAG.MUTE_SPEAKER })
}

/**
* Send DTMF digits one per message (allowed characters: 0-9, *, #)
*
* @param {string} sessionId Session id of receiver
* @param {string} digit DTMF digit to send
* @param sessionId Session id of receiver
* @param digit DTMF digit to send
*/
const callSIPSendDTMF = async function(sessionId, digit) {
const callSIPSendDTMF = async function(sessionId: string, digit: string) {
await callSIPSendCallMessage(sessionId, { type: 'dtmf', digit })
}

/**
* Send a message to SIP via signaling
*
* @param {string} sessionId Session id of receiver
* @param {object} data Payload for message to be sent
* @param sessionId Session id of receiver
* @param data Payload for message to be sent
*/
const callSIPSendCallMessage = async function(sessionId, data) {
const callSIPSendCallMessage = async function(sessionId: string, data: CallSIPSendCallMessagePayload) {
if (!sessionId) {
console.debug('Session ID has not been provided')
return
Expand Down
2 changes: 1 addition & 1 deletion src/store/participantsStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { banActor } from '../services/banService.ts'
import {
joinCall,
leaveCall,
} from '../services/callsService.js'
} from '../services/callsService.ts'
import { hasTalkFeature, setRemoteCapabilities } from '../services/CapabilitiesManager.ts'
import { EventBus } from '../services/EventBus.ts'
import {
Expand Down
2 changes: 1 addition & 1 deletion src/store/participantsStore.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { PARTICIPANT } from '../constants.ts'
import {
joinCall,
leaveCall,
} from '../services/callsService.js'
} from '../services/callsService.ts'
import { fetchConversation } from '../services/conversationsService.ts'
import { EventBus } from '../services/EventBus.ts'
import {
Expand Down
12 changes: 12 additions & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,10 @@ export type JoinRoomFullResponse = {
data: operations['room-join-room']['responses']['200']['content']['application/json']
}

// Call
export type fetchPeersResponse = ApiResponse<operations['call-get-peers-for-call']['responses'][200]['content']['application/json']>
export type callSIPDialOutResponse = ApiResponse<operations['call-sip-dial-out']['responses'][201]['content']['application/json']>

// Participants
export type ParticipantStatus = {
status?: string | null
Expand Down Expand Up @@ -411,6 +415,14 @@ export type UserFilterObject = {
showUserStatus: boolean
}

// SIP call message payload
// TODO unify this type
// hint: check TYPE_ENCRYPTION* in "encryption.js"
export type CallSIPSendCallMessagePayload =
| { type: 'control' | 'hangup' }
| { type: 'dtmf', digit: string }
| { type: 'mute', audio: number }

// Autocomplete API
export type {
AutocompleteParams,
Expand Down