Skip to content

Commit

Permalink
feat: support HLS media playback (#25174)
Browse files Browse the repository at this point in the history
  • Loading branch information
daibhin authored Sep 24, 2024
1 parent 83a77ef commit bfcf27e
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 2 deletions.
39 changes: 39 additions & 0 deletions frontend/src/scenes/session-recordings/player/rrweb/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Hls from 'hls.js'
import { EventType, eventWithTime, IncrementalSource } from 'rrweb'
import { playerConfig, ReplayPlugin } from 'rrweb/typings/types'

Expand Down Expand Up @@ -122,6 +123,44 @@ export const WindowTitlePlugin = (cb: (windowId: string, title: string) => void)
}
}

export const HLSPlayerPlugin: ReplayPlugin = {
onBuild: (node) => {
if (node && node.nodeName === 'VIDEO' && node.nodeType === 1) {
const videoEl = node as HTMLVideoElement
const hlsSrc = videoEl.getAttribute('hls-src')

if (videoEl && hlsSrc) {
if (Hls.isSupported()) {
const hls = new Hls()
hls.loadSource(hlsSrc)
hls.attachMedia(videoEl)

hls.on(Hls.Events.ERROR, (_, data) => {
if (data.fatal) {
switch (data.type) {
case Hls.ErrorTypes.NETWORK_ERROR:
hls.startLoad()
break
case Hls.ErrorTypes.MEDIA_ERROR:
hls.recoverMediaError()
break
// Unrecoverable error
default:
hls.destroy()
break
}
}
})
}
// HLS not supported natively but can play in Safari
else if (videoEl.canPlayType('application/vnd.apple.mpegurl')) {
videoEl.src = hlsSrc
}
}
}
},
}

const defaultStyleRules = `.ph-no-capture { background-image: ${PLACEHOLDER_SVG_DATA_IMAGE_URL} }`
// replaces a common rule in Shopify templates removed during capture
// fix tracked in https://github.com/rrweb-io/rrweb/pull/1322
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import { AvailableFeature, RecordingSegment, SessionPlayerData, SessionPlayerSta

import type { sessionRecordingsPlaylistLogicType } from '../playlist/sessionRecordingsPlaylistLogicType'
import { playerSettingsLogic } from './playerSettingsLogic'
import { COMMON_REPLAYER_CONFIG, CorsPlugin } from './rrweb'
import { COMMON_REPLAYER_CONFIG, CorsPlugin, HLSPlayerPlugin } from './rrweb'
import { CanvasReplayerPlugin } from './rrweb/canvas/canvas-plugin'
import type { sessionRecordingPlayerLogicType } from './sessionRecordingPlayerLogicType'
import { deleteRecording } from './utils/playerUtils'
Expand Down Expand Up @@ -596,7 +596,7 @@ export const sessionRecordingPlayerLogic = kea<sessionRecordingPlayerLogicType>(
return
}

const plugins: ReplayPlugin[] = []
const plugins: ReplayPlugin[] = [HLSPlayerPlugin]

// We don't want non-cloud products to talk to our proxy as it likely won't work, but we _do_ want local testing to work
if (values.preflight?.cloud || window.location.hostname === 'localhost') {
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@
"kea-test-utils": "^0.2.4",
"kea-waitfor": "^0.2.1",
"kea-window-values": "^3.0.0",
"hls.js": "^1.5.15",
"lodash.merge": "^4.6.2",
"maplibre-gl": "^3.5.1",
"md5": "^2.3.0",
Expand Down
7 changes: 7 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit bfcf27e

Please sign in to comment.