Correctly display broken muxing session
Can happen when we stream an audio stream only
This commit is contained in:
parent
ad801093b9
commit
543fbd1ffe
|
@ -45,7 +45,9 @@ export class LiveStreamInformationComponent {
|
|||
[LiveVideoError.FFMPEG_ERROR]: $localize`Server error`,
|
||||
[LiveVideoError.QUOTA_EXCEEDED]: $localize`Quota exceeded`,
|
||||
[LiveVideoError.RUNNER_JOB_CANCEL]: $localize`Runner job cancelled`,
|
||||
[LiveVideoError.RUNNER_JOB_ERROR]: $localize`Error in runner job`
|
||||
[LiveVideoError.RUNNER_JOB_ERROR]: $localize`Error in runner job`,
|
||||
[LiveVideoError.UNKNOWN_ERROR]: $localize`Unknown error`,
|
||||
[LiveVideoError.INVALID_INPUT_VIDEO_STREAM]: $localize`Invalid input video stream`
|
||||
}
|
||||
|
||||
return errors[session.error]
|
||||
|
|
|
@ -5,7 +5,9 @@ export const LiveVideoError = {
|
|||
FFMPEG_ERROR: 4,
|
||||
BLACKLISTED: 5,
|
||||
RUNNER_JOB_ERROR: 6,
|
||||
RUNNER_JOB_CANCEL: 7
|
||||
RUNNER_JOB_CANCEL: 7,
|
||||
UNKNOWN_ERROR: 8,
|
||||
INVALID_INPUT_VIDEO_STREAM: 9
|
||||
} as const
|
||||
|
||||
export type LiveVideoErrorType = typeof LiveVideoError[keyof typeof LiveVideoError]
|
||||
|
|
|
@ -187,7 +187,13 @@ class LiveManager {
|
|||
return this.getContext().sessions.has(sessionId)
|
||||
}
|
||||
|
||||
stopSessionOf (videoUUID: string, error: LiveVideoErrorType | null) {
|
||||
stopSessionOf (options: {
|
||||
videoUUID: string
|
||||
error: LiveVideoErrorType | null
|
||||
errorOnReplay?: boolean
|
||||
}) {
|
||||
const { videoUUID, error } = options
|
||||
|
||||
const sessionId = this.videoSessions.get(videoUUID)
|
||||
if (!sessionId) {
|
||||
logger.debug('No live session to stop for video %s', videoUUID, lTags(sessionId, videoUUID))
|
||||
|
@ -196,7 +202,7 @@ class LiveManager {
|
|||
|
||||
logger.info('Stopping live session of video %s', videoUUID, { error, ...lTags(sessionId, videoUUID) })
|
||||
|
||||
this.saveEndingSession(videoUUID, error)
|
||||
this.saveEndingSession(options)
|
||||
.catch(err => logger.error('Cannot save ending session.', { err, ...lTags(sessionId, videoUUID) }))
|
||||
|
||||
this.videoSessions.delete(videoUUID)
|
||||
|
@ -338,23 +344,23 @@ class LiveManager {
|
|||
localLTags
|
||||
)
|
||||
|
||||
this.stopSessionOf(videoUUID, LiveVideoError.BAD_SOCKET_HEALTH)
|
||||
this.stopSessionOf({ videoUUID, error: LiveVideoError.BAD_SOCKET_HEALTH })
|
||||
})
|
||||
|
||||
muxingSession.on('duration-exceeded', ({ videoUUID }) => {
|
||||
logger.info('Stopping session of %s: max duration exceeded.', videoUUID, localLTags)
|
||||
|
||||
this.stopSessionOf(videoUUID, LiveVideoError.DURATION_EXCEEDED)
|
||||
this.stopSessionOf({ videoUUID, error: LiveVideoError.DURATION_EXCEEDED })
|
||||
})
|
||||
|
||||
muxingSession.on('quota-exceeded', ({ videoUUID }) => {
|
||||
logger.info('Stopping session of %s: user quota exceeded.', videoUUID, localLTags)
|
||||
|
||||
this.stopSessionOf(videoUUID, LiveVideoError.QUOTA_EXCEEDED)
|
||||
this.stopSessionOf({ videoUUID, error: LiveVideoError.QUOTA_EXCEEDED })
|
||||
})
|
||||
|
||||
muxingSession.on('transcoding-error', ({ videoUUID }) => {
|
||||
this.stopSessionOf(videoUUID, LiveVideoError.FFMPEG_ERROR)
|
||||
this.stopSessionOf({ videoUUID, error: LiveVideoError.FFMPEG_ERROR })
|
||||
})
|
||||
|
||||
muxingSession.on('transcoding-end', ({ videoUUID }) => {
|
||||
|
@ -377,8 +383,15 @@ class LiveManager {
|
|||
muxingSession.runMuxing()
|
||||
.catch(err => {
|
||||
logger.error('Cannot run muxing.', { err, ...localLTags })
|
||||
this.abortSession(sessionId)
|
||||
this.videoSessions.delete(videoUUID)
|
||||
|
||||
this.muxingSessions.delete(sessionId)
|
||||
muxingSession.destroy()
|
||||
|
||||
this.stopSessionOf({
|
||||
videoUUID,
|
||||
error: err.liveVideoErrorCode || LiveVideoError.UNKNOWN_ERROR,
|
||||
errorOnReplay: true // Replay cannot be processed as muxing session failed directly
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -418,7 +431,7 @@ class LiveManager {
|
|||
|
||||
this.videoSessions.delete(videoUUID)
|
||||
|
||||
this.saveEndingSession(videoUUID, null)
|
||||
this.saveEndingSession({ videoUUID, error: null })
|
||||
.catch(err => logger.error('Cannot save ending session.', { err, ...lTags(sessionId) }))
|
||||
}
|
||||
|
||||
|
@ -536,13 +549,23 @@ class LiveManager {
|
|||
})
|
||||
}
|
||||
|
||||
private async saveEndingSession (videoUUID: string, error: LiveVideoErrorType | null) {
|
||||
private async saveEndingSession (options: {
|
||||
videoUUID: string
|
||||
error: LiveVideoErrorType | null
|
||||
errorOnReplay?: boolean
|
||||
}) {
|
||||
const { videoUUID, error, errorOnReplay } = options
|
||||
|
||||
const liveSession = await VideoLiveSessionModel.findCurrentSessionOf(videoUUID)
|
||||
if (!liveSession) return
|
||||
|
||||
liveSession.endDate = new Date()
|
||||
liveSession.error = error
|
||||
|
||||
if (errorOnReplay === true) {
|
||||
liveSession.endingProcessed = true
|
||||
}
|
||||
|
||||
return liveSession.save()
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ import { removeHLSFileObjectStorageByPath, storeHLSFileFromContent, storeHLSFile
|
|||
import { VideoFileModel } from '@server/models/video/video-file.js'
|
||||
import { VideoStreamingPlaylistModel } from '@server/models/video/video-streaming-playlist.js'
|
||||
import { MStreamingPlaylistVideo, MUserId, MVideoLiveVideo } from '@server/types/models/index.js'
|
||||
import { VideoStorage, VideoStreamingPlaylistType } from '@peertube/peertube-models'
|
||||
import { LiveVideoError, VideoStorage, VideoStreamingPlaylistType } from '@peertube/peertube-models'
|
||||
import {
|
||||
generateHLSMasterPlaylistFilename,
|
||||
generateHlsSha256SegmentsFilename,
|
||||
|
@ -490,10 +490,21 @@ class MuxingSession extends EventEmitter {
|
|||
inputLocalUrl: this.inputLocalUrl,
|
||||
inputPublicUrl: this.inputPublicUrl,
|
||||
|
||||
toTranscode: this.allResolutions.map(resolution => ({
|
||||
resolution,
|
||||
fps: computeOutputFPS({ inputFPS: this.fps, resolution })
|
||||
})),
|
||||
toTranscode: this.allResolutions.map(resolution => {
|
||||
let toTranscodeFPS: number
|
||||
|
||||
try {
|
||||
toTranscodeFPS = computeOutputFPS({ inputFPS: this.fps, resolution })
|
||||
} catch (err) {
|
||||
err.liveVideoErrorCode = LiveVideoError.INVALID_INPUT_VIDEO_STREAM
|
||||
throw err
|
||||
}
|
||||
|
||||
return {
|
||||
resolution,
|
||||
fps: toTranscodeFPS
|
||||
}
|
||||
}),
|
||||
|
||||
fps: this.fps,
|
||||
bitrate: this.bitrate,
|
||||
|
|
|
@ -165,7 +165,7 @@ export class LiveRTMPHLSTranscodingJobHandler extends AbstractJobHandler<CreateO
|
|||
cancelled: LiveVideoError.RUNNER_JOB_CANCEL
|
||||
}
|
||||
|
||||
LiveManager.Instance.stopSessionOf(privatePayload.videoUUID, errorType[type])
|
||||
LiveManager.Instance.stopSessionOf({ videoUUID: privatePayload.videoUUID, error: errorType[type] })
|
||||
|
||||
logger.info('Runner live RTMP to HLS job %s for video %s %s.', runnerJob.uuid, videoUUID, type, this.lTags(runnerJob.uuid, videoUUID))
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ async function blacklistVideo (videoInstance: MVideoAccountLight, options: Video
|
|||
}
|
||||
|
||||
if (videoInstance.isLive) {
|
||||
LiveManager.Instance.stopSessionOf(videoInstance.uuid, LiveVideoError.BLACKLISTED)
|
||||
LiveManager.Instance.stopSessionOf({ videoUUID: videoInstance.uuid, error: LiveVideoError.BLACKLISTED })
|
||||
}
|
||||
|
||||
Notifier.Instance.notifyOnVideoBlacklist(blacklist)
|
||||
|
|
|
@ -808,7 +808,7 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> {
|
|||
|
||||
logger.info('Stopping live of video %s after video deletion.', instance.uuid)
|
||||
|
||||
LiveManager.Instance.stopSessionOf(instance.uuid, null)
|
||||
LiveManager.Instance.stopSessionOf({ videoUUID: instance.uuid, error: null })
|
||||
}
|
||||
|
||||
@BeforeDestroy
|
||||
|
|
Loading…
Reference in New Issue