/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
-import 'mocha'
-import * as chai from 'chai'
+import { expect } from 'chai'
import { basename, join } from 'path'
import { ffprobePromise, getVideoStream } from '@server/helpers/ffmpeg'
-import { checkLiveCleanup, checkLiveSegmentHash, checkResolutionsInMasterPlaylist, testImage } from '@server/tests/shared'
-import { wait } from '@shared/core-utils'
+import { testImage, testVideoResolutions } from '@server/tests/shared'
+import { getAllFiles, wait } from '@shared/core-utils'
import {
HttpStatusCode,
LiveVideo,
waitUntilLivePublishedOnAllServers
} from '@shared/server-commands'
-const expect = chai.expect
-
describe('Test live', function () {
let servers: PeerTubeServer[] = []
let commands: LiveCommand[]
let vodVideoId: string
before(async function () {
- this.timeout(120000)
+ this.timeout(240000)
vodVideoId = (await servers[0].videos.quickUpload({ name: 'vod video' })).uuid
return uuid
}
- async function testVideoResolutions (liveVideoId: string, resolutions: number[]) {
- for (const server of servers) {
- const { data } = await server.videos.list()
- expect(data.find(v => v.uuid === liveVideoId)).to.exist
-
- const video = await server.videos.get({ id: liveVideoId })
-
- expect(video.streamingPlaylists).to.have.lengthOf(1)
-
- const hlsPlaylist = video.streamingPlaylists.find(s => s.type === VideoStreamingPlaylistType.HLS)
- expect(hlsPlaylist).to.exist
-
- // Only finite files are displayed
- expect(hlsPlaylist.files).to.have.lengthOf(0)
-
- await checkResolutionsInMasterPlaylist({ server, playlistUrl: hlsPlaylist.playlistUrl, resolutions })
-
- for (let i = 0; i < resolutions.length; i++) {
- const segmentNum = 3
- const segmentName = `${i}-00000${segmentNum}.ts`
- await commands[0].waitUntilSegmentGeneration({ videoUUID: video.uuid, resolution: i, segment: segmentNum })
-
- const subPlaylist = await servers[0].streamingPlaylists.get({
- url: `${servers[0].url}/static/streaming-playlists/hls/${video.uuid}/${i}.m3u8`
- })
-
- expect(subPlaylist).to.contain(segmentName)
-
- const baseUrlAndPath = servers[0].url + '/static/streaming-playlists/hls'
- await checkLiveSegmentHash({
- server,
- baseUrlSegment: baseUrlAndPath,
- videoUUID: video.uuid,
- segmentName,
- hlsPlaylist
- })
- }
- }
- }
-
function updateConf (resolutions: number[]) {
return servers[0].config.updateCustomSubConfig({
newConfig: {
await waitUntilLivePublishedOnAllServers(servers, liveVideoId)
await waitJobs(servers)
- await testVideoResolutions(liveVideoId, [ 720 ])
+ await testVideoResolutions({
+ originServer: servers[0],
+ servers,
+ liveVideoId,
+ resolutions: [ 720 ],
+ objectStorage: false,
+ transcoded: true
+ })
+
+ await stopFfmpeg(ffmpegCommand)
+ })
+
+ it('Should transcode audio only RTMP stream', async function () {
+ this.timeout(120000)
+
+ liveVideoId = await createLiveWrapper(false)
+
+ const ffmpegCommand = await commands[0].sendRTMPStreamInVideo({ videoId: liveVideoId, fixtureName: 'video_short_no_audio.mp4' })
+ await waitUntilLivePublishedOnAllServers(servers, liveVideoId)
+ await waitJobs(servers)
await stopFfmpeg(ffmpegCommand)
})
await waitUntilLivePublishedOnAllServers(servers, liveVideoId)
await waitJobs(servers)
- await testVideoResolutions(liveVideoId, resolutions)
+ await testVideoResolutions({
+ originServer: servers[0],
+ servers,
+ liveVideoId,
+ resolutions: resolutions.concat([ 720 ]),
+ objectStorage: false,
+ transcoded: true
+ })
await stopFfmpeg(ffmpegCommand)
})
await waitUntilLivePublishedOnAllServers(servers, liveVideoId)
await waitJobs(servers)
- await testVideoResolutions(liveVideoId, resolutions)
+ await testVideoResolutions({
+ originServer: servers[0],
+ servers,
+ liveVideoId,
+ resolutions,
+ objectStorage: false,
+ transcoded: true
+ })
await stopFfmpeg(ffmpegCommand)
await commands[0].waitUntilEnded({ videoId: liveVideoId })
}
const minBitrateLimits = {
- 720: 5500 * 1000,
+ 720: 5000 * 1000,
360: 1000 * 1000,
240: 550 * 1000
}
expect(file.size).to.be.greaterThan(1)
if (resolution >= 720) {
- expect(file.fps).to.be.approximately(60, 2)
+ expect(file.fps).to.be.approximately(60, 10)
} else {
- expect(file.fps).to.be.approximately(30, 2)
+ expect(file.fps).to.be.approximately(30, 3)
}
const filename = basename(file.fileUrl)
}
})
- it('Should correctly have cleaned up the live files', async function () {
- this.timeout(30000)
+ it('Should not generate an upper resolution than original file', async function () {
+ this.timeout(400_000)
+
+ const resolutions = [ 240, 480 ]
+ await updateConf(resolutions)
- await checkLiveCleanup(servers[0], liveVideoId, [ 240, 360, 720 ])
+ await servers[0].config.updateExistingSubConfig({
+ newConfig: {
+ live: {
+ transcoding: {
+ alwaysTranscodeOriginalResolution: false
+ }
+ }
+ }
+ })
+
+ liveVideoId = await createLiveWrapper(true)
+
+ const ffmpegCommand = await commands[0].sendRTMPStreamInVideo({ videoId: liveVideoId, fixtureName: 'video_short2.webm' })
+ await waitUntilLivePublishedOnAllServers(servers, liveVideoId)
+ await waitJobs(servers)
+
+ await testVideoResolutions({
+ originServer: servers[0],
+ servers,
+ liveVideoId,
+ resolutions,
+ objectStorage: false,
+ transcoded: true
+ })
+
+ await stopFfmpeg(ffmpegCommand)
+ await commands[0].waitUntilEnded({ videoId: liveVideoId })
+
+ await waitJobs(servers)
+
+ await waitUntilLivePublishedOnAllServers(servers, liveVideoId)
+
+ const video = await servers[0].videos.get({ id: liveVideoId })
+ const hlsFiles = video.streamingPlaylists[0].files
+
+ expect(video.files).to.have.lengthOf(0)
+ expect(hlsFiles).to.have.lengthOf(resolutions.length)
+
+ // eslint-disable-next-line @typescript-eslint/require-array-sort-compare
+ expect(getAllFiles(video).map(f => f.resolution.id).sort()).to.deep.equal(resolutions)
+ })
+
+ it('Should only keep the original resolution if all resolutions are disabled', async function () {
+ this.timeout(600_000)
+
+ await updateConf([])
+ liveVideoId = await createLiveWrapper(true)
+
+ const ffmpegCommand = await commands[0].sendRTMPStreamInVideo({ videoId: liveVideoId, fixtureName: 'video_short2.webm' })
+ await waitUntilLivePublishedOnAllServers(servers, liveVideoId)
+ await waitJobs(servers)
+
+ await testVideoResolutions({
+ originServer: servers[0],
+ servers,
+ liveVideoId,
+ resolutions: [ 720 ],
+ objectStorage: false,
+ transcoded: true
+ })
+
+ await stopFfmpeg(ffmpegCommand)
+ await commands[0].waitUntilEnded({ videoId: liveVideoId })
+
+ await waitJobs(servers)
+
+ await waitUntilLivePublishedOnAllServers(servers, liveVideoId)
+
+ const video = await servers[0].videos.get({ id: liveVideoId })
+ const hlsFiles = video.streamingPlaylists[0].files
+
+ expect(video.files).to.have.lengthOf(0)
+ expect(hlsFiles).to.have.lengthOf(1)
+
+ expect(hlsFiles[0].resolution.id).to.equal(720)
})
})
let permanentLiveReplayName: string
+ let beforeServerRestart: Date
+
async function createLiveWrapper (options: { saveReplay: boolean, permanent: boolean }) {
const liveAttributes: LiveVideoCreate = {
name: 'live video',
}
before(async function () {
- this.timeout(160000)
+ this.timeout(600_000)
liveVideoId = await createLiveWrapper({ saveReplay: false, permanent: false })
liveVideoReplayId = await createLiveWrapper({ saveReplay: true, permanent: false })
commands[0].waitUntilPublished({ videoId: liveVideoReplayId })
])
- await commands[0].waitUntilSegmentGeneration({ videoUUID: liveVideoId, resolution: 0, segment: 2 })
- await commands[0].waitUntilSegmentGeneration({ videoUUID: liveVideoReplayId, resolution: 0, segment: 2 })
- await commands[0].waitUntilSegmentGeneration({ videoUUID: permanentLiveVideoReplayId, resolution: 0, segment: 2 })
+ await commands[0].waitUntilSegmentGeneration({ videoUUID: liveVideoId, playlistNumber: 0, segment: 2 })
+ await commands[0].waitUntilSegmentGeneration({ videoUUID: liveVideoReplayId, playlistNumber: 0, segment: 2 })
+ await commands[0].waitUntilSegmentGeneration({ videoUUID: permanentLiveVideoReplayId, playlistNumber: 0, segment: 2 })
{
const video = await servers[0].videos.get({ id: permanentLiveVideoReplayId })
}
await killallServers([ servers[0] ])
+
+ beforeServerRestart = new Date()
await servers[0].run()
await wait(5000)
})
it('Should save a non permanent live replay', async function () {
- this.timeout(120000)
+ this.timeout(240000)
await commands[0].waitUntilPublished({ videoId: liveVideoReplayId })
+
+ const session = await commands[0].getReplaySession({ videoId: liveVideoReplayId })
+ expect(session.endDate).to.exist
+ expect(new Date(session.endDate)).to.be.above(beforeServerRestart)
})
it('Should have saved a permanent live replay', async function () {