import { expect } from 'chai'
import { basename, join } from 'path'
-import { ffprobePromise, getVideoStream } from '@server/helpers/ffmpeg'
-import { checkLiveSegmentHash, checkResolutionsInMasterPlaylist, testImage } from '@server/tests/shared'
+import { SQLCommand, testImage, testLiveVideoResolutions } from '@server/tests/shared'
import { getAllFiles, wait } from '@shared/core-utils'
+import { ffprobePromise, getVideoStream } from '@shared/ffmpeg'
import {
HttpStatusCode,
LiveVideo,
doubleFollow,
killallServers,
LiveCommand,
+ makeGetRequest,
makeRawRequest,
PeerTubeServer,
sendRTMPStream,
commentsEnabled: false,
downloadEnabled: false,
saveReplay: true,
+ replaySettings: { privacy: VideoPrivacy.PUBLIC },
latencyMode: LiveVideoLatencyMode.SMALL_LATENCY,
privacy: VideoPrivacy.PUBLIC,
previewfile: 'video_short1-preview.webm.jpg',
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
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 })
}
})
}
expect(live.saveReplay).to.be.false
+ expect(live.replaySettings).to.not.exist
expect(live.latencyMode).to.equal(LiveVideoLatencyMode.DEFAULT)
}
})
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, playlistNumber: 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: {
before(async function () {
await updateConf([])
+
+ sqlCommandServer1 = new SQLCommand(servers[0])
})
it('Should enable transcoding without additional resolutions', async 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)
})
await waitUntilLivePublishedOnAllServers(servers, liveVideoId)
await waitJobs(servers)
- await testVideoResolutions(liveVideoId, resolutions.concat([ 720 ]))
+ await testLiveVideoResolutions({
+ originServer: servers[0],
+ sqlCommand: sqlCommandServer1,
+ 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 testLiveVideoResolutions({
+ originServer: servers[0],
+ sqlCommand: sqlCommandServer1,
+ servers,
+ liveVideoId,
+ resolutions,
+ objectStorage: false,
+ transcoded: true
+ })
await stopFfmpeg(ffmpegCommand)
await commands[0].waitUntilEnded({ videoId: liveVideoId })
}
const minBitrateLimits = {
- 720: 5500 * 1000,
+ 720: 4800 * 1000,
360: 1000 * 1000,
240: 550 * 1000
}
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')
if (resolution >= 720) {
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)
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 })
}
}
})
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 })
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)
await commands[0].waitUntilEnded({ videoId: liveVideoId })
expect(hlsFiles[0].resolution.id).to.equal(720)
})
+
+ after(async function () {
+ await sqlCommandServer1.cleanup()
+ })
})
describe('After a server restart', function () {
channelId: servers[0].store.channel.id,
privacy: VideoPrivacy.PUBLIC,
saveReplay: options.saveReplay,
+ replaySettings: options.saveReplay
+ ? { privacy: VideoPrivacy.PUBLIC }
+ : undefined,
permanentLive: options.permanent
}
commands[0].waitUntilPublished({ videoId: liveVideoReplayId })
])
- 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 })
+ 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 })