Automatic SDP negotiation (#103)
This commit is contained in:
@ -2,7 +2,14 @@ import EventEmitter from 'eventemitter3'
|
||||
import { OPCODE } from './data'
|
||||
import { EVENT, WebSocketEvents } from './events'
|
||||
|
||||
import { WebSocketMessages, WebSocketPayloads, SignalProvidePayload, SignalCandidatePayload } from './messages'
|
||||
import {
|
||||
WebSocketMessages,
|
||||
WebSocketPayloads,
|
||||
SignalProvidePayload,
|
||||
SignalCandidatePayload,
|
||||
SignalOfferPayload,
|
||||
SignalAnswerMessage,
|
||||
} from './messages'
|
||||
|
||||
export interface BaseEvents {
|
||||
info: (...message: any[]) => void
|
||||
@ -180,7 +187,7 @@ export abstract class BaseClient extends EventEmitter<BaseEvents> {
|
||||
this._ws!.send(JSON.stringify({ event, ...payload }))
|
||||
}
|
||||
|
||||
public async createPeer(sdp: string, lite: boolean, servers: RTCIceServer[]) {
|
||||
public async createPeer(lite: boolean, servers: RTCIceServer[]) {
|
||||
this.emit('debug', `creating peer`)
|
||||
if (!this.socketOpen) {
|
||||
this.emit(
|
||||
@ -243,13 +250,32 @@ export abstract class BaseClient extends EventEmitter<BaseEvents> {
|
||||
}
|
||||
|
||||
this._peer.ontrack = this.onTrack.bind(this)
|
||||
this._peer.addTransceiver('audio', { direction: 'recvonly' })
|
||||
this._peer.addTransceiver('video', { direction: 'recvonly' })
|
||||
|
||||
this._peer.onnegotiationneeded = async () => {
|
||||
this.emit('warn', `negotiation is needed`)
|
||||
|
||||
const d = await this._peer!.createOffer()
|
||||
this._peer!.setLocalDescription(d)
|
||||
|
||||
this._ws!.send(
|
||||
JSON.stringify({
|
||||
event: EVENT.SIGNAL.OFFER,
|
||||
sdp: d.sdp,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
this._channel = this._peer.createDataChannel('data')
|
||||
this._channel.onerror = this.onError.bind(this)
|
||||
this._channel.onmessage = this.onData.bind(this)
|
||||
this._channel.onclose = this.onDisconnected.bind(this, new Error('peer data channel closed'))
|
||||
}
|
||||
|
||||
public async setRemoteOffer(sdp: string) {
|
||||
if (!this._peer) {
|
||||
this.emit('warn', `attempting to set remote offer while disconnected`)
|
||||
return
|
||||
}
|
||||
|
||||
this._peer.setRemoteDescription({ type: 'offer', sdp })
|
||||
|
||||
@ -274,7 +300,16 @@ export abstract class BaseClient extends EventEmitter<BaseEvents> {
|
||||
}
|
||||
}
|
||||
|
||||
private onMessage(e: MessageEvent) {
|
||||
public async setRemoteAnswer(sdp: string) {
|
||||
if (!this._peer) {
|
||||
this.emit('warn', `attempting to set remote answer while disconnected`)
|
||||
return
|
||||
}
|
||||
|
||||
this._peer.setRemoteDescription({ type: 'answer', sdp })
|
||||
}
|
||||
|
||||
private async onMessage(e: MessageEvent) {
|
||||
const { event, ...payload } = JSON.parse(e.data) as WebSocketMessages
|
||||
|
||||
this.emit('debug', `received websocket event ${event} ${payload ? `with payload: ` : ''}`, payload)
|
||||
@ -282,7 +317,20 @@ export abstract class BaseClient extends EventEmitter<BaseEvents> {
|
||||
if (event === EVENT.SIGNAL.PROVIDE) {
|
||||
const { sdp, lite, ice, id } = payload as SignalProvidePayload
|
||||
this._id = id
|
||||
this.createPeer(sdp, lite, ice)
|
||||
await this.createPeer(lite, ice)
|
||||
await this.setRemoteOffer(sdp)
|
||||
return
|
||||
}
|
||||
|
||||
if (event === EVENT.SIGNAL.OFFER) {
|
||||
const { sdp } = payload as SignalOfferPayload
|
||||
await this.setRemoteOffer(sdp)
|
||||
return
|
||||
}
|
||||
|
||||
if (event === EVENT.SIGNAL.ANSWER) {
|
||||
const { sdp } = payload as SignalAnswerMessage
|
||||
await this.setRemoteAnswer(sdp)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@ export const EVENT = {
|
||||
ERROR: 'system/error',
|
||||
},
|
||||
SIGNAL: {
|
||||
OFFER: 'signal/offer',
|
||||
ANSWER: 'signal/answer',
|
||||
PROVIDE: 'signal/provide',
|
||||
CANDIDATE: 'signal/candidate',
|
||||
@ -81,7 +82,13 @@ export type ControlEvents =
|
||||
|
||||
export type SystemEvents = typeof EVENT.SYSTEM.DISCONNECT
|
||||
export type MemberEvents = typeof EVENT.MEMBER.LIST | typeof EVENT.MEMBER.CONNECTED | typeof EVENT.MEMBER.DISCONNECTED
|
||||
export type SignalEvents = typeof EVENT.SIGNAL.ANSWER | typeof EVENT.SIGNAL.PROVIDE | typeof EVENT.SIGNAL.CANDIDATE
|
||||
|
||||
export type SignalEvents =
|
||||
| typeof EVENT.SIGNAL.OFFER
|
||||
| typeof EVENT.SIGNAL.ANSWER
|
||||
| typeof EVENT.SIGNAL.PROVIDE
|
||||
| typeof EVENT.SIGNAL.CANDIDATE
|
||||
|
||||
export type ChatEvents = typeof EVENT.CHAT.MESSAGE | typeof EVENT.CHAT.EMOTE
|
||||
export type ScreenEvents = typeof EVENT.SCREEN.CONFIGURATIONS | typeof EVENT.SCREEN.RESOLUTION | typeof EVENT.SCREEN.SET
|
||||
|
||||
|
@ -14,6 +14,7 @@ import { Member, ScreenConfigurations, ScreenResolution } from './types'
|
||||
export type WebSocketMessages =
|
||||
| WebSocketMessage
|
||||
| SignalProvideMessage
|
||||
| SignalOfferMessage
|
||||
| SignalAnswerMessage
|
||||
| SignalCandidateMessage
|
||||
| MemberListMessage
|
||||
@ -26,6 +27,7 @@ export type WebSocketMessages =
|
||||
|
||||
export type WebSocketPayloads =
|
||||
| SignalProvidePayload
|
||||
| SignalOfferPayload
|
||||
| SignalAnswerPayload
|
||||
| SignalCandidatePayload
|
||||
| MemberListPayload
|
||||
@ -74,6 +76,14 @@ export interface SignalProvidePayload {
|
||||
sdp: string
|
||||
}
|
||||
|
||||
// signal/offer
|
||||
export interface SignalOfferMessage extends WebSocketMessage, SignalOfferPayload {
|
||||
event: typeof EVENT.SIGNAL.OFFER
|
||||
}
|
||||
export interface SignalOfferPayload {
|
||||
sdp: string
|
||||
}
|
||||
|
||||
// signal/answer
|
||||
export interface SignalAnswerMessage extends WebSocketMessage, SignalAnswerPayload {
|
||||
event: typeof EVENT.SIGNAL.ANSWER
|
||||
|
Reference in New Issue
Block a user