import { inject , injectable } from 'inversify' ; import * as apid from '../../../../api' ; import IChannelDB from '../../db/IChannelDB' ; import IProgramDB from '../../db/IProgramDB' ; import IRecordedDB from '../../db/IRecordedDB' ; import IVideoFileDB from '../../db/IVideoFileDB' ; import IConfiguration from '../../IConfiguration' ; import { LiveHLSStreamModelProvider , LiveStreamModelProvider } from '../../service/stream/base/ILiveStreamBaseModel' ; import { RecordedHLSStreamModelProvider , RecordedStreamModelProvider , } from '../../service/stream/base/IRecordedStreamBaseModel' ; import IStreamManageModel from '../../service/stream/manager/IStreamManageModel' ; import IApiUtil from '../IApiUtil' ; import IPlayList from '../IPlayList' ; import IStreamApiModel , { StreamResponse } from './IStreamApiModel' ; interface StreamConfig { cmd ? : string ; } interface RecordedStreamConfig { cmd : string ; } @ injectable ( ) export default class StreamApiModel implements IStreamApiModel { private configure : IConfiguration ; private liveStreamProvider : LiveStreamModelProvider ; private liveHLSStreamProvider : LiveHLSStreamModelProvider ; private recordedStreamProvider : RecordedStreamModelProvider ; private recordedHLSStreamProvider : RecordedHLSStreamModelProvider ; private streamManageModel : IStreamManageModel ; private programDB : IProgramDB ; private videoFileDB : IVideoFileDB ; private recordedDB : IRecordedDB ; private channelDB : IChannelDB ; private apiUtil : IApiUtil ; constructor ( @ inject ( 'IConfiguration' ) configure , @ inject ( 'LiveStreamModelProvider' ) liveStreamProvider , @ inject ( 'LiveHLSStreamModelProvider' ) liveHLSStreamProvider , @ inject ( 'RecordedStreamModelProvider' ) recordedStreamProvider , @ inject ( 'RecordedHLSStreamModelProvider' ) recordedHLSStreamProvider , @ inject ( 'IStreamManageModel' ) streamManageModel , @ inject ( 'IProgramDB' ) programDB , @ inject ( 'IVideoFileDB' ) videoFileDB , @ inject ( 'IRecordedDB' ) recordedDB , @ inject ( 'IChannelDB' ) channelDB , @ inject ( 'IApiUtil' ) apiUtil ) { this . configure = configure ; this . liveStreamProvider = liveStreamProvider ; this . liveHLSStreamProvider = liveHLSStreamProvider ; this . recordedStreamProvider = recordedStreamProvider ; this . recordedHLSStreamProvider = recordedHLSStreamProvider ; this . streamManageModel = streamManageModel ; this . programDB = programDB ; this . videoFileDB = videoFileDB ; this . recordedDB = recordedDB ; this . channelDB = channelDB ; this . apiUtil = apiUtil ; } param option return public async startLiveM2TsStream ( option ) { const conf = this . getTsLiveConfig ( 'm2ts' , option . mode ) ; const stream = await this . liveStreamProvider ( ) ; stream . setOption ( { channelId : option . channelId , cmd : conf . cmd , } , option . mode ) ; const streamId = await this . streamManageModel . start ( stream ) ; return { streamId : streamId , stream : stream . getStream ( ) , } ; } param option return public async startLiveM2TsLLStream ( option ) { const conf = this . getTsLiveConfig ( 'm2tsll' , option . mode ) ; const stream = await this . liveStreamProvider ( ) ; stream . setOption ( { channelId : option . channelId , cmd : conf . cmd , } , option . mode ) ; const streamId = await this . streamManageModel . start ( stream ) ; return { streamId : streamId , stream : stream . getStream ( ) , } ; } param option return public async startLiveWebmStream ( option ) { const conf = this . getTsLiveConfig ( 'webm' , option . mode ) ; const stream = await this . liveStreamProvider ( ) ; stream . setOption ( { channelId : option . channelId , cmd : conf . cmd , } , option . mode ) ; const streamId = await this . streamManageModel . start ( stream ) ; return { streamId : streamId , stream : stream . getStream ( ) , } ; } param option return public async startMp4Stream ( option ) { const conf = this . getTsLiveConfig ( 'mp4' , option . mode ) ; const stream = await this . liveStreamProvider ( ) ; stream . setOption ( { channelId : option . channelId , cmd : conf . cmd , } , option . mode ) ; const streamId = await this . streamManageModel . start ( stream ) ; return { streamId : streamId , stream : stream . getStream ( ) , } ; } param option return public async startLiveHLSStream ( option ) { const conf = this . getTsLiveConfig ( 'hls' , option . mode ) ; const stream = await this . liveHLSStreamProvider ( ) ; stream . setOption ( { channelId : option . channelId , cmd : conf . cmd , } , option . mode ) ; return await this . streamManageModel . start ( stream ) ; } param type param mode return private getTsLiveConfig ( type , mode ) { const config = this . configure . getConfig ( ) ; if ( typeof config . stream === 'undefined' || typeof config . stream . live === 'undefined' || typeof config . stream . live . ts === 'undefined' || typeof config . stream . live . ts [ type ] === 'undefined' || typeof ( config . stream . live . ts [ type ] as any ) [ mode ] === 'undefined' ) { throw new Error ( 'ConfigIsUndefined' ) ; } return { cmd : ( config . stream . live . ts [ type ] as any ) [ mode ] . cmd , } ; } param option return public async startRecordedWebMStream ( option ) { const conf = await this . getRecordedVideoConfig ( 'webm' , option ) ; const stream = await this . recordedStreamProvider ( ) ; stream . setOption ( { videoFileId : option . videoFileId , playPosition : option . playPosition , cmd : conf . cmd , } , option . mode ) ; const streamId = await this . streamManageModel . start ( stream ) ; return { streamId : streamId , stream : stream . getStream ( ) , } ; } param option return public async startRecordedMp4Stream ( option ) { const conf = await this . getRecordedVideoConfig ( 'mp4' , option ) ; const stream = await this . recordedStreamProvider ( ) ; stream . setOption ( { videoFileId : option . videoFileId , playPosition : option . playPosition , cmd : conf . cmd , } , option . mode ) ; const streamId = await this . streamManageModel . start ( stream ) ; return { streamId : streamId , stream : stream . getStream ( ) , } ; } param option return public async startRecordedHLSStream ( option ) { const conf = await this . getRecordedVideoConfig ( 'hls' , option ) ; const stream = await this . recordedHLSStreamProvider ( ) ; stream . setOption ( { videoFileId : option . videoFileId , playPosition : option . playPosition , cmd : conf . cmd , } , option . mode ) ; return await this . streamManageModel . start ( stream ) ; } param type param option return private async getRecordedVideoConfig ( type , option ) { const isEncodedVideo = await this . isEncodedVideo ( option . videoFileId ) ; const config = this . configure . getConfig ( ) ; if ( typeof config . stream === 'undefined' || typeof config . stream . recorded === 'undefined' ) { throw new Error ( 'ConfigIsUndefined' ) ; } let cmd ; if ( isEncodedVideo === true ) { if ( typeof config . stream . recorded . encoded === 'undefined' || typeof config . stream . recorded . encoded [ type ] === 'undefined' || typeof ( config . stream . recorded . encoded [ type ] as any ) [ option . mode ] === 'undefined' ) { throw new Error ( 'ConfigIsUndefined' ) ; } cmd = ( config . stream . recorded . encoded [ type ] as any ) [ option . mode ] . cmd ; } else { if ( typeof config . stream . recorded . ts === 'undefined' || typeof config . stream . recorded . ts [ type ] === 'undefined' || typeof ( config . stream . recorded . ts [ type ] as any ) [ option . mode ] === 'undefined' ) { throw new Error ( 'ConfigIsUndefined' ) ; } cmd = ( config . stream . recorded . ts [ type ] as any ) [ option . mode ] . cmd ; } if ( typeof cmd === 'undefined' ) { throw new Error ( 'CmdIsUndefined' ) ; } return { cmd : cmd , } ; } param videoFileId return private async isEncodedVideo ( videoFileId ) { const video = await this . videoFileDB . findId ( videoFileId ) ; if ( video === null ) { throw new Error ( 'VideoFileIsNotFound' ) ; } return video . type === 'encoded' ; } param host param isSecure param option return public async getLiveM2TsStreamM3u8 ( host , isSecure , option ) { const channel = await this . channelDB . findId ( option . channelId ) ; if ( channel === null ) { return null ; } return { name : encodeURIComponent ( channel . name + '.m3u8' ) , playList : this . apiUtil . createM3U8PlayListStr ( { host : host , isSecure : isSecure , name : channel . name , duration : 0 , baseUrl : `/api/streams/live/${ option . channelId . toString ( 10 ) }/m2ts?mode=${ option . mode }` , } ) , } ; } param streamId param isForce return public async stop ( streamId , isForce = false ) { await this . streamManageModel . stop ( streamId , isForce ) ; } return public async stopAll ( ) { await this . streamManageModel . stopAll ( ) ; } param streamId public keep ( streamId ) { this . streamManageModel . keep ( streamId ) ; } param isHalfWidth return public async getStreamInfos ( isHalfWidth ) { const infos = this . streamManageModel . getStreamInfos ( ) ; const items = [ ] ; const now = new Date ( ) . getTime ( ) ; for ( const info of infos ) { if ( info . info . type === 'LiveStream' || info . info . type === 'LiveHLS' ) { const item = { streamId : info . streamId , type : info . info . type , mode : info . info . mode , isEnable : info . info . isEnable , channelId : info . info . channelId , name : '' , startAt : 0 , endAt : 0 , } ; const program = await this . programDB . findChannelIdAndTime ( info . info . channelId , now ) ; if ( program !== null ) { item . name = isHalfWidth === true ? program . halfWidthName : program . name ; item . startAt = program . startAt ; item . endAt = program . endAt ; if ( program . description !== null && program . halfWidthDescription !== null ) { item . description = isHalfWidth === true ? program . halfWidthDescription : program . description ; } if ( program . extended !== null && program . halfWidthExtended !== null ) { item . extended = isHalfWidth === true ? program . halfWidthExtended : program . extended ; } if ( program . rawExtended !== null && program . rawHalfWidthExtended !== null ) { item . rawExtended = isHalfWidth === true ? JSON . parse ( program . rawHalfWidthExtended ) : JSON . parse ( program . rawExtended ) ; } } items . push ( item ) ; } else if ( info . info . type === 'RecordedStream' || info . info . type === 'RecordedHLS' ) { const item = { streamId : info . streamId , type : info . info . type , mode : info . info . mode , isEnable : info . info . isEnable , channelId : 0 , name : '' , startAt : 0 , endAt : 0 , viodeFileId : info . info . videoFileId , recordedId : 0 , } ; const videoFile = await this . videoFileDB . findId ( info . info . videoFileId ) ; if ( videoFile !== null ) { item . recordedId = videoFile . recordedId ; const recorded = await this . recordedDB . findId ( videoFile . recordedId ) ; if ( recorded !== null ) { item . channelId = recorded . channelId ; item . name = recorded . name ; item . startAt = recorded . startAt ; item . endAt = recorded . endAt ; if ( recorded . description !== null && recorded . halfWidthDescription !== null ) { item . description = isHalfWidth === true ? recorded . halfWidthDescription : recorded . description ; } if ( recorded . extended !== null && recorded . halfWidthExtended !== null ) { item . extended = isHalfWidth === true ? recorded . halfWidthExtended : recorded . extended ; } if ( recorded . rawExtended !== null && recorded . rawHalfWidthExtended !== null ) { item . rawExtended = isHalfWidth === true ? JSON . parse ( recorded . rawHalfWidthExtended ) : JSON . parse ( recorded . rawExtended ) ; } } } items . push ( item ) ; } else { throw new Error ( 'StreamInfoTypeError' ) ; } } return { items : items , } ; } }