X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=server%2Ftests%2Fapi%2Flive%2Flive.ts;h=f9b0d257bc846c9863663e6b8dbef143358afb13;hb=a687879e94fa5d3ecdd76bec3d94d0e1698ee913;hp=c497f7840afec94f2e1cda43ea04952c7515e919;hpb=3cb60ca19eba97738342a10e15d5e5a916e2e690;p=github%2FChocobozzz%2FPeerTube.git diff --git a/server/tests/api/live/live.ts b/server/tests/api/live/live.ts index c497f7840..f9b0d257b 100644 --- a/server/tests/api/live/live.ts +++ b/server/tests/api/live/live.ts @@ -1,11 +1,10 @@ /* 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 { SQLCommand, testImage, testLiveVideoResolutions } from '@server/tests/shared' +import { getAllFiles, wait } from '@shared/core-utils' +import { ffprobePromise, getVideoStream } from '@shared/ffmpeg' import { HttpStatusCode, LiveVideo, @@ -22,6 +21,7 @@ import { doubleFollow, killallServers, LiveCommand, + makeGetRequest, makeRawRequest, PeerTubeServer, sendRTMPStream, @@ -33,8 +33,6 @@ import { waitUntilLivePublishedOnAllServers } from '@shared/server-commands' -const expect = chai.expect - describe('Test live', function () { let servers: PeerTubeServer[] = [] let commands: LiveCommand[] @@ -89,6 +87,7 @@ describe('Test live', function () { commentsEnabled: false, downloadEnabled: false, saveReplay: true, + replaySettings: { privacy: VideoPrivacy.PUBLIC }, latencyMode: LiveVideoLatencyMode.SMALL_LATENCY, privacy: VideoPrivacy.PUBLIC, previewfile: 'video_short1-preview.webm.jpg', @@ -130,6 +129,9 @@ describe('Test live', function () { if (server.url === servers[0].url) { expect(live.rtmpUrl).to.equal('rtmp://' + server.hostname + ':' + servers[0].rtmpPort + '/live') expect(live.streamKey).to.not.be.empty + + expect(live.replaySettings).to.exist + expect(live.replaySettings.privacy).to.equal(VideoPrivacy.PUBLIC) } else { expect(live.rtmpUrl).to.not.exist expect(live.streamKey).to.not.exist @@ -160,8 +162,8 @@ describe('Test live', function () { expect(video.privacy.id).to.equal(VideoPrivacy.UNLISTED) expect(video.nsfw).to.be.true - await makeRawRequest(server.url + video.thumbnailPath, HttpStatusCode.OK_200) - await makeRawRequest(server.url + video.previewPath, HttpStatusCode.OK_200) + await makeGetRequest({ url: server.url, path: video.thumbnailPath, expectedStatus: HttpStatusCode.OK_200 }) + await makeGetRequest({ url: server.url, path: video.previewPath, expectedStatus: HttpStatusCode.OK_200 }) } }) @@ -198,6 +200,7 @@ describe('Test live', function () { } expect(live.saveReplay).to.be.false + expect(live.replaySettings).to.not.exist expect(live.latencyMode).to.equal(LiveVideoLatencyMode.DEFAULT) } }) @@ -223,7 +226,7 @@ describe('Test live', function () { let vodVideoId: string before(async function () { - this.timeout(120000) + this.timeout(240000) vodVideoId = (await servers[0].videos.quickUpload({ name: 'vod video' })).uuid @@ -362,59 +365,23 @@ describe('Test live', function () { describe('Live transcoding', function () { let liveVideoId: string + let sqlCommandServer1: SQLCommand async function createLiveWrapper (saveReplay: boolean) { const liveAttributes = { name: 'live video', channelId: servers[0].store.channel.id, privacy: VideoPrivacy.PUBLIC, - saveReplay + saveReplay, + replaySettings: saveReplay + ? { privacy: VideoPrivacy.PUBLIC } + : undefined } const { uuid } = await commands[0].create({ fields: liveAttributes }) 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: { @@ -441,6 +408,8 @@ describe('Test live', function () { before(async function () { await updateConf([]) + + sqlCommandServer1 = new SQLCommand(servers[0]) }) it('Should enable transcoding without additional resolutions', async function () { @@ -452,7 +421,27 @@ describe('Test live', function () { await waitUntilLivePublishedOnAllServers(servers, liveVideoId) await waitJobs(servers) - await testVideoResolutions(liveVideoId, [ 720 ]) + await testLiveVideoResolutions({ + originServer: servers[0], + sqlCommand: sqlCommandServer1, + 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) }) @@ -468,7 +457,15 @@ describe('Test live', function () { await waitUntilLivePublishedOnAllServers(servers, liveVideoId) await waitJobs(servers) - await testVideoResolutions(liveVideoId, resolutions) + await testLiveVideoResolutions({ + originServer: servers[0], + sqlCommand: sqlCommandServer1, + servers, + liveVideoId, + resolutions: resolutions.concat([ 720 ]), + objectStorage: false, + transcoded: true + }) await stopFfmpeg(ffmpegCommand) }) @@ -513,7 +510,15 @@ describe('Test live', function () { await waitUntilLivePublishedOnAllServers(servers, liveVideoId) await waitJobs(servers) - await testVideoResolutions(liveVideoId, resolutions) + await testLiveVideoResolutions({ + originServer: servers[0], + sqlCommand: sqlCommandServer1, + servers, + liveVideoId, + resolutions, + objectStorage: false, + transcoded: true + }) await stopFfmpeg(ffmpegCommand) await commands[0].waitUntilEnded({ videoId: liveVideoId }) @@ -529,7 +534,7 @@ describe('Test live', function () { } const minBitrateLimits = { - 720: 5500 * 1000, + 720: 4800 * 1000, 360: 1000 * 1000, 240: 550 * 1000 } @@ -542,8 +547,8 @@ describe('Test live', function () { expect(video.files).to.have.lengthOf(0) const hlsPlaylist = video.streamingPlaylists.find(s => s.type === VideoStreamingPlaylistType.HLS) - await makeRawRequest(hlsPlaylist.playlistUrl, HttpStatusCode.OK_200) - await makeRawRequest(hlsPlaylist.segmentsSha256Url, HttpStatusCode.OK_200) + await makeRawRequest({ url: hlsPlaylist.playlistUrl, expectedStatus: HttpStatusCode.OK_200 }) + await makeRawRequest({ url: hlsPlaylist.segmentsSha256Url, expectedStatus: HttpStatusCode.OK_200 }) // We should have generated random filenames expect(basename(hlsPlaylist.playlistUrl)).to.not.equal('master.m3u8') @@ -558,9 +563,9 @@ describe('Test live', function () { 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) @@ -574,16 +579,99 @@ describe('Test live', function () { expect(probe.format.bit_rate).to.be.below(maxBitrateLimits[videoStream.height]) expect(probe.format.bit_rate).to.be.at.least(minBitrateLimits[videoStream.height]) - await makeRawRequest(file.torrentUrl, HttpStatusCode.OK_200) - await makeRawRequest(file.fileUrl, HttpStatusCode.OK_200) + await makeRawRequest({ url: file.torrentUrl, expectedStatus: HttpStatusCode.OK_200 }) + await makeRawRequest({ url: file.fileUrl, expectedStatus: HttpStatusCode.OK_200 }) } } }) - 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 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 testLiveVideoResolutions({ + originServer: servers[0], + sqlCommand: sqlCommandServer1, + 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 checkLiveCleanup(servers[0], liveVideoId, [ 240, 360, 720 ]) + 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 testLiveVideoResolutions({ + originServer: servers[0], + sqlCommand: sqlCommandServer1, + 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) + }) + + after(async function () { + await sqlCommandServer1.cleanup() }) }) @@ -602,6 +690,9 @@ describe('Test live', function () { channelId: servers[0].store.channel.id, privacy: VideoPrivacy.PUBLIC, saveReplay: options.saveReplay, + replaySettings: options.saveReplay + ? { privacy: VideoPrivacy.PUBLIC } + : undefined, permanentLive: options.permanent } @@ -610,7 +701,7 @@ describe('Test live', function () { } before(async function () { - this.timeout(160000) + this.timeout(600_000) liveVideoId = await createLiveWrapper({ saveReplay: false, permanent: false }) liveVideoReplayId = await createLiveWrapper({ saveReplay: true, permanent: false }) @@ -628,9 +719,15 @@ describe('Test live', function () { 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 }) + for (const videoUUID of [ liveVideoId, liveVideoReplayId, permanentLiveVideoReplayId ]) { + await commands[0].waitUntilSegmentGeneration({ + server: servers[0], + videoUUID, + playlistNumber: 0, + segment: 2, + objectStorage: false + }) + } { const video = await servers[0].videos.get({ id: permanentLiveVideoReplayId })