@jxstjh/jhvideo
Version:
HTML5 jhvideo base on MPEG2-TS Stream Player
204 lines (188 loc) • 6.74 kB
text/typescript
import { EventEmitter } from 'events'
const playType = {
REALPLAY: 'realplay',
PLAYBACK: 'playback',
TALK: 'talk'
}
class StreamWebsocket {
private _ws:any = null
private _headBuffer:any = null
private _lastCmd:any = null
private _receivedSteamHead:boolean = false
_requestData={
playUrl:'',
playType:'playback',
startTime:0,
endTime:0,
}
emitter: any
constructor(url:string, playType = 'playback' ) {
this.emitter = new EventEmitter()
this._requestData.playUrl = url
this._requestData.playType = playType
}
on(event:any, listener:any) {
this.emitter.addListener(event, listener);
}
off(event:any, listener:any) {
this.emitter.removeListener(event, listener);
}
sendArrayBuffer(arrBuf:any) {
this._ws.send(arrBuf)
}
open(url?:string) {
return new Promise((resolve, reject) => {
this.emitter.on(`cmd.${this._requestData.playType}`, (code:any, mediaInfo:any) => {
if (code === 0) {
resolve({
code,
mediaInfo,
playType: this._requestData.playType,
head: this._headBuffer
})
} else {
// resolve({})
reject(code)
}
})
const _url = url || this._requestData.playUrl
this._ws = new WebSocket(_url)
this._ws.binaryType = 'arraybuffer'
this._ws.onopen = (val:any) => {
// console.log('onopen',val)
}
this._ws.onerror = (err:any) => {
// console.log('onerror',err)
// this._bError = true
}
this._ws.onclose = () => {
// console.log('close')
// if (this._receivedSteamHead) {
// this.emitter.emit('stream.interrupt', 'codes.ERR_INTERRUPT')
// }
this.emitter.emit(`cmd.${this._requestData.playType}`, '0x-000000')
}
this._ws.onmessage = (msg:any) => {
let { data } = msg
if (data instanceof ArrayBuffer) {
this._handleStream(data)
} else if (typeof data === 'string') {
this._handleInteract(data)
}
}
})
}
/**
* 码流处理
* @param {*} bufData
* @returns
*/
_handleStream(bufData:any) {
if (!this._receivedSteamHead) {
this._headBuffer = bufData
this._receivedSteamHead = true
let isHead = true
if (this.emitter.eventNames().includes(`cmd.${this._requestData.playType}`)) {
this.emitter.emit(`cmd.${this._requestData.playType}`, 0)
}
this.emitter.emit('stream.input', bufData, isHead)
} else {
this.emitter.emit('stream.input', bufData)
}
}
/**
* 交互信息处理
* @param {*} strData
*/
_handleInteract(strData:any) {
let jsonData = JSON.parse(strData)
if (!this._lastCmd) { // 开流
let { errorCode, errorMsg } = jsonData
if (parseInt(errorCode) === 0) { // 安全认证成功,与服务端建立连接
if (this._requestData.playType === playType.TALK) {
this.emitter.emit(`cmd.${this._requestData.playType}`, errorCode, jsonData.audioInfo)
} else {
this.emitter.emit(`cmd.${this._requestData.playType}`, errorCode)
}
} else {
let errorCodeHex = '0x0' + errorCode.toString(16)
this.emitter.emit(`cmd.${this._requestData.playType}`, errorCodeHex, errorMsg)
}
return
}
if (jsonData.hasOwnProperty('errorCode')) { // 交互消息
let { errorCode, errorMsg } = jsonData
if (parseInt(errorCode) === 0) {
this.emitter.emit(`cmd.${this._lastCmd.cmd}`, parseInt(errorCode))
} else {
let errorCodeHex = '0x0' + errorCode.toString(16)
this.emitter.emit(`cmd.${this._lastCmd.cmd}`, errorCodeHex, errorMsg)
}
} else { // 服务端主动消息
if (!jsonData.hasOwnProperty('cmd')) {
let extra:any = {
url: this._requestData.playUrl
}
let cmd = this._requestData.playType
if (this._requestData.playType === playType.PLAYBACK) {
extra.startTime = this._requestData.startTime
extra.endTime = this._requestData.endTime
}
this.sendCmd(cmd, extra).catch((err) => {
console.error(err)
})
} else {
let { cmd } = jsonData
if (cmd === 'end') {
this.emitter.emit('stream.end')
this.close()
}
else if (cmd === 'newStreamFlag') {}
}
}
}
sendCmd(cmd, extra = {}) {
return new Promise((resolve, reject) => {
if (!this._ws && this._ws.readyState !== WebSocket.OPEN) {
return reject('意外的状态')
}
// 设置消息发送监听
this.emitter.once(`cmd.${cmd}`, (code) => {
if (code === 0) {
resolve('codes.OK')
} else {
reject(code)
}
})
// 发送消息
let cmdBody = {
cmd,
...extra,
sequence: !this._lastCmd ? 0 : this._lastCmd.sequence + 1,
}
this._ws.send(JSON.stringify(cmdBody))
this._lastCmd = cmdBody
})
}
destroy() {
this.close()
if(this.emitter){
this.emitter.removeAllListeners()
this.emitter = null;
}
}
close() {
if (!this._ws)
return
let ws = this._ws
ws.close(1000)
ws.onmessage = null
ws.onclose = null
ws.onerror = null
ws.onopen = null
this._ws = null
this._receivedSteamHead = false
this._lastCmd = null
}
}
export default StreamWebsocket