mirror of
https://github.com/balzack/databag.git
synced 2025-03-13 00:50:03 +00:00
configuring cloudlare turn service
This commit is contained in:
parent
2804de9972
commit
0f51f7b5d4
23
doc/api.oa3
23
doc/api.oa3
@ -4119,6 +4119,8 @@ components:
|
||||
type: boolean
|
||||
enableIce:
|
||||
type: boolean
|
||||
iceService:
|
||||
type: boolean
|
||||
iceUrl:
|
||||
type: string
|
||||
iceUsername:
|
||||
@ -4130,6 +4132,7 @@ components:
|
||||
openAccessLimit:
|
||||
type: integer
|
||||
format: int64
|
||||
|
||||
|
||||
Seal:
|
||||
type: object
|
||||
@ -4899,12 +4902,28 @@ components:
|
||||
keepAlive:
|
||||
type: integer
|
||||
format: int32
|
||||
iceService:
|
||||
type: boolean
|
||||
iceUrl:
|
||||
type: string
|
||||
iceUsername:
|
||||
type: string
|
||||
icePassword:
|
||||
type: string
|
||||
|
||||
IceUrl:
|
||||
tyle: object
|
||||
required:
|
||||
- urls
|
||||
- username
|
||||
- credential
|
||||
properties:
|
||||
urls:
|
||||
type: string
|
||||
username:
|
||||
type: string
|
||||
credential:
|
||||
type: string
|
||||
|
||||
Ring:
|
||||
type: object
|
||||
@ -4920,6 +4939,10 @@ components:
|
||||
index:
|
||||
type: integer
|
||||
format: int32
|
||||
ice:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/IceUrl'
|
||||
iceUrl:
|
||||
type: string
|
||||
iceUsername:
|
||||
|
@ -61,6 +61,7 @@ func AddCall(w http.ResponseWriter, r *http.Request) {
|
||||
// allocate bridge
|
||||
callerToken := hex.EncodeToString(callerBin);
|
||||
calleeToken := hex.EncodeToString(calleeBin);
|
||||
iceService := getBoolConfigValue(CNFIceService, false);
|
||||
iceUrl := getStrConfigValue(CNFIceUrl, "")
|
||||
iceUsername := getStrConfigValue(CNFIceUsername, "")
|
||||
icePassword := getStrConfigValue(CNFIcePassword, "")
|
||||
@ -72,6 +73,7 @@ func AddCall(w http.ResponseWriter, r *http.Request) {
|
||||
CardId: cardId,
|
||||
CallerToken: callerToken,
|
||||
CalleeToken: calleeToken,
|
||||
IceService: iceService,
|
||||
IceUrl: iceUrl,
|
||||
IceUsername: iceUsername,
|
||||
IcePassword: icePassword,
|
||||
|
@ -25,6 +25,7 @@ func GetNodeConfig(w http.ResponseWriter, r *http.Request) {
|
||||
config.KeyType = getStrConfigValue(CNFKeyType, APPRSA2048)
|
||||
config.PushSupported = getBoolConfigValue(CNFPushSupported, true)
|
||||
config.EnableIce = getBoolConfigValue(CNFEnableIce, false)
|
||||
config.IceService = getBoolConfigValue(CNFIceService, false)
|
||||
config.IceUrl = getStrConfigValue(CNFIceUrl, "")
|
||||
config.IceUsername = getStrConfigValue(CNFIceUsername, "")
|
||||
config.IcePassword = getStrConfigValue(CNFIcePassword, "")
|
||||
|
@ -101,7 +101,7 @@ func SetNodeConfig(w http.ResponseWriter, r *http.Request) {
|
||||
return res
|
||||
}
|
||||
|
||||
// upsert push supported
|
||||
// upsert ice supported
|
||||
if res := tx.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "config_id"}},
|
||||
DoUpdates: clause.AssignmentColumns([]string{"bool_value"}),
|
||||
@ -109,6 +109,14 @@ func SetNodeConfig(w http.ResponseWriter, r *http.Request) {
|
||||
return res
|
||||
}
|
||||
|
||||
// upsert ice service used
|
||||
if res := tx.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "config_id"}},
|
||||
DoUpdates: clause.AssignmentColumns([]string{"bool_value"}),
|
||||
}).Create(&store.Config{ConfigID: CNFIceService, BoolValue: config.IceService}).Error; res != nil {
|
||||
return res
|
||||
}
|
||||
|
||||
// upsert key type
|
||||
if res := tx.Clauses(clause.OnConflict{
|
||||
Columns: []clause.Column{{Name: "config_id"}},
|
||||
|
@ -155,6 +155,7 @@ func SetRing(card *store.Card, ring Ring) {
|
||||
var phone Phone
|
||||
phone.CallID = ring.CallID
|
||||
phone.CalleeToken = ring.CalleeToken
|
||||
phone.Ice = ring.Ice
|
||||
phone.IceUrl = ring.IceUrl
|
||||
phone.IceUsername = ring.IceUsername
|
||||
phone.IcePassword = ring.IcePassword
|
||||
|
@ -54,6 +54,9 @@ const CNFKeyType = "key_type"
|
||||
//CNFEnableIce specifies whether webrtc is enabled
|
||||
const CNFEnableIce = "enable_ice"
|
||||
|
||||
//CNFIceMode specifies if turn service is used
|
||||
const CNFIceService = "ice_service"
|
||||
|
||||
//CNFIceUrl specifies the ice candidate url
|
||||
const CNFIceUrl = "ice_url"
|
||||
|
||||
|
@ -375,6 +375,8 @@ type NodeConfig struct {
|
||||
|
||||
EnableIce bool `json:"enableIce"`
|
||||
|
||||
IceService bool `json:"iceService"`
|
||||
|
||||
IceUrl string `json:"iceUrl"`
|
||||
|
||||
IceUsername string `json:"iceUsername"`
|
||||
@ -458,6 +460,8 @@ type Phone struct {
|
||||
|
||||
CalleeToken string `json:"calleeToken"`
|
||||
|
||||
Ice []IceUrl `json:"ice,omitEmpty"`
|
||||
|
||||
IceUrl string `json:"iceUrl"`
|
||||
|
||||
IceUsername string `json:"iceUsername"`
|
||||
@ -563,6 +567,8 @@ type Call struct {
|
||||
|
||||
KeepAlive int32 `json:"keepAlive"`
|
||||
|
||||
IceService bool `json:"iceService"`
|
||||
|
||||
IceUrl string `json:"iceUrl"`
|
||||
|
||||
IceUsername string `json:"iceUsername"`
|
||||
@ -570,6 +576,15 @@ type Call struct {
|
||||
IcePassword string `json:"icePassword"`
|
||||
}
|
||||
|
||||
type IceUrl struct {
|
||||
|
||||
URLs string `json:"urls"`
|
||||
|
||||
Username string `json:"username"`
|
||||
|
||||
Credential string `json:"credential"`
|
||||
}
|
||||
|
||||
type Ring struct {
|
||||
|
||||
CallID string `json:"callId"`
|
||||
@ -578,6 +593,8 @@ type Ring struct {
|
||||
|
||||
Index int32 `json:"index"`
|
||||
|
||||
Ice []IceUrl `json:"ice,omitEmpty"`
|
||||
|
||||
IceUrl string `json:"iceUrl"`
|
||||
|
||||
IceUsername string `json:"iceUsername"`
|
||||
|
@ -144,6 +144,8 @@ export const en = {
|
||||
binaryHint: 'Allow binary files to be posted in topics',
|
||||
enableWeb: 'Enable WebRTC Calls',
|
||||
webHint: 'Enable audio and video calls to contacts',
|
||||
enableService: 'Cloudflare Service',
|
||||
serviceHint: 'Enable Cloudflare Service',
|
||||
serverUrl: 'WebRTC Server URL',
|
||||
urlHint: 'turn:ip:port?transport=udp',
|
||||
webUsername: 'WebRTC Username',
|
||||
@ -350,6 +352,8 @@ export const fr = {
|
||||
binaryHint: 'Autoriser la publication de fichiers binaires dans les sujets',
|
||||
enableWeb: 'Activer les Appels WebRTC',
|
||||
webHint: 'Autoriser les appels audio et vidéo aux contacts',
|
||||
enableService: 'Service Cloudflare',
|
||||
serviceHint: 'Activer le Service Cloudflare',
|
||||
serverUrl: 'URL du Serveur WebRTC',
|
||||
urlHint: 'turn:ip:port?transport=udp',
|
||||
webUsername: "Nom d'Utilisateur WebRTC",
|
||||
@ -557,6 +561,8 @@ export const sp = {
|
||||
binaryHint: 'Permitir que se publiquen archivos binarios en temas',
|
||||
enableWeb: 'Activar llamadas WebRTC',
|
||||
webHint: 'Permitir llamadas de audio y video a contactos',
|
||||
enableService: 'Servicio Cloudflare',
|
||||
serviceHint: 'Habilitar el Servicio Cloudflare',
|
||||
serverUrl: 'URL del servidor WebRTC',
|
||||
urlHint: 'turn:ip:puerto?transporte=udp',
|
||||
webUsername: 'Nombre de usuario WebRTC',
|
||||
@ -763,6 +769,8 @@ export const pt = {
|
||||
binaryHint: 'Permitir que arquivos binários sejam postados em tópicos',
|
||||
enableWeb: 'Ativar chamadas WebRTC',
|
||||
webHint: 'Permitir chamadas de áudio e vídeo para contatos',
|
||||
enableService: 'Serviço Cloudflare',
|
||||
serviceHint: 'Habilitar serviço Cloudflare',
|
||||
serverUrl: 'URL do servidor WebRTC',
|
||||
urlHint: 'turn:ip:port?transport=udp',
|
||||
webUsername: 'Nome de usuário WebRTC',
|
||||
@ -969,6 +977,8 @@ export const de = {
|
||||
binaryHint: 'Erlauben Sie die Veröffentlichung von Binärdateien in Themen',
|
||||
enableWeb: 'WebRTC-Anrufe aktivieren',
|
||||
webHint: 'Audio- und Videoanrufe an Kontakte zulassen',
|
||||
enableService: 'Cloudflare-Dienst',
|
||||
serviceHint: 'Aktivieren Sie den Cloudflare-Dienst',
|
||||
serverUrl: 'URL des WebRTC-Servers',
|
||||
urlHint: 'turn:ip:port?transport=udp',
|
||||
webUsername: 'WebRTC-Benutzername',
|
||||
@ -1175,6 +1185,8 @@ export const ru = {
|
||||
binaryHint: 'Разрешить публикацию двоичных файлов в темах',
|
||||
enableWeb: 'Включить WebRTC-звонки',
|
||||
webHint: 'Разрешить аудио- и видеозвонки контактам',
|
||||
enableService: 'Сервис Cloudflare',
|
||||
serviceHint: 'Включить службу Cloudflare',
|
||||
serverUrl: 'URL сервера WebRTC',
|
||||
urlHint: 'turn:ip:port?transport=udp',
|
||||
webUsername: 'Имя пользователя WebRTC',
|
||||
|
@ -185,8 +185,9 @@ export function useAppContext(websocket) {
|
||||
setAppRevision(activity.revision);
|
||||
}
|
||||
else if (activity.ring) {
|
||||
const { cardId, callId, calleeToken, iceUrl, iceUsername, icePassword } = activity.ring;
|
||||
ringContext.actions.ring(cardId, callId, calleeToken, iceUrl, iceUsername, icePassword);
|
||||
const { cardId, callId, calleeToken, ice, iceUrl, iceUsername, icePassword } = activity.ring;
|
||||
const config = ice ? ice : [{ urls: iceUrl, username: iceUsername, credential: icePassword }];
|
||||
ringContext.actions.ring(cardId, callId, calleeToken, ice);
|
||||
}
|
||||
else {
|
||||
setAppRevision(activity);
|
||||
|
@ -134,6 +134,28 @@ export function useRingContext() {
|
||||
processing.current = false;
|
||||
}
|
||||
|
||||
const getIce = async (service, urls, username, credential) => {
|
||||
if (!service) {
|
||||
return [{ urls, username, credential }];
|
||||
}
|
||||
|
||||
const params = await fetch(urls.replace('%%TURN_KEY_ID%%', username), {
|
||||
method: 'POST',
|
||||
body: '{"ttl": 86400}',
|
||||
headers: new Headers({
|
||||
'Authorization': `Bearer ${credential}`,
|
||||
'Content-Type': 'application/json'
|
||||
})
|
||||
});
|
||||
const server = await params.json();
|
||||
const ice = [];
|
||||
server.iceServers.urls.forEach(urls => {
|
||||
const { username, credential } = server.iceServers;
|
||||
ice.push({ urls, username, credential });
|
||||
});
|
||||
return ice;
|
||||
}
|
||||
|
||||
const getAudioStream = async (audioId) => {
|
||||
try {
|
||||
if (audioId) {
|
||||
@ -300,9 +322,9 @@ export function useRingContext() {
|
||||
clearToken: () => {
|
||||
access.current = null;
|
||||
},
|
||||
ring: (cardId, callId, calleeToken, iceUrl, iceUsername, icePassword) => {
|
||||
ring: (cardId, callId, calleeToken, ice) => {
|
||||
const key = `${cardId}:${callId}`
|
||||
const call = ringing.current.get(key) || { cardId, calleeToken, callId, iceUrl, iceUsername, icePassword }
|
||||
const call = ringing.current.get(key) || { cardId, calleeToken, callId, ice }
|
||||
call.expires = Date.now() + EXPIRE;
|
||||
ringing.current.set(key, call);
|
||||
updateState({ ringing: ringing.current });
|
||||
@ -334,13 +356,11 @@ export function useRingContext() {
|
||||
}
|
||||
}
|
||||
},
|
||||
accept: async (cardId, callId, contactNode, contactToken, calleeToken, iceUrl, iceUsername, icePassword, audioId) => {
|
||||
accept: async (cardId, callId, contactNode, contactToken, calleeToken, ice, audioId) => {
|
||||
if (calling.current) {
|
||||
throw new Error("active session");
|
||||
}
|
||||
|
||||
const ice = [{ urls: iceUrl, username: iceUsername, credential: icePassword }];
|
||||
|
||||
const key = `${cardId}:${callId}`
|
||||
const call = ringing.current.get(key);
|
||||
if (call) {
|
||||
@ -389,6 +409,7 @@ export function useRingContext() {
|
||||
|
||||
// create call
|
||||
let call;
|
||||
let ice;
|
||||
try {
|
||||
call = await addCall(access.current, cardId);
|
||||
}
|
||||
@ -398,9 +419,11 @@ export function useRingContext() {
|
||||
}
|
||||
|
||||
let index = 0;
|
||||
const { id, keepAlive, callerToken, calleeToken, iceUrl, iceUsername, icePassword } = call;
|
||||
const { id, keepAlive, callerToken, calleeToken, iceService, iceUrl, iceUsername, icePassword } = call;
|
||||
try {
|
||||
await addContactRing(contactNode, contactToken, { index, callId: id, calleeToken, iceUrl, iceUsername, icePassword });
|
||||
ice = await getIce(iceService, iceUrl, iceUsername, icePassword);
|
||||
const turn = ice[ice.length - 1];
|
||||
await addContactRing(contactNode, contactToken, { index, callId: id, calleeToken, ice, iceUrl: turn.urls, iceUsername: turn.username, icePassword: turn.credential });
|
||||
}
|
||||
catch (err) {
|
||||
console.log(err);
|
||||
@ -421,7 +444,8 @@ export function useRingContext() {
|
||||
}
|
||||
}
|
||||
else {
|
||||
await addContactRing(contactNode, contactToken, { index, callId: id, calleeToken, iceUrl, iceUsername, icePassword });
|
||||
const turn = ice[ice.length - 1];
|
||||
await addContactRing(contactNode, contactToken, { index, callId: id, calleeToken, ice, iceUrl: turn.urls, iceUsername: turn.username, icePassword: turn.credential });
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
@ -432,7 +456,6 @@ export function useRingContext() {
|
||||
|
||||
updateState({ callStatus: "ringing" });
|
||||
calling.current = { callId: id, host: true };
|
||||
const ice = [{ urls: iceUrl, username: iceUsername, credential: icePassword }];
|
||||
await connect('polite', audioId, window.location.host, callerToken, () => clearInterval(ringInterval), () => clearInterval(aliveInterval), ice);
|
||||
},
|
||||
enableVideo: async (videoId) => {
|
||||
|
@ -265,21 +265,34 @@ export function Dashboard() {
|
||||
defaultChecked={false} checked={state.enableIce} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
<div className="field">
|
||||
<div>{state.strings.serverUrl}</div>
|
||||
<Input placeholder={state.strings.urlHint} onChange={(e) => actions.setIceUrl(e.target.value)}
|
||||
disabled={!state.enableIce} value={state.iceUrl} />
|
||||
</div>
|
||||
<div className="field">
|
||||
<div>{state.strings.webUsername}</div>
|
||||
<Input placeholder={state.strings.username} onChange={(e) => actions.setIceUsername(e.target.value)}
|
||||
disabled={!state.enableIce} value={state.iceUsername} />
|
||||
</div>
|
||||
<div className="field">
|
||||
<div>{state.strings.webPassword}</div>
|
||||
<Input placeholder={state.strings.password} onChange={(e) => actions.setIcePassword(e.target.value)}
|
||||
disabled={!state.enableIce} value={state.icePassword} />
|
||||
</div>
|
||||
{ state.enableIce && (
|
||||
<div className="iceInput">
|
||||
<Tooltip placement="topLeft" title={state.strings.serviceHint}>
|
||||
<div className="field">
|
||||
<div>{state.strings.enableService}</div>
|
||||
<Switch onChange={(e) => actions.setIceService(e)} size="small"
|
||||
defaultChecked={false} checked={state.iceService} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
{ !state.iceService && (
|
||||
<div className="field">
|
||||
<div>{state.strings.serverUrl}</div>
|
||||
<Input placeholder={state.strings.urlHint} onChange={(e) => actions.setIceUrl(e.target.value)}
|
||||
value={state.iceUrl} />
|
||||
</div>
|
||||
)}
|
||||
<div className="field">
|
||||
<div>{state.strings.webUsername}</div>
|
||||
<Input placeholder={state.strings.username} onChange={(e) => actions.setIceUsername(e.target.value)}
|
||||
value={state.iceUsername} />
|
||||
</div>
|
||||
<div className="field">
|
||||
<div>{state.strings.webPassword}</div>
|
||||
<Input placeholder={state.strings.password} onChange={(e) => actions.setIcePassword(e.target.value)}
|
||||
value={state.icePassword} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="control">
|
||||
<Button key="back" onClick={() => actions.setShowSettings(false)}>{state.strings.cancel}</Button>
|
||||
<Button key="save" type="primary" onClick={() => actions.setSettings()} loading={state.busy}>{state.strings.save}</Button>
|
||||
|
@ -111,6 +111,12 @@ export const SettingsLayout = styled(Space)`
|
||||
min-height: 32px;
|
||||
}
|
||||
|
||||
.iceInput {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.field {
|
||||
white-space: nowrap;
|
||||
display: flex;
|
||||
|
@ -27,6 +27,7 @@ export function useDashboard(token) {
|
||||
enableVideo: null,
|
||||
enableBinary: null,
|
||||
enableIce: null,
|
||||
iceService: null,
|
||||
iceUrl: null,
|
||||
iceUsername: null,
|
||||
icePassword: null,
|
||||
@ -128,6 +129,10 @@ export function useDashboard(token) {
|
||||
setEnableIce: (enableIce) => {
|
||||
updateState({ enableIce });
|
||||
},
|
||||
setIceService: (iceService) => {
|
||||
const iceUrl = iceService ? 'https://rtc.live.cloudflare.com/v1/turn/keys/%%TURN_KEY_ID%%/credentials/generate' : '';
|
||||
updateState({ iceService, iceUrl });
|
||||
},
|
||||
setIceUrl: (iceUrl) => {
|
||||
updateState({ iceUrl });
|
||||
},
|
||||
@ -181,9 +186,9 @@ export function useDashboard(token) {
|
||||
if (!state.busy) {
|
||||
updateState({ busy: true });
|
||||
try {
|
||||
const { domain, keyType, accountStorage, pushSupported, transformSupported, allowUnsealed, enableImage, enableAudio, enableVideo, enableBinary, enableIce, iceUrl, iceUsername, icePassword, enableOpenAccess, openAccessLimit } = state;
|
||||
const { domain, keyType, accountStorage, pushSupported, transformSupported, allowUnsealed, enableImage, enableAudio, enableVideo, enableBinary, enableIce, iceService, iceUrl, iceUsername, icePassword, enableOpenAccess, openAccessLimit } = state;
|
||||
const storage = accountStorage * 1073741824;
|
||||
const config = { domain, accountStorage: storage, keyType, enableImage, enableAudio, enableVideo, enableBinary, pushSupported, transformSupported, allowUnsealed, enableIce, iceUrl, iceUsername, icePassword, enableOpenAccess, openAccessLimit };
|
||||
const config = { domain, accountStorage: storage, keyType, enableImage, enableAudio, enableVideo, enableBinary, pushSupported, transformSupported, allowUnsealed, enableIce, iceService, iceUrl, iceUsername, icePassword, enableOpenAccess, openAccessLimit };
|
||||
await setNodeConfig(app.state.adminToken, config);
|
||||
updateState({ busy: false, showSettings: false });
|
||||
}
|
||||
@ -200,9 +205,9 @@ export function useDashboard(token) {
|
||||
try {
|
||||
const enabled = await getAdminMFAuth(app.state.adminToken);
|
||||
const config = await getNodeConfig(app.state.adminToken);
|
||||
const { accountStorage, domain, keyType, pushSupported, transformSupported, allowUnsealed, enableImage, enableAudio, enableVideo, enableBinary, enableIce, iceUrl, iceUsername, icePassword, enableOpenAccess, openAccessLimit } = config;
|
||||
const { accountStorage, domain, keyType, pushSupported, transformSupported, allowUnsealed, enableImage, enableAudio, enableVideo, enableBinary, enableIce, iceService, iceUrl, iceUsername, icePassword, enableOpenAccess, openAccessLimit } = config;
|
||||
const storage = Math.ceil(accountStorage / 1073741824);
|
||||
updateState({ mfAuthSet: true, mfaAuthEnabled: enabled, configError: false, domain, accountStorage: storage, keyType, enableImage, enableAudio, enableVideo, enableBinary, pushSupported, transformSupported, allowUnsealed, enableIce, iceUrl, iceUsername, icePassword, enableOpenAccess, openAccessLimit });
|
||||
updateState({ mfAuthSet: true, mfaAuthEnabled: enabled, configError: false, domain, accountStorage: storage, keyType, enableImage, enableAudio, enableVideo, enableBinary, pushSupported, transformSupported, allowUnsealed, enableIce, iceService, iceUrl, iceUsername, icePassword, enableOpenAccess, openAccessLimit });
|
||||
}
|
||||
catch(err) {
|
||||
console.log(err);
|
||||
|
@ -58,14 +58,14 @@ export function useSession() {
|
||||
const expired = Date.now();
|
||||
ring.state.ringing.forEach(call => {
|
||||
if (call.expires > expired && !call.status) {
|
||||
const { callId, cardId, calleeToken, iceUrl, iceUsername, icePassword } = call;
|
||||
const { callId, cardId, calleeToken, ice } = call;
|
||||
const contact = card.state.cards.get(cardId);
|
||||
if (contact) {
|
||||
const { imageSet, name, handle, node, guid } = contact.data.cardProfile || {};
|
||||
const { token } = contact.data.cardDetail;
|
||||
const contactToken = `${guid}.${token}`;
|
||||
const img = imageSet ? card.actions.getCardImageUrl(cardId) : null;
|
||||
ringing.push({ cardId, img, name, handle, contactNode: node, callId, contactToken, calleeToken, iceUrl, iceUsername, icePassword });
|
||||
ringing.push({ cardId, img, name, handle, contactNode: node, callId, contactToken, calleeToken, ice });
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -180,9 +180,9 @@ export function useSession() {
|
||||
await ring.actions.decline(cardId, node, contactToken, callId);
|
||||
},
|
||||
accept: async (call) => {
|
||||
const { cardId, callId, contactNode, contactToken, calleeToken, iceUrl, iceUsername, icePassword } = call;
|
||||
const { cardId, callId, contactNode, contactToken, calleeToken, ice } = call;
|
||||
const node = contactNode ? contactNode : window.location.host;
|
||||
await ring.actions.accept(cardId, callId, node, contactToken, calleeToken, iceUrl, iceUsername, icePassword, state.audioId);
|
||||
await ring.actions.accept(cardId, callId, node, contactToken, calleeToken, ice, state.audioId);
|
||||
},
|
||||
end: async () => {
|
||||
await ring.actions.end();
|
||||
|
Loading…
Reference in New Issue
Block a user