mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-01-15 18:38:56 +01:00
Fix: temp fix for aac codec error by forcing aac encode #172, Change: Failed streams will close the stream and show error
This commit is contained in:
parent
8316a8c18b
commit
ac72ec1317
@ -194,6 +194,13 @@ export default {
|
|||||||
console.error('No Audio Ref')
|
console.error('No Audio Ref')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
streamError(streamId) {
|
||||||
|
if (this.stream && (this.stream.id === streamId || streamId === 'n/a')) {
|
||||||
|
this.terminateStream()
|
||||||
|
this.$store.commit('clearStreamAudiobook', this.stream.audiobook.id)
|
||||||
|
this.stream = null
|
||||||
|
}
|
||||||
|
},
|
||||||
sendStreamSync(syncData) {
|
sendStreamSync(syncData) {
|
||||||
var diff = syncData.currentTime - this.lastServerUpdateSentSeconds
|
var diff = syncData.currentTime - this.lastServerUpdateSentSeconds
|
||||||
if (Math.abs(diff) < 1 && !syncData.timeListened) {
|
if (Math.abs(diff) < 1 && !syncData.timeListened) {
|
||||||
|
@ -134,6 +134,10 @@ export default {
|
|||||||
streamReset(payload) {
|
streamReset(payload) {
|
||||||
if (this.$refs.streamContainer) this.$refs.streamContainer.streamReset(payload)
|
if (this.$refs.streamContainer) this.$refs.streamContainer.streamReset(payload)
|
||||||
},
|
},
|
||||||
|
streamError({ id, errorMessage }) {
|
||||||
|
this.$toast.error(`Stream Failed: ${errorMessage}`)
|
||||||
|
if (this.$refs.streamContainer) this.$refs.streamContainer.streamError(id)
|
||||||
|
},
|
||||||
audiobookAdded(audiobook) {
|
audiobookAdded(audiobook) {
|
||||||
this.$store.commit('audiobooks/addUpdate', audiobook)
|
this.$store.commit('audiobooks/addUpdate', audiobook)
|
||||||
},
|
},
|
||||||
@ -327,6 +331,7 @@ export default {
|
|||||||
this.socket.on('stream_progress', this.streamProgress)
|
this.socket.on('stream_progress', this.streamProgress)
|
||||||
this.socket.on('stream_ready', this.streamReady)
|
this.socket.on('stream_ready', this.streamReady)
|
||||||
this.socket.on('stream_reset', this.streamReset)
|
this.socket.on('stream_reset', this.streamReset)
|
||||||
|
this.socket.on('stream_error', this.streamError)
|
||||||
|
|
||||||
// Audiobook Listeners
|
// Audiobook Listeners
|
||||||
this.socket.on('audiobook_updated', this.audiobookUpdated)
|
this.socket.on('audiobook_updated', this.audiobookUpdated)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "audiobookshelf-client",
|
"name": "audiobookshelf-client",
|
||||||
"version": "1.6.16",
|
"version": "1.6.17",
|
||||||
"description": "Audiobook manager and player",
|
"description": "Audiobook manager and player",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "audiobookshelf",
|
"name": "audiobookshelf",
|
||||||
"version": "1.6.16",
|
"version": "1.6.17",
|
||||||
"description": "Self-hosted audiobook server for managing and playing audiobooks",
|
"description": "Self-hosted audiobook server for managing and playing audiobooks",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -28,8 +28,12 @@ class StreamManager {
|
|||||||
this.streams = this.streams.filter(s => s.id !== stream.id)
|
this.streams = this.streams.filter(s => s.id !== stream.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
async openStream(client, audiobook) {
|
async openStream(client, audiobook, transcodeOptions = {}) {
|
||||||
var stream = new Stream(this.StreamsPath, client, audiobook)
|
if (!client || !client.user) {
|
||||||
|
Logger.error('[StreamManager] Cannot open stream invalid client', client)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var stream = new Stream(this.StreamsPath, client, audiobook, transcodeOptions)
|
||||||
|
|
||||||
stream.on('closed', () => {
|
stream.on('closed', () => {
|
||||||
this.removeStream(stream)
|
this.removeStream(stream)
|
||||||
|
@ -10,13 +10,15 @@ const hlsPlaylistGenerator = require('../utils/hlsPlaylistGenerator')
|
|||||||
const UserListeningSession = require('./UserListeningSession')
|
const UserListeningSession = require('./UserListeningSession')
|
||||||
|
|
||||||
class Stream extends EventEmitter {
|
class Stream extends EventEmitter {
|
||||||
constructor(streamPath, client, audiobook) {
|
constructor(streamPath, client, audiobook, transcodeOptions = {}) {
|
||||||
super()
|
super()
|
||||||
|
|
||||||
this.id = (Date.now() + Math.trunc(Math.random() * 1000)).toString(36)
|
this.id = (Date.now() + Math.trunc(Math.random() * 1000)).toString(36)
|
||||||
this.client = client
|
this.client = client
|
||||||
this.audiobook = audiobook
|
this.audiobook = audiobook
|
||||||
|
|
||||||
|
this.transcodeOptions = transcodeOptions
|
||||||
|
|
||||||
this.segmentLength = 6
|
this.segmentLength = 6
|
||||||
this.maxSeekBackTime = 30
|
this.maxSeekBackTime = 30
|
||||||
this.streamPath = Path.join(streamPath, this.id)
|
this.streamPath = Path.join(streamPath, this.id)
|
||||||
@ -110,6 +112,14 @@ class Stream extends EventEmitter {
|
|||||||
return Number(prog.toFixed(3))
|
return Number(prog.toFixed(3))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get isAACEncodable() {
|
||||||
|
return ['mp4', 'm4a', 'm4b'].includes(this.tracksAudioFileType)
|
||||||
|
}
|
||||||
|
|
||||||
|
get transcodeForceAAC() {
|
||||||
|
return !!this.transcodeOptions.forceAAC
|
||||||
|
}
|
||||||
|
|
||||||
toJSON() {
|
toJSON() {
|
||||||
return {
|
return {
|
||||||
id: this.id,
|
id: this.id,
|
||||||
@ -314,8 +324,8 @@ class Stream extends EventEmitter {
|
|||||||
this.ffmpeg.inputOption('-noaccurate_seek')
|
this.ffmpeg.inputOption('-noaccurate_seek')
|
||||||
}
|
}
|
||||||
|
|
||||||
const logLevel = process.env.NODE_ENV === 'production' ? 'error' : 'error'
|
const logLevel = process.env.NODE_ENV === 'production' ? 'error' : 'warning'
|
||||||
const audioCodec = (this.hlsSegmentType === 'fmp4' || this.tracksAudioFileType === 'opus') ? 'aac' : 'copy'
|
const audioCodec = (this.hlsSegmentType === 'fmp4' || this.tracksAudioFileType === 'opus' || this.transcodeForceAAC) ? 'aac' : 'copy'
|
||||||
this.ffmpeg.addOption([
|
this.ffmpeg.addOption([
|
||||||
`-loglevel ${logLevel}`,
|
`-loglevel ${logLevel}`,
|
||||||
'-map 0:a',
|
'-map 0:a',
|
||||||
@ -349,11 +359,13 @@ class Stream extends EventEmitter {
|
|||||||
Logger.info('[INFO] FFMPEG transcoding started with command: ' + command)
|
Logger.info('[INFO] FFMPEG transcoding started with command: ' + command)
|
||||||
Logger.info('')
|
Logger.info('')
|
||||||
if (this.isResetting) {
|
if (this.isResetting) {
|
||||||
|
// AAC encode is much slower
|
||||||
|
const clearIsResettingTime = this.transcodeForceAAC ? 3000 : 500
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
Logger.info('[STREAM] Clearing isResetting')
|
Logger.info('[STREAM] Clearing isResetting')
|
||||||
this.isResetting = false
|
this.isResetting = false
|
||||||
this.startLoop()
|
this.startLoop()
|
||||||
}, 500)
|
}, clearIsResettingTime)
|
||||||
} else {
|
} else {
|
||||||
this.startLoop()
|
this.startLoop()
|
||||||
}
|
}
|
||||||
@ -368,10 +380,21 @@ class Stream extends EventEmitter {
|
|||||||
// This is an intentional SIGKILL
|
// This is an intentional SIGKILL
|
||||||
Logger.info('[FFMPEG] Transcode Killed')
|
Logger.info('[FFMPEG] Transcode Killed')
|
||||||
this.ffmpeg = null
|
this.ffmpeg = null
|
||||||
|
clearInterval(this.loop)
|
||||||
} else {
|
} else {
|
||||||
Logger.error('Ffmpeg Err', err.message)
|
Logger.error('Ffmpeg Err', '"' + err.message + '"')
|
||||||
|
|
||||||
|
// Temporary workaround for https://github.com/advplyr/audiobookshelf/issues/172
|
||||||
|
const aacErrorMsg = 'ffmpeg exited with code 1: Could not write header for output file #0 (incorrect codec parameters ?)'
|
||||||
|
if (audioCodec === 'copy' && this.isAACEncodable && err.message && err.message.startsWith(aacErrorMsg)) {
|
||||||
|
Logger.info(`[Stream] Re-attempting stream with AAC encode`)
|
||||||
|
this.transcodeOptions.forceAAC = true
|
||||||
|
this.reset(this.startTime)
|
||||||
|
} else {
|
||||||
|
// Close stream show error
|
||||||
|
this.close(err.message)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
clearInterval(this.loop)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
this.ffmpeg.on('end', (stdout, stderr) => {
|
this.ffmpeg.on('end', (stdout, stderr) => {
|
||||||
@ -392,7 +415,7 @@ class Stream extends EventEmitter {
|
|||||||
this.ffmpeg.run()
|
this.ffmpeg.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
async close() {
|
async close(errorMessage = null) {
|
||||||
clearInterval(this.loop)
|
clearInterval(this.loop)
|
||||||
|
|
||||||
Logger.info('Closing Stream', this.id)
|
Logger.info('Closing Stream', this.id)
|
||||||
@ -407,7 +430,8 @@ class Stream extends EventEmitter {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (this.socket) {
|
if (this.socket) {
|
||||||
this.socket.emit('stream_closed', this.id)
|
if (errorMessage) this.socket.emit('stream_error', { id: this.id, error: (errorMessage || '').trim() })
|
||||||
|
else this.socket.emit('stream_closed', this.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.emit('closed')
|
this.emit('closed')
|
||||||
|
Loading…
Reference in New Issue
Block a user