Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(webrtc): fix incoming & active call destroy on hangup #4868

Merged
merged 3 commits into from
Sep 16, 2022
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 libraries/Enums/types/webrtc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ export enum WebRTCEnum {
HEADPHONES = 'headphones',
}

export type WebRTC = keyof typeof WebRTCEnum
export type WebRTCKinds = keyof typeof WebRTCEnum
42 changes: 23 additions & 19 deletions libraries/Iridium/IridiumManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,24 +49,28 @@ export class IridiumManager extends Emitter {
* @param param0 Textile Configuration that includes id, password and SolanaWallet instance
* @returns a promise that resolves when the initialization completes
*/
async init({ pass, wallet }: { pass: string; wallet: Account }) {
async start({ pass, wallet }: { pass: string; wallet: Account }) {
this.connector?.on('stopping', async () => {
await this.friends.stop?.()
await this.users.stop?.()
// await this.profile.stop?.()
// await this.groups.stop?.()
// await this.chat.stop?.()
// await this.files.stop?.()
// await this.webRTC.stop?.()
// await this.settings.stop?.()
// await this.notifications.stop?.()
await this.stop()
})

logger.info('iridium/manager', 'init()')
const seed = await IdentityManager.seedFromWallet(pass, wallet)
return this.initFromEntropy(seed)
}

async stop() {
await this.friends.stop?.()
await this.users.stop?.()
await this.profile.stop?.()
await this.groups.stop?.()
await this.chat.stop?.()
await this.files.stop?.()
await this.webRTC.stop?.()
await this.settings.stop?.()
await this.notifications.stop?.()
}

get id(): string {
if (!this.connector) {
throw new Error('Iridium not initialized')
Expand Down Expand Up @@ -132,7 +136,7 @@ export class IridiumManager extends Emitter {
this.profile.on('changed', this.onProfileChange.bind(this))

logger.info('iridium/manager', 'initializing profile')
await this.profile.init()
await this.profile.start()
}

async onProfileChange() {
Expand Down Expand Up @@ -174,32 +178,32 @@ export class IridiumManager extends Emitter {
if (this.ready) return

logger.info('iridium/manager', 'initializing users')
await this.users.init()
await this.users.start()

logger.info('iridium/friends', 'initializing friends')
this.friends.init()
this.friends.start()

logger.info('iridium/manager', 'initializing chat')
this.chat.init()
this.chat.start()

logger.info('iridium/manager', 'ready')
this.ready = true
this.emit('ready', {})

logger.info('iridium/manager', 'initializing groups')
this.groups.init()
this.groups.start()

logger.info('iridium/manager', 'initializing files')
this.files.init()
this.files.start()

logger.info('iridium/manager', 'initializing settings')
this.settings.init()
this.settings.start()

logger.info('iridium/manager', 'initializing webRTC')
this.webRTC.init()
this.webRTC.start()

logger.info('iridium/manager', 'notification settings')
this.notifications.init()
this.notifications.start()

logger.info(
'iridium/manager',
Expand Down
4 changes: 3 additions & 1 deletion libraries/Iridium/NotificationManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@ export default class NotificationManager extends Emitter<Notification> {
notifications: [],
}

async init() {
async start() {
await this.fetch()
this.ready = true
this.emit('ready', {})
}

async stop() {}

async fetch() {
logger.info('iridium/notifications/fetch', 'fetching')
const fetched = await iridium.connector?.get<{
Expand Down
4 changes: 3 additions & 1 deletion libraries/Iridium/chat/ChatManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export default class ChatManager extends Emitter<ConversationMessage> {
typing: {},
}

async init() {
async start() {
const fetched = await this.get<State>()
this.state.conversations = {
...this.state.conversations,
Expand Down Expand Up @@ -100,6 +100,8 @@ export default class ChatManager extends Emitter<ConversationMessage> {
this.emit('ready', {})
}

async stop() {}

private async onConversationAnnounce(
message: IridiumPubsubMessage<
IridiumDecodedPayload<IridiumConversationEvent>
Expand Down
4 changes: 3 additions & 1 deletion libraries/Iridium/files/FilesManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { DIRECTORY_TYPE } from '~/libraries/Files/types/directory'
export default class FilesManager extends Emitter {
public state: { items: IridiumItem[] } = { items: [] }

async init() {
async start() {
if (!iridium.connector) {
throw new Error('cannot initialize files, no iridium connector')
}
Expand All @@ -38,6 +38,8 @@ export default class FilesManager extends Emitter {
this.emit('ready', {})
}

async stop() {}

async fetch() {
const res = await iridium.connector?.get<{ items: IridiumItem[] }>('/files')
if (!res?.items) {
Expand Down
2 changes: 1 addition & 1 deletion libraries/Iridium/friends/FriendsManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export default class FriendsManager extends Emitter<IridiumFriendPubsub> {

private loggerTag = 'iridium/friends'

async init() {
async start() {
if (!iridium.connector) {
throw new Error('cannot initialize friends, no iridium connector')
}
Expand Down
4 changes: 3 additions & 1 deletion libraries/Iridium/groups/GroupManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export default class GroupManager extends Emitter<IridiumMessage> {

private loggerTag = 'iridium/groups'

async init() {
async start() {
if (!iridium.connector) {
throw new Error('cannot initialize groups, no iridium connector')
}
Expand All @@ -51,6 +51,8 @@ export default class GroupManager extends Emitter<IridiumMessage> {
await this.fetch()
}

async stop() {}

private async fetch() {
this.state = (await iridium.connector?.get('/groups')) || {}
}
Expand Down
14 changes: 8 additions & 6 deletions libraries/Iridium/profile/ProfileManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export default class IridiumProfile extends Emitter {
public state?: User
public ready?: boolean = false

async init() {
async start() {
if (!iridium) {
throw new Error('cannot initialize profile, no iridium connector')
}
Expand All @@ -22,6 +22,8 @@ export default class IridiumProfile extends Emitter {
})
}

async stop() {}

private async fetch() {
this.state = await this.get<User>()
await this.setUser()
Expand Down Expand Up @@ -75,11 +77,11 @@ export default class IridiumProfile extends Emitter {

async updateUser(details: Partial<User>) {
logger.info('iridium/profile', 'updating user', { details })
for (const [key, value] of Object.entries(details)) {
this.state[key] = value
}

await this.set('/', { ...this.state, ...(details as User) })
this.state = {
...this.state,
...details,
} as User
await this.set('/', this.state)
if (!this.state || !iridium.id) return
// tell our peers via user announce
await iridium.users.send({
Expand Down
4 changes: 3 additions & 1 deletion libraries/Iridium/settings/SettingsManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,12 @@ export default class SettingsManager extends Emitter {
this.state = initialState
}

async init() {
async start() {
await this.fetch()
}

async stop() {}

private async fetch() {
const fetched = await this.get()
if (!fetched) {
Expand Down
2 changes: 1 addition & 1 deletion libraries/Iridium/users/UsersManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export default class UsersManager extends Emitter<IridiumUserPubsub> {
return Object.values(this.state)
}

async init() {
async start() {
if (!iridium.connector) {
throw new Error('cannot initialize users, no iridium connector')
}
Expand Down
40 changes: 30 additions & 10 deletions libraries/Iridium/webrtc/WebRTCManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export default class WebRTCManager extends Emitter {
return this.state.streamConstraints
}

async init() {
async start() {
if (!iridium.connector || !iridium.connector.p2p.primaryNodeID) {
throw new Error('not connected to primary node')
}
Expand All @@ -99,7 +99,7 @@ export default class WebRTCManager extends Emitter {
this.wire.on('wire:message', this.onMessage.bind(this))

// Initialize the Wire
await this.wire.init()
await this.wire.start()

setInterval(() => {
if (this.state.activeCall) {
Expand All @@ -108,6 +108,12 @@ export default class WebRTCManager extends Emitter {
}, 1000)
}

async stop() {
await Promise.all(
Object.values(this.state.calls).map(async (call) => call.destroy()),
)
}

private async onMessage({
type,
message,
Expand Down Expand Up @@ -438,14 +444,25 @@ export default class WebRTCManager extends Emitter {
callId?: string
did: string
}) => {
// It's not related the active call, so we don't reset the state
if (this.state.activeCall?.callId !== callId) return
const incomingCallId = this.state.incomingCall?.callId
if (incomingCallId && incomingCallId === callId) {
const incomingCall = this.state.calls[incomingCallId]
if (incomingCall) {
incomingCall.destroy()
}
this.state.incomingCall = null
}

this.state.incomingCall = null
// It's not related the active call, so we don't reset the state
const activeCallId = this.state.activeCall?.callId
if (!activeCallId || activeCallId !== callId) return
const activeCall = this.state.calls[activeCallId]
activeCall?.destroy()
this.state.activeCall = null
this.state.callStartedAt = 0
}
call.on('HANG_UP', onCallHangup)
call.on('REMOTE_HANG_UP', onCallHangup)

const onCallTrack = async ({
track,
Expand Down Expand Up @@ -591,9 +608,12 @@ export default class WebRTCManager extends Emitter {
callId?: string
did: string
}) => {
// Reset the state only if the event is related to the active call
if (callId === this.state.activeCall?.callId) {
if (!callId) return
if (callId === this.state.incomingCall?.callId) {
this.state.incomingCall = null
}

if (callId === this.state.activeCall?.callId) {
this.state.activeCall = null
this.state.callStartedAt = 0
}
Expand Down Expand Up @@ -760,10 +780,10 @@ export default class WebRTCManager extends Emitter {
}

public async mute({
kind = 'audio',
kind = WebRTCEnum.AUDIO,
did = iridium.id,
}: {
kind: string
kind: WebRTCEnum
did?: string
}) {
if (!this.state.activeCall) return
Expand All @@ -776,7 +796,7 @@ export default class WebRTCManager extends Emitter {
kind,
did = iridium.id,
}: {
kind: string
kind: WebRTCEnum
did?: string
}) {
if (!this.state.activeCall) return
Expand Down
2 changes: 1 addition & 1 deletion libraries/Iridium/webrtc/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { WebRTCEnum } from '~/libraries/Enums/enums'
import { Call } from '~/libraries/WebRTC/Call'

export type PeerMutedState = {
[key in WebRTCEnum]: boolean
[key: string]: boolean
}
export type StreamMutedState = {
[key: string]: PeerMutedState
Expand Down
8 changes: 7 additions & 1 deletion libraries/WebRTC/Call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1051,7 +1051,7 @@ export class Call extends Emitter<CallEventListeners> {
*/
protected _onError(peer: CallPeer, error: Error) {
// FOR DEBUG
console.error(`${error} CODE: ${error.code}`)
logger.error('webrtc/call', 'error', error)
this.emit('ERROR', { did: peer.id, error })
}

Expand Down Expand Up @@ -1201,6 +1201,12 @@ export class Call extends Emitter<CallEventListeners> {
// It's related to another call
if (callId !== this.callId) return

// reset incoming call
this.emit('REMOTE_HANG_UP', {
did,
callId,
})

this.peerDialingDisabled[did] = true
this.isCallee[did] = false
this.isCaller[did] = false
Expand Down
10 changes: 8 additions & 2 deletions libraries/WebRTC/Wire.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export class Wire extends Emitter<WireEventListeners> {
[did: string]: ReturnType<typeof setTimeout>
} = {}

async init() {
async start() {
this._bus = new IridiumBus('/webrtc/announce')

this._bus.on('message', this.onMessage.bind(this))
Expand All @@ -50,6 +50,8 @@ export class Wire extends Emitter<WireEventListeners> {
await this.setupAnnounce()
}

async stop() {}

onMessage({
type,
message,
Expand Down Expand Up @@ -304,7 +306,11 @@ export class Wire extends Emitter<WireEventListeners> {
}
})

logger.debug(this.loggerTag, 'Sending message to', { online, offline })
logger.debug(this.loggerTag, 'Sending message to', {
online,
offline,
message,
})

if (online.length && iridium.connector) {
const encodedMessage = await encoding.encodePayload(
Expand Down
1 change: 1 addition & 0 deletions libraries/WebRTC/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export interface CallEventListeners {
CONNECTED: (data: { did: string; callId?: string }) => void
HANG_UP: (data: { did: string; callId?: string }) => void
ERROR: (data: { did: string; error: Error; callId?: string }) => void
REMOTE_HANG_UP: (data: { did: string; callId?: string }) => void
REMOTE_TRACK_RECEIVED: (data: {
did: string
callId?: string
Expand Down