aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/tests/api/live/live-fast-restream.ts
blob: 4e30feaef23cf6db4546fbe81fdaf088d6162eb6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */

import { expect } from 'chai'
import { wait } from '@shared/core-utils'
import { HttpStatusCode, LiveVideoCreate, VideoPrivacy } from '@shared/models'
import {
  cleanupTests,
  createSingleServer,
  makeRawRequest,
  PeerTubeServer,
  setAccessTokensToServers,
  setDefaultVideoChannel,
  stopFfmpeg,
  waitJobs
} from '@shared/server-commands'

describe('Fast restream in live', function () {
  let server: PeerTubeServer

  async function createLiveWrapper (options: { permanent: boolean, replay: boolean }) {
    const attributes: LiveVideoCreate = {
      channelId: server.store.channel.id,
      privacy: VideoPrivacy.PUBLIC,
      name: 'my super live',
      saveReplay: options.replay,
      replaySettings: options.replay ? { privacy: VideoPrivacy.PUBLIC } : undefined,
      permanentLive: options.permanent
    }

    const { uuid } = await server.live.create({ fields: attributes })
    return uuid
  }

  async function fastRestreamWrapper ({ replay }: { replay: boolean }) {
    const liveVideoUUID = await createLiveWrapper({ permanent: true, replay })
    await waitJobs([ server ])

    const rtmpOptions = {
      videoId: liveVideoUUID,
      copyCodecs: true,
      fixtureName: 'video_short.mp4'
    }

    // Streaming session #1
    let ffmpegCommand = await server.live.sendRTMPStreamInVideo(rtmpOptions)
    await server.live.waitUntilPublished({ videoId: liveVideoUUID })

    const video = await server.videos.get({ id: liveVideoUUID })
    const session1PlaylistId = video.streamingPlaylists[0].id

    await stopFfmpeg(ffmpegCommand)
    await server.live.waitUntilWaiting({ videoId: liveVideoUUID })

    // Streaming session #2
    ffmpegCommand = await server.live.sendRTMPStreamInVideo(rtmpOptions)

    let hasNewPlaylist = false
    do {
      const video = await server.videos.get({ id: liveVideoUUID })
      hasNewPlaylist = video.streamingPlaylists.length === 1 && video.streamingPlaylists[0].id !== session1PlaylistId

      await wait(100)
    } while (!hasNewPlaylist)

    await server.live.waitUntilSegmentGeneration({
      server,
      videoUUID: liveVideoUUID,
      segment: 1,
      playlistNumber: 0,
      objectStorage: false
    })

    return { ffmpegCommand, liveVideoUUID }
  }

  async function ensureLastLiveWorks (liveId: string) {
    // Equivalent to PEERTUBE_TEST_CONSTANTS_VIDEO_LIVE_CLEANUP_DELAY
    for (let i = 0; i < 100; i++) {
      const video = await server.videos.get({ id: liveId })
      expect(video.streamingPlaylists).to.have.lengthOf(1)

      try {
        await server.live.getSegmentFile({ videoUUID: liveId, segment: 0, playlistNumber: 0 })
        await makeRawRequest({ url: video.streamingPlaylists[0].playlistUrl, expectedStatus: HttpStatusCode.OK_200 })
        await makeRawRequest({ url: video.streamingPlaylists[0].segmentsSha256Url, expectedStatus: HttpStatusCode.OK_200 })
      } catch (err) {
        // FIXME: try to debug error in CI "Unexpected end of JSON input"
        console.error(err)
        throw err
      }

      await wait(100)
    }
  }

  async function runTest (replay: boolean) {
    const { ffmpegCommand, liveVideoUUID } = await fastRestreamWrapper({ replay })

    // TODO: remove, we try to debug a test timeout failure here
    console.log('Ensuring last live works')

    await ensureLastLiveWorks(liveVideoUUID)

    await stopFfmpeg(ffmpegCommand)
    await server.live.waitUntilWaiting({ videoId: liveVideoUUID })

    // Wait for replays
    await waitJobs([ server ])

    const { total, data: sessions } = await server.live.listSessions({ videoId: liveVideoUUID })

    expect(total).to.equal(2)
    expect(sessions).to.have.lengthOf(2)

    for (const session of sessions) {
      expect(session.error).to.be.null

      if (replay) {
        expect(session.replayVideo).to.exist

        await server.videos.get({ id: session.replayVideo.uuid })
      } else {
        expect(session.replayVideo).to.not.exist
      }
    }
  }

  before(async function () {
    this.timeout(120000)

    const env = { PEERTUBE_TEST_CONSTANTS_VIDEO_LIVE_CLEANUP_DELAY: '10000' }
    server = await createSingleServer(1, {}, { env })

    // Get the access tokens
    await setAccessTokensToServers([ server ])
    await setDefaultVideoChannel([ server ])

    await server.config.enableMinimumTranscoding(false, true)
    await server.config.enableLive({ allowReplay: true, transcoding: true, resolutions: 'min' })
  })

  it('Should correctly fast restream in a permanent live with and without save replay', async function () {
    this.timeout(480000)

    // A test can take a long time, so prefer to run them in parallel
    await Promise.all([
      runTest(true),
      runTest(false)
    ])
  })

  after(async function () {
    await cleanupTests([ server ])
  })
})