@100mslive/100ms-web-sdk
Advanced tools
Comparing version 0.0.12-31 to 0.0.12-32
export declare enum HMSConnectionRole { | ||
PUBLISH = 0, | ||
SUBSCRIBE = 1 | ||
Publish = 0, | ||
Subscribe = 1 | ||
} | ||
@@ -5,0 +5,0 @@ export interface HMSTrickle { |
@@ -1,11 +0,11 @@ | ||
export interface CodeMessage { | ||
code: number; | ||
message: string; | ||
requiresAction: string; | ||
requiresErrorInfo: string; | ||
} | ||
import { HMSAction } from './HMSAction'; | ||
import { CodeMessage } from './HMSErrors'; | ||
export declare class HMSExceptionBuilder { | ||
private readonly code; | ||
private readonly message; | ||
constructor(code: number, message: string); | ||
private readonly cm; | ||
private _action; | ||
private _errorInfo; | ||
constructor(codeMessage: CodeMessage); | ||
action(action: HMSAction): this; | ||
errorInfo(errorInfo: string): this; | ||
static from(code: number, message: string, requiresAction?: boolean, requiresErrorInfo?: boolean): HMSExceptionBuilder; | ||
build(): HMSException; | ||
@@ -12,0 +12,0 @@ } |
@@ -8,5 +8,5 @@ import HMSVideoTrack from './HMSVideoTrack'; | ||
private replaceTrackWith; | ||
private replaceTrackWithBlackness; | ||
private replaceTrackWithBlank; | ||
setEnabled(value: boolean): Promise<void>; | ||
setSettings(settings: HMSVideoTrackSettings): Promise<void>; | ||
} |
@@ -24,3 +24,2 @@ import HMSConfig from '../interfaces/config'; | ||
private observer; | ||
constructor(); | ||
join(config: HMSConfig, listener: HMSUpdateListener): void; | ||
@@ -27,0 +26,0 @@ private cleanUp; |
@@ -1,5 +0,2 @@ | ||
export declare enum HMSConnectionRole { | ||
PUBLISH = 0, | ||
SUBSCRIBE = 1 | ||
} | ||
import { HMSConnectionRole } from '../connection/model'; | ||
export interface Track { | ||
@@ -6,0 +3,0 @@ mute: boolean; |
@@ -8,2 +8,3 @@ import ITransportObserver from './ITransportObserver'; | ||
export default class HMSTransport implements ITransport { | ||
private state; | ||
private tracks; | ||
@@ -23,2 +24,3 @@ private readonly observer; | ||
private subscribeConnectionObserver; | ||
private handleIceConnectionFailure; | ||
constructor(observer: ITransportObserver); | ||
@@ -25,0 +27,0 @@ getLocalScreen(settings: HMSVideoTrackSettings): Promise<HMSTrack>; |
@@ -1,2 +0,6 @@ | ||
declare function jwt_decode(token: string): any; | ||
export { jwt_decode }; | ||
export interface AuthToken { | ||
roomId: string; | ||
userId: string; | ||
role: string; | ||
} | ||
export default function decodeJWT(token: string): AuthToken; |
{ | ||
"version": "0.0.12-31", | ||
"version": "0.0.12-32", | ||
"license": "UNLICENSED", | ||
@@ -4,0 +4,0 @@ "main": "dist/index.js", |
export enum HMSConnectionRole { | ||
PUBLISH = 0, | ||
SUBSCRIBE = 1, | ||
Publish = 0, | ||
Subscribe = 1, | ||
} | ||
@@ -5,0 +5,0 @@ |
@@ -23,3 +23,3 @@ import HMSConnection from '../index'; | ||
) { | ||
super(HMSConnectionRole.PUBLISH, signal); | ||
super(HMSConnectionRole.Publish, signal); | ||
this.observer = observer; | ||
@@ -26,0 +26,0 @@ this.transport = transport; |
@@ -82,3 +82,3 @@ import HMSConnection from '../index'; | ||
constructor(signal: ISignal, config: RTCConfiguration, observer: ISubscribeConnectionObserver) { | ||
super(HMSConnectionRole.SUBSCRIBE, signal); | ||
super(HMSConnectionRole.Subscribe, signal); | ||
this.observer = observer; | ||
@@ -85,0 +85,0 @@ |
@@ -1,21 +0,61 @@ | ||
// import HMSLogger from '../utils/logger'; | ||
import { HMSAction } from './HMSAction'; | ||
import { CodeMessage } from './HMSErrors'; | ||
export interface CodeMessage { | ||
code: number; | ||
message: string; | ||
requiresAction: string; | ||
requiresErrorInfo: string; | ||
} | ||
export class HMSExceptionBuilder { | ||
private readonly code: number; | ||
private readonly message: string; | ||
private readonly cm: CodeMessage; | ||
private _action: string | null = null; | ||
private _errorInfo: string | null = null; | ||
constructor(code: number, message: string) { | ||
this.code = code; | ||
this.message = message; | ||
constructor(codeMessage: CodeMessage) { | ||
this.cm = codeMessage; | ||
} | ||
action(action: HMSAction) { | ||
this._action = action.toString(); | ||
return this; | ||
} | ||
errorInfo(errorInfo: string) { | ||
this._errorInfo = errorInfo; | ||
return this; | ||
} | ||
static from(code: number, message: string, requiresAction: boolean = false, requiresErrorInfo: boolean = false) { | ||
const cm = { | ||
code, | ||
messageTemplate: message, | ||
requiresAction, | ||
requiresErrorInfo, | ||
}; | ||
if (!message.includes('{action}') && requiresAction) { | ||
cm.messageTemplate = `[{action}] ${cm.messageTemplate}`; | ||
} | ||
if (!message.includes('{error_info}') && requiresAction) { | ||
cm.messageTemplate = `${cm.messageTemplate}. {error_info}`; | ||
} | ||
return new HMSExceptionBuilder(cm); | ||
} | ||
build(): HMSException { | ||
return new HMSException(this.code, this.message); | ||
const { code, requiresAction, requiresErrorInfo } = this.cm; | ||
let message = this.cm.messageTemplate; | ||
if (requiresAction && this._action === null) { | ||
throw Error(`${code}: ${message} requires action property`); | ||
} else if (requiresAction) { | ||
message = message.replace('{action}', this._action!); | ||
} else if (this._action !== null) { | ||
message = `[${this._action}] ${message}`; | ||
} | ||
if (requiresErrorInfo && this._errorInfo === null) { | ||
throw Error(`${code}: ${message} requires errorInfo property`); | ||
} else if (requiresErrorInfo) { | ||
message = message.replace('{error_info}', this._errorInfo!); | ||
} else if (this._errorInfo !== null) { | ||
message = `${message}. ${this._errorInfo}`; | ||
} | ||
return new HMSException(this.cm.code, message); | ||
} | ||
@@ -29,4 +69,8 @@ } | ||
super(message); | ||
// Ref: https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work | ||
Object.setPrototypeOf(this, HMSException.prototype); | ||
this.name = 'HMSException'; | ||
this.code = code; | ||
} | ||
} |
import HMSVideoTrackSettings, { HMSVideoTrackSettingsBuilder } from './HMSVideoTrackSettings'; | ||
import HMSAudioTrackSettings, { HMSAudioTrackSettingsBuilder } from './HMSAudioTrackSettings'; | ||
import { HMSExceptionBuilder } from '../../error/HMSException'; | ||
import HMSErrors from '../../error/HMSErrors'; | ||
@@ -26,3 +28,3 @@ export class HMSTrackSettingsBuilder { | ||
if (this._audio === null && this._video === null) { | ||
throw Error('There is no media to return. Please select either video or audio or both'); | ||
throw new HMSExceptionBuilder(HMSErrors.NothingToReturn).build(); | ||
} | ||
@@ -29,0 +31,0 @@ |
@@ -9,2 +9,4 @@ import HMSMediaStream from './HMSMediaStream'; | ||
import HMSLogger from '../../utils/logger'; | ||
import { HMSAction } from '../../error/HMSAction'; | ||
import { BuildGetMediaError } from '../../error/HMSErrorFactory'; | ||
@@ -27,4 +29,10 @@ const TAG = 'HMSLocalStream'; | ||
} as MediaStreamConstraints; | ||
// @ts-ignore [https://github.com/microsoft/TypeScript/issues/33232] | ||
const stream = (await navigator.mediaDevices.getDisplayMedia(constraints)) as MediaStream; | ||
let stream; | ||
try { | ||
// @ts-ignore [https://github.com/microsoft/TypeScript/issues/33232] | ||
stream = (await navigator.mediaDevices.getDisplayMedia(constraints)) as MediaStream; | ||
} catch (err) { | ||
throw BuildGetMediaError(err, HMSAction.GetLocalScreen); | ||
} | ||
const local = new HMSLocalStream(stream); | ||
@@ -39,8 +47,12 @@ const nativeTrack = stream.getVideoTracks()[0]; | ||
static async getLocalTracks(settings: HMSTrackSettings) { | ||
const stream = await navigator.mediaDevices.getUserMedia({ | ||
audio: settings.audio != null ? settings.audio!.toConstraints() : false, | ||
video: settings.video != null ? settings.video!.toConstraints() : false, | ||
}); | ||
let stream; | ||
try { | ||
stream = await navigator.mediaDevices.getUserMedia({ | ||
audio: settings.audio != null ? settings.audio!.toConstraints() : false, | ||
video: settings.video != null ? settings.video!.toConstraints() : false, | ||
}); | ||
} catch (err) { | ||
throw BuildGetMediaError(err, HMSAction.GetLocalScreen); | ||
} | ||
// TODO: Handle error cases, wrap in `HMSException` and throw it | ||
const local = new HMSLocalStream(stream); | ||
@@ -47,0 +59,0 @@ const tracks: Array<HMSTrack> = []; |
@@ -5,6 +5,3 @@ import HMSAudioTrack from './HMSAudioTrack'; | ||
import { getAudioTrack } from '../../utils/track'; | ||
import HMSLogger from '../../utils/logger'; | ||
const TAG = '[HMSLocalAudioTrack]'; | ||
function generateHasPropertyChanged(newSettings: HMSAudioTrackSettings, oldSettings: HMSAudioTrackSettings) { | ||
@@ -45,6 +42,2 @@ return function hasChanged(prop: 'codec' | 'volume' | 'maxBitrate' | 'deviceId' | 'advanced') { | ||
if (hasPropertyChanged('codec')) { | ||
HMSLogger.w(TAG, "Audio Codec can't be changed mid call."); | ||
} | ||
if (hasPropertyChanged('deviceId')) { | ||
@@ -59,7 +52,3 @@ await this.replaceTrackWith(newSettings); | ||
if (hasPropertyChanged('advanced')) { | ||
try { | ||
await this.nativeTrack.applyConstraints(newSettings.toConstraints()); | ||
} catch (error) { | ||
HMSLogger.e(TAG, error); | ||
} | ||
await this.nativeTrack.applyConstraints(newSettings.toConstraints()); | ||
} | ||
@@ -66,0 +55,0 @@ |
@@ -5,3 +5,2 @@ import HMSVideoTrack from './HMSVideoTrack'; | ||
import { getEmptyVideoTrack, getVideoTrack } from '../../utils/track'; | ||
import HMSLogger from '../../utils/logger'; | ||
@@ -16,4 +15,2 @@ function generateHasPropertyChanged(newSettings: HMSVideoTrackSettings, oldSettings: HMSVideoTrackSettings) { | ||
const TAG = '[HMSLocalVideoTrack]'; | ||
export default class HMSLocalVideoTrack extends HMSVideoTrack { | ||
@@ -36,3 +33,3 @@ settings: HMSVideoTrackSettings; | ||
private async replaceTrackWithBlackness() { | ||
private async replaceTrackWithBlank() { | ||
const prevTrack = this.nativeTrack; | ||
@@ -51,3 +48,3 @@ const withTrack = getEmptyVideoTrack(prevTrack); | ||
} else { | ||
await this.replaceTrackWithBlackness(); | ||
await this.replaceTrackWithBlank(); | ||
} | ||
@@ -62,6 +59,2 @@ } | ||
if (hasPropertyChanged('codec')) { | ||
HMSLogger.w(TAG, "Video Codec can't be changed mid call."); | ||
} | ||
if (hasPropertyChanged('deviceId')) { | ||
@@ -68,0 +61,0 @@ await this.replaceTrackWith(newSettings); |
@@ -9,3 +9,3 @@ import HMSConfig from '../interfaces/config'; | ||
import HMSLogger, { HMSLogLevel } from '../utils/logger'; | ||
import { jwt_decode } from '../utils/jwt'; | ||
import decodeJWT from '../utils/jwt'; | ||
import { getNotificationMethod, HMSNotificationMethod } from './models/enums/HMSNotificationMethod'; | ||
@@ -64,3 +64,3 @@ import { getNotification, HMSNotifications, Peer as PeerNotification } from './models/HMSNotifications'; | ||
constructor() { | ||
join(config: HMSConfig, listener: HMSUpdateListener) { | ||
this.notificationManager.addEventListener('role-change', (e: any) => { | ||
@@ -70,9 +70,5 @@ this.publishParams = e.detail.params.role.publishParams; | ||
this.transport = new HMSTransport(this.observer); | ||
} | ||
join(config: HMSConfig, listener: HMSUpdateListener) { | ||
this.transport = new HMSTransport(this.observer); | ||
this.listener = listener; | ||
this.audioSinkManager = new HMSAudioSinkManager(this.notificationManager, config.audioSinkElementId); | ||
const { room_id, role } = jwt_decode(config.authToken); | ||
const { roomId, role } = decodeJWT(config.authToken); | ||
@@ -90,3 +86,3 @@ const peerId = uuidv4(); | ||
HMSLogger.d(this.TAG, `⏳ Joining room ${room_id}`); | ||
HMSLogger.d(this.TAG, `⏳ Joining room ${roomId}`); | ||
@@ -102,4 +98,4 @@ this.transport | ||
.then(() => { | ||
HMSLogger.d(this.TAG, `✅ Joined room ${room_id}`); | ||
this.roomId = room_id; | ||
HMSLogger.d(this.TAG, `✅ Joined room ${roomId}`); | ||
this.roomId = roomId; | ||
if (!this.published) { | ||
@@ -106,0 +102,0 @@ this.publish(config.settings); |
@@ -18,7 +18,6 @@ import { InitConfig } from './models'; | ||
// TODO: Add user-agent, handle error status codes | ||
// @TODO: Add user-agent, handle error status codes | ||
const response = await fetch(url); | ||
const config = (await response.json()) as InitConfig; | ||
return config; | ||
return (await response.json()) as InitConfig; | ||
} | ||
} |
@@ -1,5 +0,2 @@ | ||
export enum HMSConnectionRole { | ||
PUBLISH = 0, | ||
SUBSCRIBE = 1, | ||
} | ||
import { HMSConnectionRole } from '../connection/model'; | ||
@@ -6,0 +3,0 @@ export interface Track { |
@@ -9,2 +9,3 @@ import { v4 as uuid } from 'uuid'; | ||
import HMSLogger from '../../utils/logger'; | ||
import HMSErrors from '../../error/HMSErrors'; | ||
import HMSMessage from '../../interfaces/message'; | ||
@@ -63,2 +64,10 @@ | ||
this.socket.addEventListener('open', openHandler); | ||
this.socket.addEventListener('close', (e) => { | ||
// https://stackoverflow.com/questions/18803971/websocket-onerror-how-to-read-error-description | ||
if (e.code !== 1000) { | ||
// 1000 code indicated `Normal Closure` [https://tools.ietf.org/html/rfc6455#section-7.4.1] | ||
const error = new HMSExceptionBuilder(HMSErrors.ConnectionLost).errorInfo(`${e.reason} [${e.code}]`).build(); | ||
this.observer.onFailure(error); | ||
} | ||
}); | ||
this.socket.addEventListener('message', (event) => this.onMessageHandler(event.data)); | ||
@@ -148,3 +157,3 @@ }); | ||
const error = response.error; | ||
const ex = new HMSExceptionBuilder(error.code, error.message).build(); | ||
const ex = HMSExceptionBuilder.from(error.code, error.message).build(); | ||
cb.reject(ex); | ||
@@ -151,0 +160,0 @@ } |
@@ -13,3 +13,3 @@ import ITransportObserver from './ITransportObserver'; | ||
import HMSTrack from '../media/tracks/HMSTrack'; | ||
import HMSException from '../error/HMSException'; | ||
import HMSException, { HMSExceptionBuilder } from '../error/HMSException'; | ||
import { PromiseCallbacks } from '../utils/promise'; | ||
@@ -23,5 +23,15 @@ import { RENEGOTIATION_CALLBACK_ID } from '../utils/constants'; | ||
import { TrackState } from '../sdk/models/HMSNotifications'; | ||
import HMSErrors from '../error/HMSErrors'; | ||
import { TransportState } from './TransportState'; | ||
import { HMSAction } from '../error/HMSAction'; | ||
const TAG = '[HMSTransport]:'; | ||
interface CallbackTriple { | ||
promise: PromiseCallbacks<boolean>; | ||
action: HMSAction; | ||
extra: any; | ||
} | ||
export default class HMSTransport implements ITransport { | ||
private state: TransportState = TransportState.Disconnected; | ||
private tracks: Map<string, TrackState> = new Map(); | ||
@@ -37,3 +47,3 @@ private readonly observer: ITransportObserver; | ||
*/ | ||
private readonly callbacks = new Map<string, PromiseCallbacks<boolean>>(); | ||
private readonly callbacks = new Map<string, CallbackTriple>(); | ||
@@ -53,3 +63,3 @@ private signalObserver: ISignalEventsObserver = { | ||
const connection = | ||
trickle.target === HMSConnectionRole.PUBLISH ? this.publishConnection! : this.subscribeConnection!; | ||
trickle.target === HMSConnectionRole.Publish ? this.publishConnection! : this.subscribeConnection!; | ||
if (connection.remoteDescription === null) { | ||
@@ -77,3 +87,2 @@ // ICE candidates can't be added without any remote session description | ||
// TODO: Handle errors, pass these errors as publish failure (try-catch) | ||
try { | ||
@@ -84,6 +93,17 @@ const offer = await this.publishConnection!.createOffer(); | ||
await this.publishConnection!.setRemoteDescription(answer); | ||
callback?.resolve(true); | ||
HMSLogger.d(TAG, `✅ [role=PUBLISH] onRenegotiationNeeded DONE`, this.tracks); | ||
} catch (e) { | ||
console.error(TAG, e); | ||
callback!.promise.resolve(true); | ||
HMSLogger.d(TAG, `[role=PUBLISH] onRenegotiationNeeded DONE ✅`); | ||
} catch (err) { | ||
let ex: HMSException; | ||
if (err instanceof HMSException) { | ||
ex = err; | ||
} else { | ||
ex = new HMSExceptionBuilder(HMSErrors.PeerConnectionFailed) | ||
.action(callback!.action) | ||
.errorInfo(err.message) | ||
.build(); | ||
} | ||
callback!.promise.reject(ex); | ||
HMSLogger.d(TAG, `[role=PUBLISH] onRenegotiationNeeded FAILED ❌`); | ||
} | ||
@@ -94,3 +114,3 @@ }, | ||
if (newState === 'failed') { | ||
// TODO: Handle `failed` event, initiate restartIce/reconnection | ||
this.handleIceConnectionFailure(HMSConnectionRole.Publish); | ||
} | ||
@@ -105,8 +125,15 @@ }, | ||
onTrackAdd: (track: HMSTrack) => this.observer.onTrackAdd(track), | ||
onTrackRemove: (track: HMSTrack) => this.observer.onTrackRemove(track), | ||
onTrackAdd: (track: HMSTrack) => { | ||
HMSLogger.d(TAG, '[Subscribe] onTrackAdd', track); | ||
this.observer.onTrackAdd(track); | ||
}, | ||
onTrackRemove: (track: HMSTrack) => { | ||
HMSLogger.d(TAG, '[Subscribe] onTrackRemove', track); | ||
this.observer.onTrackRemove(track); | ||
}, | ||
onIceConnectionChange: (newState: RTCIceConnectionState) => { | ||
if (newState === 'failed') { | ||
// TODO: Handle `failed` event, initiate restartIce/reconnection | ||
this.handleIceConnectionFailure(HMSConnectionRole.Subscribe); | ||
} | ||
@@ -116,2 +143,14 @@ }, | ||
private handleIceConnectionFailure(role: HMSConnectionRole) { | ||
// TODO: Should we initiate an ice-restart? | ||
// TODO: Should we close both peer-connections or just one? | ||
const ex = new HMSExceptionBuilder(HMSErrors.PeerConnectionFailed) | ||
.errorInfo(`[role=${role}] Ice connection state FAILED`) | ||
.build(); | ||
this.state = TransportState.Failed; | ||
this.observer.onFailure(ex); | ||
} | ||
constructor(observer: ITransportObserver) { | ||
@@ -122,4 +161,3 @@ this.observer = observer; | ||
async getLocalScreen(settings: HMSVideoTrackSettings): Promise<HMSTrack> { | ||
const track = await HMSLocalStream.getLocalScreen(settings); | ||
return track; | ||
return await HMSLocalStream.getLocalScreen(settings); | ||
} | ||
@@ -138,2 +176,5 @@ | ||
): Promise<void> { | ||
if (this.state !== TransportState.Disconnected) { | ||
throw new HMSExceptionBuilder(HMSErrors.AlreadyJoined).action(HMSAction.Join).build(); | ||
} | ||
const config = await InitService.fetchInitConfig(authToken, initEndpoint); | ||
@@ -186,3 +227,7 @@ | ||
const p = new Promise<boolean>((resolve, reject) => { | ||
this.callbacks.set(RENEGOTIATION_CALLBACK_ID, { resolve, reject }); | ||
this.callbacks.set(RENEGOTIATION_CALLBACK_ID, { | ||
promise: { resolve, reject }, | ||
action: HMSAction.Publish, | ||
extra: {}, | ||
}); | ||
}); | ||
@@ -210,3 +255,7 @@ const stream = track.stream as HMSLocalStream; | ||
const p = new Promise<boolean>((resolve, reject) => { | ||
this.callbacks.set(RENEGOTIATION_CALLBACK_ID, { resolve, reject }); | ||
this.callbacks.set(RENEGOTIATION_CALLBACK_ID, { | ||
promise: { resolve, reject }, | ||
action: HMSAction.Unpublish, | ||
extra: {}, | ||
}); | ||
}); | ||
@@ -213,0 +262,0 @@ const stream = track.stream as HMSLocalStream; |
@@ -1,14 +0,36 @@ | ||
import { jwt_decode } from './jwt'; | ||
import HMSErrors from '../error/HMSErrors'; | ||
import HMSException from '../error/HMSException'; | ||
import decodeJWT from './jwt'; | ||
const token = | ||
const validToken = | ||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3Nfa2V5IjoiNWY5ZWRjNmJkMjM4MjE1YWVjNzcwMGUyIiwiYXBwX2lkIjoiNWY5ZWRjNmJkMjM4MjE1YWVjNzcwMGUxIiwicm9vbV9pZCI6IjVmY2I0ZGY2YjQ5MjQxOWE5ODVhYjIzYSIsInVzZXJfaWQiOiJhMDVmZWEzZC03YmNhLTRhY2ItODQ1Ny1mZjliZTM4NjIwMDlFZGxhIiwicm9sZSI6Ikhvc3QiLCJpYXQiOjE2MTg0NzgyMzksImV4cCI6MTYxODU2NDYzOSwiaXNzIjoiNWY5ZWRjNmJkMjM4MjE1YWVjNzcwMGRmIiwianRpIjoiZjE0OTZhNmQtMjllYy00ZGVhLWI0YmItNzZkMjcxOGY0NDJkIn0.YsBSyt52cdRfYDSeDEm-FRc4wL792eXM6PFHMtrp6i4'; | ||
describe('jwt_decode', () => { | ||
describe('decodeJWT', () => { | ||
it('should return roomId from an authToken', () => { | ||
expect(jwt_decode(token).room_id).toEqual('5fcb4df6b492419a985ab23a'); | ||
expect(decodeJWT(validToken).roomId).toEqual('5fcb4df6b492419a985ab23a'); | ||
}); | ||
it('should return role from an authToken', () => { | ||
expect(jwt_decode(token).role).toEqual('Host'); | ||
expect(decodeJWT(validToken).role).toEqual('Host'); | ||
}); | ||
it('should throw HMSException when authToken is empty', () => { | ||
try { | ||
decodeJWT(''); | ||
} catch (e) { | ||
expect(e).toBeInstanceOf(HMSException); | ||
expect(e.message).toEqual(HMSErrors.MissingToken.messageTemplate); | ||
} | ||
}); | ||
it('should throw HMSException when authToken is invalid', () => { | ||
try { | ||
decodeJWT( | ||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3Nfa2V5IjoiNWY5ZWRjNmJkMjM4MjE1YWVjNzcwMGUyIiwiYXBwX2lkIjoiNWY5ZWRjNmJkMjM4MjE1YWVjNzcwMGUxIiwicm9vbV9pZCI6IjVmY2I0ZGY2YjQ5MjQxOWE5ODVhYjIzYSIsInVzZXJfaWQiOiJhMDVmZWEzZC03YmNhLTRhY2ItODQ1Ny1mZjliZTM4NjIwMDlFZGxhIiwicm9sZSI6Ikhvc3QiLCJpYXQiOjE2MTg0NzgyMzksImV4cCI6MTYxODU2NDYzOSwiaXNzIjoiNWY5ZWRjNmJkMjM4MjE1YWVjNzcwMGRmIiwianRpIjoiZjE0OTZhNmQtMjllYy00ZGVhLWI0YmItNz', | ||
); | ||
} catch (e) { | ||
expect(e).toBeInstanceOf(HMSException); | ||
expect(e.message).toEqual(HMSErrors.InvalidTokenFormat.messageTemplate); | ||
} | ||
}); | ||
}); |
@@ -1,5 +0,31 @@ | ||
function jwt_decode(token: string) { | ||
return JSON.parse(atob(token.split('.')[1])); | ||
import HMSErrors from '../error/HMSErrors'; | ||
import { HMSExceptionBuilder } from '../error/HMSException'; | ||
export interface AuthToken { | ||
roomId: string; | ||
userId: string; | ||
role: string; | ||
} | ||
export { jwt_decode }; | ||
export default function decodeJWT(token: string): AuthToken { | ||
if (token.length === 0) { | ||
throw new HMSExceptionBuilder(HMSErrors.MissingToken).build(); | ||
} | ||
const parts = token.split('.'); | ||
if (parts.length !== 3) { | ||
throw new HMSExceptionBuilder(HMSErrors.InvalidTokenFormat).build(); | ||
} | ||
const payloadStr = atob(parts[1]); | ||
try { | ||
const payload = JSON.parse(payloadStr); | ||
return { | ||
roomId: payload.room_id, | ||
userId: payload.user_id, | ||
role: payload.role, | ||
} as AuthToken; | ||
} catch (err) { | ||
throw new HMSExceptionBuilder(HMSErrors.TokenMissingRoomId).build(); | ||
} | ||
} |
@@ -0,16 +1,26 @@ | ||
import { HMSAction } from '../error/HMSAction'; | ||
import { BuildGetMediaError } from '../error/HMSErrorFactory'; | ||
import HMSAudioTrackSettings from '../media/settings/HMSAudioTrackSettings'; | ||
import HMSVideoTrackSettings from '../media/settings/HMSVideoTrackSettings'; | ||
export async function getAudioTrack(settings: HMSAudioTrackSettings) { | ||
const stream = await navigator.mediaDevices.getUserMedia({ | ||
audio: settings.toConstraints(), | ||
}); | ||
return stream.getAudioTracks()[0]; | ||
export async function getAudioTrack(settings: HMSAudioTrackSettings): Promise<MediaStreamTrack> { | ||
try { | ||
const stream = await navigator.mediaDevices.getUserMedia({ | ||
audio: settings.toConstraints(), | ||
}); | ||
return stream.getAudioTracks()[0]; | ||
} catch (err) { | ||
throw BuildGetMediaError(err, HMSAction.SwitchDevice); | ||
} | ||
} | ||
export async function getVideoTrack(settings: HMSVideoTrackSettings) { | ||
const stream = await navigator.mediaDevices.getUserMedia({ | ||
video: settings.toConstraints(), | ||
}); | ||
return stream.getVideoTracks()[0]; | ||
export async function getVideoTrack(settings: HMSVideoTrackSettings): Promise<MediaStreamTrack> { | ||
try { | ||
const stream = await navigator.mediaDevices.getUserMedia({ | ||
video: settings.toConstraints(), | ||
}); | ||
return stream.getVideoTracks()[0]; | ||
} catch (err) { | ||
throw BuildGetMediaError(err, HMSAction.SwitchDevice); | ||
} | ||
} | ||
@@ -17,0 +27,0 @@ |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1157177
151
12891