mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-08-02 01:05:25 +02:00
Adding audio playback speed control, updating volume control UI, fix stream play for small streams
This commit is contained in:
parent
4bcb346365
commit
be7e2576f1
13 changed files with 192 additions and 211 deletions
|
@ -28,14 +28,11 @@ class HlsController {
|
|||
|
||||
async streamFileRequest(req, res) {
|
||||
var streamId = req.params.stream
|
||||
|
||||
// Logger.info('Got hls request', streamId, req.params.file)
|
||||
|
||||
var fullFilePath = Path.join(this.MetadataPath, streamId, req.params.file)
|
||||
|
||||
var exists = await fs.pathExists(fullFilePath)
|
||||
if (!exists) {
|
||||
Logger.error('File path does not exist', fullFilePath)
|
||||
Logger.warn('File path does not exist', fullFilePath)
|
||||
|
||||
var fileExt = Path.extname(req.params.file)
|
||||
if (fileExt === '.ts') {
|
||||
|
@ -52,36 +49,16 @@ class HlsController {
|
|||
} else {
|
||||
var startTimeForReset = await stream.checkSegmentNumberRequest(segNum)
|
||||
if (startTimeForReset) {
|
||||
// HLS.js should request the file again]
|
||||
// HLS.js will restart the stream at the new time
|
||||
Logger.info(`[HLS-CONTROLLER] Resetting Stream - notify client @${startTimeForReset}s`)
|
||||
this.emitter('stream_reset', {
|
||||
startTime: startTimeForReset,
|
||||
streamId: stream.id
|
||||
})
|
||||
return res.sendStatus(500)
|
||||
// await new Promise((resolve) => {
|
||||
// setTimeout(() => {
|
||||
// console.log('Waited 4 seconds')
|
||||
// resolve()
|
||||
// }, 4000)
|
||||
// })
|
||||
|
||||
// exists = await fs.pathExists(fullFilePath)
|
||||
// if (!exists) {
|
||||
// console.error('Still does not exist')
|
||||
// return res.sendStatus(404)
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
// await new Promise(resolve => setTimeout(resolve, 500))
|
||||
// exists = await fs.pathExists(fullFilePath)
|
||||
// Logger.info('Waited', exists)
|
||||
// if (!exists) {
|
||||
// Logger.error('still does not exist', fullFilePath)
|
||||
// return res.sendStatus(404)
|
||||
// }
|
||||
}
|
||||
// Logger.info('Sending file', fullFilePath)
|
||||
res.sendFile(fullFilePath)
|
||||
|
|
|
@ -130,7 +130,6 @@ class Server {
|
|||
res.sendStatus(200)
|
||||
})
|
||||
|
||||
app.post('/stream', (req, res) => this.streamManager.openStreamRequest(req, res))
|
||||
app.post('/login', (req, res) => this.auth.login(req, res))
|
||||
app.post('/logout', this.logout.bind(this))
|
||||
app.get('/ping', (req, res) => {
|
||||
|
@ -165,7 +164,6 @@ class Server {
|
|||
socket.on('close_stream', () => this.streamManager.closeStreamRequest(socket))
|
||||
socket.on('stream_update', (payload) => this.streamManager.streamUpdate(socket, payload))
|
||||
socket.on('test', () => {
|
||||
console.log('Test Request from', socket.id)
|
||||
socket.emit('test_received', socket.id)
|
||||
})
|
||||
|
||||
|
|
142
server/Stream.js
142
server/Stream.js
|
@ -296,144 +296,12 @@ class Stream extends EventEmitter {
|
|||
|
||||
this.ffmpeg.on('end', (stdout, stderr) => {
|
||||
Logger.info('[FFMPEG] Transcoding ended')
|
||||
this.isTranscodeComplete = true
|
||||
this.ffmpeg = null
|
||||
})
|
||||
|
||||
this.ffmpeg.run()
|
||||
}
|
||||
|
||||
async startConcat() {
|
||||
Logger.info(`[STREAM] START STREAM - Num Segments: ${this.numSegments}`)
|
||||
|
||||
|
||||
var concatOutput = null
|
||||
if (this.tracks.length > 1) {
|
||||
var start = Date.now()
|
||||
await new Promise(async (resolve) => {
|
||||
Logger.info('Concatenating here', this.tracks.length)
|
||||
|
||||
this.ffmpeg = Ffmpeg()
|
||||
var trackExt = this.tracks[0].ext
|
||||
concatOutput = Path.join(this.streamPath, `concat${trackExt}`)
|
||||
Logger.info('Concat OUTPUT', concatOutput)
|
||||
var trackPaths = this.tracks.map(t => {
|
||||
var line = 'file ' + this.escapeSingleQuotes(t.fullPath) + '\n' + `duration ${t.duration}`
|
||||
return line
|
||||
})
|
||||
var inputstr = trackPaths.join('\n\n')
|
||||
await fs.writeFile(this.concatFilesPath, inputstr)
|
||||
this.ffmpeg.addInput(this.concatFilesPath)
|
||||
this.ffmpeg.inputFormat('concat')
|
||||
this.ffmpeg.inputOption('-safe 0')
|
||||
this.ffmpeg.addOption([
|
||||
'-loglevel warning',
|
||||
'-map 0:a',
|
||||
'-c:a copy'
|
||||
])
|
||||
this.ffmpeg.output(concatOutput)
|
||||
|
||||
this.ffmpeg.on('start', (command) => {
|
||||
Logger.info('[CONCAT] FFMPEG transcoding started with command: ' + command)
|
||||
})
|
||||
this.ffmpeg.on('error', (err, stdout, stderr) => {
|
||||
Logger.info('[CONCAT] ERROR', err, stderr)
|
||||
})
|
||||
|
||||
this.ffmpeg.on('end', (stdout, stderr) => {
|
||||
Logger.info('[CONCAT] Concat is done')
|
||||
resolve()
|
||||
})
|
||||
this.ffmpeg.run()
|
||||
})
|
||||
var elapsed = ((Date.now() - start) / 1000).toFixed(1)
|
||||
Logger.info(`[CONCAT] Final elapsed is ${elapsed}s`)
|
||||
} else {
|
||||
concatOutput = this.tracks[0].fullPath
|
||||
}
|
||||
|
||||
|
||||
this.ffmpeg = Ffmpeg()
|
||||
|
||||
// var currTrackEnd = 0
|
||||
// var startingTrack = this.tracks.find(t => {
|
||||
// currTrackEnd += t.duration
|
||||
// return this.startTime < currTrackEnd
|
||||
// })
|
||||
// var trackStartTime = currTrackEnd - startingTrack.duration
|
||||
// var currInpoint = this.startTime - trackStartTime
|
||||
|
||||
// var tracksToInclude = this.tracks.filter(t => t.index >= startingTrack.index)
|
||||
|
||||
// var trackPaths = tracksToInclude.map(t => {
|
||||
// var line = 'file ' + this.escapeSingleQuotes(t.fullPath) + '\n' + `duration ${t.duration}`
|
||||
// if (t.index === startingTrack.index) {
|
||||
// line += `\ninpoint ${currInpoint}`
|
||||
// }
|
||||
// return line
|
||||
// })
|
||||
// var inputstr = trackPaths.join('\n\n')
|
||||
// await fs.writeFile(this.concatFilesPath, inputstr)
|
||||
|
||||
this.ffmpeg.addInput(concatOutput)
|
||||
// this.ffmpeg.inputFormat('concat')
|
||||
// this.ffmpeg.inputOption('-safe 0')
|
||||
|
||||
if (this.startTime > 0) {
|
||||
Logger.info(`[STREAM] Starting Stream at startTime ${secondsToTimestamp(this.startTime)} and Segment #${this.segmentStartNumber}`)
|
||||
this.ffmpeg.inputOption(`-ss ${this.startTime}`)
|
||||
this.ffmpeg.inputOption('-noaccurate_seek')
|
||||
}
|
||||
|
||||
this.ffmpeg.addOption([
|
||||
'-loglevel warning',
|
||||
'-map 0:a',
|
||||
'-c:a copy'
|
||||
])
|
||||
this.ffmpeg.addOption([
|
||||
'-f hls',
|
||||
"-copyts",
|
||||
"-avoid_negative_ts disabled",
|
||||
"-max_delay 5000000",
|
||||
"-max_muxing_queue_size 2048",
|
||||
`-hls_time 6`,
|
||||
"-hls_segment_type mpegts",
|
||||
`-start_number ${this.segmentStartNumber}`,
|
||||
"-hls_playlist_type vod",
|
||||
"-hls_list_size 0",
|
||||
"-hls_allow_cache 0"
|
||||
])
|
||||
var segmentFilename = Path.join(this.streamPath, this.segmentBasename)
|
||||
this.ffmpeg.addOption(`-hls_segment_filename ${segmentFilename}`)
|
||||
this.ffmpeg.output(this.playlistPath)
|
||||
|
||||
this.ffmpeg.on('start', (command) => {
|
||||
Logger.info('[INFO] FFMPEG transcoding started with command: ' + command)
|
||||
if (this.isResetting) {
|
||||
setTimeout(() => {
|
||||
Logger.info('[STREAM] Clearing isResetting')
|
||||
this.isResetting = false
|
||||
}, 500)
|
||||
// For very small fast load
|
||||
if (!this.isClientInitialized) {
|
||||
this.isClientInitialized = true
|
||||
Logger.info(`[STREAM] ${this.id} notifying client that stream is ready`)
|
||||
this.socket.emit('stream_open', this.toJSON())
|
||||
}
|
||||
this.startLoop()
|
||||
})
|
||||
|
||||
this.ffmpeg.on('stderr', (stdErrline) => {
|
||||
Logger.info(stdErrline)
|
||||
})
|
||||
|
||||
this.ffmpeg.on('error', (err, stdout, stderr) => {
|
||||
if (err.message && err.message.includes('SIGKILL')) {
|
||||
// This is an intentional SIGKILL
|
||||
Logger.info('[FFMPEG] Transcode Killed')
|
||||
this.ffmpeg = null
|
||||
} else {
|
||||
Logger.error('Ffmpeg Err', err.message)
|
||||
}
|
||||
})
|
||||
|
||||
this.ffmpeg.on('end', (stdout, stderr) => {
|
||||
Logger.info('[FFMPEG] Transcoding ended')
|
||||
this.isTranscodeComplete = true
|
||||
this.ffmpeg = null
|
||||
})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue