diff --git a/package.json b/package.json
index 25c59b8f..6bb4595a 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "red5pro-html-sdk-testbed",
- "version": "15.2.0",
+ "version": "15.3.0",
"description": "Testbed examples for Red5 Pro HTML SDK",
"main": "src/js/index.js",
"repository": {
diff --git a/src/page/sm-test/messageChannelStreamManagerProxy/index.html b/src/page/sm-test/messageChannelStreamManagerProxy/index.html
new file mode 100644
index 00000000..d8a25ece
--- /dev/null
+++ b/src/page/sm-test/messageChannelStreamManagerProxy/index.html
@@ -0,0 +1,75 @@
+
+{{> license}}
+
+
+ {{> meta title='Message Channel Stream Manager Proxy'}}
+ {{> header-scripts}}
+ {{> header-stylesheets}}
+
+
+
+
+
+ {{> top-bar }}
+
+ {{> settings-link}}
+ {{> sm-proxy-notification}}
+ {{> test-info testTitle='Message Channel Stream Manager Proxy'}}
+
+
+
+ Data Channel Name:
+
+
+
+ Open Message Channel
+
+
+ {{> status-field-message-channel}}
+
+
+
+ Message:
+
+
+
+ Clicking the button below a message will be sent to all other connected Message Channel clients.
+
+
Click to send message.
+
+
+
+ Clicking the button below will grab a snippet of the audio of the stream and send as an ArrayBuffer over the Message Channel.
+
+
Click to send Audio Snippet.
+
+
+
+
+
+
+ {{> footer}}
+ {{> body-scripts}}
+
+
+
diff --git a/src/page/sm-test/messageChannelStreamManagerProxy/index.js b/src/page/sm-test/messageChannelStreamManagerProxy/index.js
new file mode 100644
index 00000000..5b8e8b9f
--- /dev/null
+++ b/src/page/sm-test/messageChannelStreamManagerProxy/index.js
@@ -0,0 +1,372 @@
+/*
+Copyright © 2015 Infrared5, Inc. All rights reserved.
+
+The accompanying code comprising examples for use solely in conjunction with Red5 Pro (the "Example Code")
+is licensed to you by Infrared5 Inc. in consideration of your agreement to the following
+license terms and conditions. Access, use, modification, or redistribution of the accompanying
+code constitutes your acceptance of the following license terms and conditions.
+
+Permission is hereby granted, free of charge, to you to use the Example Code and associated documentation
+files (collectively, the "Software") without restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
+persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The Software shall be used solely in conjunction with Red5 Pro. Red5 Pro is licensed under a separate end
+user license agreement (the "EULA"), which must be executed with Infrared5, Inc.
+An example of the EULA can be found on our website at: https://account.red5.net/assets/LICENSE.txt.
+
+The above copyright notice and this license shall be included in all copies or portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL INFRARED5, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+;((window, red5prosdk) => {
+
+ const configuration = (function () {
+ var conf = sessionStorage.getItem('r5proTestBed')
+ try {
+ return JSON.parse(conf)
+ } catch (e) {
+ console.error(
+ 'Could not read testbed configuration from sessionstorage: ' + e.message
+ )
+ }
+ return {}
+ })()
+
+ const RECORDING_DURATION = 5000
+
+ red5prosdk.setLogLevel(
+ configuration.verboseLogging
+ ? red5prosdk.LOG_LEVELS.TRACE
+ : red5prosdk.LOG_LEVELS.WARN
+ )
+
+ const { MessageChannel } = red5prosdk
+ let messageChannel
+ let defaultChannelId = 'red5pro'
+ let defaultUserId = `dc-${Math.floor(Math.random() * 0x10000).toString(16)}`
+
+ const streamTitle = document.getElementById('stream-title')
+ const addressField = document.getElementById('address-field')
+ const updateStatusFromEvent = window.red5proHandleMessageChannelEvent // defined in src/template/partial/status-field-message-channel.hbs
+
+ const startButton = document.getElementById('start-button')
+ const dcInput = document.getElementById('dc-input')
+ const sendMessageButton = document.getElementById('send-message-button')
+ const sendDataButton = document.getElementById('send-data-button')
+ const messageInput = document.getElementById('message-input')
+
+ const getAuthenticationParams = () => {
+ var auth = configuration.authentication
+ return auth && auth.enabled
+ ? {
+ connectionParams: {
+ username: auth.username,
+ password: auth.password,
+ token: auth.token
+ }
+ }
+ : {}
+ }
+
+ const getRegionIfDefined = () => {
+ const region = configuration.streamManagerRegion
+ if (
+ typeof region === 'string' &&
+ region.length > 0 &&
+ region !== 'undefined'
+ ) {
+ return region
+ }
+ return undefined
+ }
+
+ const displayServerAddress = (serverAddress, proxyAddress) => {
+ addressField.classList.remove('hidden')
+ proxyAddress = typeof proxyAddress === 'undefined' ? 'N/A' : proxyAddress
+ addressField.innerText = `Proxy Address: ${proxyAddress} | Origin Address: ${serverAddress}`
+ }
+
+ const showModal = (content) => {
+ const div = document.createElement('div')
+ div.classList.add('modal')
+ const container = document.createElement('div')
+ const button = document.createElement('a')
+ const close = document.createTextNode('close')
+ button.href = '#'
+ button.appendChild(close)
+ button.classList.add('modal-close')
+ container.appendChild(button)
+ container.appendChild(content)
+ div.appendChild(container)
+ document.body.appendChild(div)
+ button.addEventListener('click', (event) => {
+ event.preventDefault()
+ document.body.removeChild(div)
+ return false
+ })
+ }
+
+ const closePreviousModal = () => {
+ const modal = document.querySelector('.modal')
+ if (modal) {
+ modal.parentNode.removeChild(modal)
+ }
+ }
+
+ const createMessageContent = (json) => {
+ closePreviousModal()
+ const data = json.data || json
+ const style = 'padding: 10px'
+ const content = document.createElement('div')
+ const p = document.createElement('p')
+ const from = data.sender_id || data.sender || data.username || data.user || data.name || 'UNKNOWN'
+ const header = document.createTextNode(
+ 'Message Received from ' + from + ':'
+ )
+ p.appendChild(header)
+ const messageP = document.createElement('p')
+ messageP.style = style
+ const timestampP = document.createElement('p')
+ timestampP.style = style
+ const message = document.createTextNode('message: ' + data.message)
+ messageP.appendChild(message)
+ const timestamp = document.createTextNode(
+ 'timestamp: ' + new Date(data.timestamp || data.send_timestamp)
+ )
+ timestampP.appendChild(timestamp)
+ content.appendChild(p)
+ content.appendChild(messageP)
+ content.appendChild(timestampP)
+ return content
+ }
+
+
+ const createAudioPlaybackContent = (arrayBuffer) => {
+ closePreviousModal()
+ const style = 'padding: 10px; text-align: center'
+ const blob = new Blob([arrayBuffer], { type: 'audio/mp3' })
+ const audioURL = window.URL.createObjectURL(blob)
+ const content = document.createElement('div')
+ const p = document.createElement('p')
+ const header = document.createTextNode(
+ 'You have received an Audio Message!'
+ )
+ const holder = document.createElement('p')
+ holder.style = style
+ const audio = document.createElement('audio')
+ audio.mimeType = 'audio/mp3'
+ audio.controls = true
+ audio.src = audioURL
+ audio.controlsList = 'nodownload'
+ holder.appendChild(audio)
+ p.appendChild(header)
+ content.appendChild(p)
+ content.appendChild(holder)
+ return content
+ }
+
+ const generateAudioRecordContent = (duration) => {
+ const delay = 500
+ let amount = duration / delay
+ const content = document.createElement('div')
+ const header = document.createElement('p')
+ let count = 0
+ const ellipseCount = 3
+ const title = 'Recording audio'
+ header.innerText = title
+ var t = setInterval(function () {
+ count = (count++ % ellipseCount) + 1
+ var text = title + new Array(count).fill('.').join('')
+ header.innerText = text
+ if (--amount < 0) {
+ clearInterval(t)
+ header.innerText = 'Sent!'
+ }
+ }, delay)
+ content.appendChild(header)
+ return content
+ }
+
+ const onMessageChannelEvent = (event) => {
+ const { type, data } = event
+ updateStatusFromEvent(event)
+ console.log(`[MessageChannel] ${type}.`)
+ if (type === 'WebRTC.Stats.Report') {
+ console.log(JSON.stringify(event.data, null, 2))
+ } else if (type === 'WebRTC.Endpoint.Changed') {
+ const { host } = configuration
+ const { data } = event
+ const { endpoint } = data
+ displayServerAddress(endpoint, host)
+ } else if (type === 'WebRTC.DataChannel.Message' || type === 'MessageChannel.Receive') {
+ console.log(data)
+ // Non-descript data coming in to handle.
+ // event.data.message.data will be either a String or ArrayBuffer/Blob
+ const {
+ message
+ } = data
+ const { data: messageData } = message
+ if (typeof messageData === 'string') {
+ try {
+ var json = JSON.parse(messageData)
+ // Otherwise is an invoke.
+ if (json && !json.send) {
+ showModal(createMessageContent(json))
+ }
+ } catch (e) {
+ // drop.
+ }
+ } else {
+ showModal(createAudioPlaybackContent(messageData))
+ }
+ }
+ }
+
+ const updateState = () => {
+ startButton.innerText = messageChannel ? 'Close Message Channel' : 'Open Message Channel'
+ sendMessageButton.disabled = !messageChannel
+ sendDataButton.disabled = !messageChannel
+ messageInput.value = ''
+ }
+
+ const startDataSend = async () => {
+ if (messageChannel) {
+ try {
+ console.log('Preparing bytes...')
+ showModal(generateAudioRecordContent(RECORDING_DURATION))
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
+ const recorder = new MediaRecorder(stream)
+
+ let chunks = []
+ recorder.ondataavailable = e => {
+ chunks.push(e.data)
+ }
+
+ recorder.onstop = async () => {
+ let blobChunks = [chunks.shift()]
+ const max = messageChannel.getPeerConnection().sctp.maxMessageSize
+ // 262144 is max bytes able to send on DC in one message.
+ let maxbytes = max - blobChunks[0].size
+ while (chunks.length > 0) {
+ const chunk = chunks.shift()
+ maxbytes -= chunk.size
+ if (maxbytes > 0) {
+ blobChunks.push(chunk)
+ }
+ }
+ const blob = new Blob(blobChunks, { type: 'audio/mp3' })
+ const buffer = await new Response(blob).arrayBuffer()
+ console.log('Sending bytes... ' + buffer.byteLength + ' bytes')
+ console.log(buffer)
+ messageChannel.getDataChannel().send(buffer)
+
+ var audioUrl = window.URL.createObjectURL(blob)
+ var audio = document.querySelector('#snippet')
+ audio.controls = true
+ audio.mimeType = 'audio/mp3'
+ audio.src = audioUrl
+ }
+
+ recorder.start(1000)
+ setTimeout(() => {
+ recorder.stop()
+ stream.getTracks().forEach(track => track.stop())
+ }, RECORDING_DURATION)
+ } catch (error) {
+ console.error(error)
+ alert(error.message)
+ }
+ }
+ }
+
+ const start = async () => {
+ shutdown()
+ try {
+ startButton.disabled = true
+
+ defaultChannelId = dcInput.value
+ defaultUserId = `dc-${Math.floor(Math.random() * 0x10000).toString(16)}`
+
+ const {
+ protocol,
+ host,
+ port,
+ app,
+ streamManagerAPI,
+ streamManagerNodeGroup: nodeGroup,
+ } = configuration
+ const region = getRegionIfDefined()
+ const params = region
+ ? {
+ region,
+ strict: true,
+ }
+ : undefined
+ const connectionParams = params
+ ? { ...params, ...getAuthenticationParams().connectionParams }
+ : getAuthenticationParams().connectionParams
+ const streamName = `${defaultChannelId}-${defaultUserId}`
+ const endpoint = `${protocol}://${host}:${port}/as/${streamManagerAPI}/proxy/whip/${app}/${streamName}`
+ const config = {
+ ...configuration,
+ streamName,
+ endpoint,
+ dataChannelConfiguration: { name: defaultChannelId },
+ connectionParams: {
+ ...connectionParams,
+ nodeGroup,
+ }
+ }
+ messageChannel = new MessageChannel()
+ messageChannel.on('*', onMessageChannelEvent)
+ await messageChannel.init(config)
+ await messageChannel.open()
+ streamTitle.innerText = streamName
+ } catch (error) {
+ console.error(error)
+ alert(error.message)
+ shutdown()
+ } finally {
+ updateState()
+ startButton.disabled = false
+ }
+ }
+
+ startButton.disabled = false
+ startButton.addEventListener('click', () => {
+ if (messageChannel) {
+ shutdown()
+ } else {
+ start()
+ }
+ })
+ sendMessageButton.addEventListener('click', () => {
+ if (messageChannel) {
+ messageChannel.sendMessage(messageInput.value)
+ messageInput.value = ''
+ }
+ })
+ sendDataButton.addEventListener('click', () => {
+ if (messageChannel) {
+ startDataSend()
+ }
+ })
+
+ const shutdown = async () => {
+ if (messageChannel) {
+ await messageChannel.close()
+ messageChannel.off('*', onMessageChannelEvent)
+ }
+ messageChannel = null
+ updateState()
+ }
+
+ window.addEventListener('pagehide', shutdown)
+ window.addEventListener('beforeunload', shutdown)
+
+})(window, window.red5prosdk)
diff --git a/src/page/sm-test/messageChannelStreamManagerProxy/index.md b/src/page/sm-test/messageChannelStreamManagerProxy/index.md
new file mode 100644
index 00000000..3750c29d
--- /dev/null
+++ b/src/page/sm-test/messageChannelStreamManagerProxy/index.md
@@ -0,0 +1,76 @@
+# MesssageChannel Client
+
+This example demonstrates using the `MessageChannel` client to open a client connection to the server in order to send and receive messages (both textual and binary) without the need of a stream.
+
+> The `MessageChannel` client allows for messaging between clients connected on the same `DataChannel` by name without the need to broadcast or consume a stream (`WHIPClient` and `WHEPClient`, respectively).
+
+# Usage
+
+Because `MessageChannel` is a subclass of `WHIPClient` (the media streaming broadcaster), much of the init setup and event structure is similar.
+
+To create and use a `MessageChannel` client (targeting a Stream Manager deployment):
+
+```js
+let messageChannel
+try {
+ const streamName = `${uuid}-message-channel`
+ const endpoint = `https://mydeployment.red5.net/as/v1/proxy/whip/live/${streamName}`
+ const configuration = {
+ endpoint,
+ streamName,
+ dataChannelConfiguration: {
+ name: 'my-channel-name'
+ },
+ connectionParams: {
+ nodeGroup: 'default'
+ }
+ }
+ messageChannel = new MessageChannel()
+ messageChannel.on('*', , (event) => console.log(event))
+
+ // See next section: Init Configuration, for more details.
+ await messageChannel.init(configuration)
+ await messageChannel.open()
+} catch (error) {
+ // Something went wrong...
+}
+
+// ... when ready to close the connection ...
+messageChannel?.close()
+```
+
+# Events
+
+Because `MessageChannel` inherits from `WHIPClient`, events unrelated to streaming - such as those related to the underlying WebRTC connection (e.g., `WebRTC.*`) - will be dispatched from `MessageChannel`.
+
+There are a few that are specific to `MessageChannel` that are available and enumerated on the `MessageChannelEventTypes` object:
+
+| Access | Event Type | Meaning |
+| :--- | :--- | :--- |
+| `OPEN` | 'MessageChannel.Open' | When the message channel has successfully opened and available to send and receive messages. |
+| `SEND` | 'MessageChannel.Send' | When the message channel has sent a message along the message channel. _Note: This is not confirmation that the server received the actual message._ |
+| `RECEIVE` | 'MessageChannel.Receive' | When the message channel has received a message. |
+| `CLOSE` | 'MessageChannel.Close' | When the message channel has been closed. |
+| `FAIL` | 'MessageChannel.Fail' | When the message channel has failed to open properly. |
+| `ERROR` | 'MessageChannel.Error' | When an error has occurred in opening or during a message channel session. |
+
+# Send API
+
+The `MessageChannel` has a few options for broadcasting messages out to other clients connected to the channel:
+
+## send(methodName: string, data: any)
+
+The `send` method is an override of the `MessageChannel` underlying `WHIPClient` implementation. It essentially is an override to ensure the message data is delivered on other connected clients to the specified DataChannel.
+
+> The `data` is expected as either a string or an `Object` that can be serialized to JSON.
+
+## sendMessage(message: any)
+
+The `sendMessage` method is a convenience method of which the `send()` call invokes - delivering JSON data to all clients connected to the specified DataChannel
+
+> The `message` is expected as either a string or an `Object` that can be serialized to JSON.
+
+## sendData(data: any)
+
+The `sendData` method will attempt to send any type of data, untouched, along the DataChannel - as such, with it comes great power; use wisely.
+
diff --git a/src/page/test/messageChannel/index.html b/src/page/test/messageChannel/index.html
new file mode 100644
index 00000000..b6cd3764
--- /dev/null
+++ b/src/page/test/messageChannel/index.html
@@ -0,0 +1,67 @@
+
+{{> license}}
+
+
+ {{> meta title='Message Channel Client'}}
+ {{> header-scripts}}
+ {{> header-stylesheets}}
+
+
+
+
+
+ {{> top-bar }}
+
+ {{> settings-link}}
+ {{> test-info testTitle='Message Channel Client'}}
+
+
+
+ Data Channel Name:
+
+
+
+ Open Message Channel
+
+
+ {{> status-field-message-channel}}
+
+
+ Message:
+
+
+
+ Clicking the button below a message will be sent to all other connected Message Channel clients.
+
+
Click to send message.
+
+
+
+ Clicking the button below will grab a snippet of the audio of the stream and send as an ArrayBuffer over the Message Channel.
+
+
Click to send Audio Snippet.
+
+
+
+
+
+
+ {{> footer}}
+ {{> body-scripts}}
+
+
+
diff --git a/src/page/test/messageChannel/index.js b/src/page/test/messageChannel/index.js
new file mode 100644
index 00000000..857f4e3a
--- /dev/null
+++ b/src/page/test/messageChannel/index.js
@@ -0,0 +1,324 @@
+/*
+Copyright © 2015 Infrared5, Inc. All rights reserved.
+
+The accompanying code comprising examples for use solely in conjunction with Red5 Pro (the "Example Code")
+is licensed to you by Infrared5 Inc. in consideration of your agreement to the following
+license terms and conditions. Access, use, modification, or redistribution of the accompanying
+code constitutes your acceptance of the following license terms and conditions.
+
+Permission is hereby granted, free of charge, to you to use the Example Code and associated documentation
+files (collectively, the "Software") without restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
+persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The Software shall be used solely in conjunction with Red5 Pro. Red5 Pro is licensed under a separate end
+user license agreement (the "EULA"), which must be executed with Infrared5, Inc.
+An example of the EULA can be found on our website at: https://account.red5.net/assets/LICENSE.txt.
+
+The above copyright notice and this license shall be included in all copies or portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL INFRARED5, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+;((window, red5prosdk) => {
+
+ const configuration = (function () {
+ var conf = sessionStorage.getItem('r5proTestBed')
+ try {
+ return JSON.parse(conf)
+ } catch (e) {
+ console.error(
+ 'Could not read testbed configuration from sessionstorage: ' + e.message
+ )
+ }
+ return {}
+ })()
+
+ const RECORDING_DURATION = 5000
+
+ red5prosdk.setLogLevel(
+ configuration.verboseLogging
+ ? red5prosdk.LOG_LEVELS.TRACE
+ : red5prosdk.LOG_LEVELS.WARN
+ )
+
+ const { MessageChannel } = red5prosdk
+ let messageChannel
+ let defaultChannelId = 'red5pro'
+ let defaultUserId = `dc-${Math.floor(Math.random() * 0x10000).toString(16)}`
+
+ const streamTitle = document.getElementById('stream-title')
+ const updateStatusFromEvent = window.red5proHandleMessageChannelEvent // defined in src/template/partial/status-field-message-channel.hbs
+
+ const startButton = document.getElementById('start-button')
+ const dcInput = document.getElementById('dc-input')
+ const sendMessageButton = document.getElementById('send-message-button')
+ const sendDataButton = document.getElementById('send-data-button')
+ const messageInput = document.getElementById('message-input')
+
+ const getAuthenticationParams = () => {
+ var auth = configuration.authentication
+ return auth && auth.enabled
+ ? {
+ connectionParams: {
+ username: auth.username,
+ password: auth.password,
+ token: auth.token
+ }
+ }
+ : {}
+ }
+
+ const showModal = (content) => {
+ const div = document.createElement('div')
+ div.classList.add('modal')
+ const container = document.createElement('div')
+ const button = document.createElement('a')
+ const close = document.createTextNode('close')
+ button.href = '#'
+ button.appendChild(close)
+ button.classList.add('modal-close')
+ container.appendChild(button)
+ container.appendChild(content)
+ div.appendChild(container)
+ document.body.appendChild(div)
+ button.addEventListener('click', (event) => {
+ event.preventDefault()
+ document.body.removeChild(div)
+ return false
+ })
+ }
+
+ const closePreviousModal = () => {
+ const modal = document.querySelector('.modal')
+ if (modal) {
+ modal.parentNode.removeChild(modal)
+ }
+ }
+
+ const createMessageContent = (json) => {
+ closePreviousModal()
+ const data = json.data || json
+ const style = 'padding: 10px'
+ const content = document.createElement('div')
+ const p = document.createElement('p')
+ const from = data.sender_id || data.sender || data.username || data.user || data.name || 'UNKNOWN'
+ const header = document.createTextNode(
+ 'Message Received from ' + from + ':'
+ )
+ p.appendChild(header)
+ const messageP = document.createElement('p')
+ messageP.style = style
+ const timestampP = document.createElement('p')
+ timestampP.style = style
+ const message = document.createTextNode('message: ' + data.message)
+ messageP.appendChild(message)
+ const timestamp = document.createTextNode(
+ 'timestamp: ' + new Date(data.timestamp || data.send_timestamp)
+ )
+ timestampP.appendChild(timestamp)
+ content.appendChild(p)
+ content.appendChild(messageP)
+ content.appendChild(timestampP)
+ return content
+ }
+
+
+ const createAudioPlaybackContent = (arrayBuffer) => {
+ closePreviousModal()
+ const style = 'padding: 10px; text-align: center'
+ const blob = new Blob([arrayBuffer], { type: 'audio/mp3' })
+ const audioURL = window.URL.createObjectURL(blob)
+ const content = document.createElement('div')
+ const p = document.createElement('p')
+ const header = document.createTextNode(
+ 'You have received an Audio Message!'
+ )
+ const holder = document.createElement('p')
+ holder.style = style
+ const audio = document.createElement('audio')
+ audio.mimeType = 'audio/mp3'
+ audio.controls = true
+ audio.src = audioURL
+ audio.controlsList = 'nodownload'
+ holder.appendChild(audio)
+ p.appendChild(header)
+ content.appendChild(p)
+ content.appendChild(holder)
+ return content
+ }
+
+ const generateAudioRecordContent = (duration) => {
+ const delay = 500
+ let amount = duration / delay
+ const content = document.createElement('div')
+ const header = document.createElement('p')
+ let count = 0
+ const ellipseCount = 3
+ const title = 'Recording audio'
+ header.innerText = title
+ var t = setInterval(function () {
+ count = (count++ % ellipseCount) + 1
+ var text = title + new Array(count).fill('.').join('')
+ header.innerText = text
+ if (--amount < 0) {
+ clearInterval(t)
+ header.innerText = 'Sent!'
+ }
+ }, delay)
+ content.appendChild(header)
+ return content
+ }
+
+ const onMessageChannelEvent = (event) => {
+ const { type, data } = event
+ updateStatusFromEvent(event)
+ console.log(`[MessageChannel] ${type}.`)
+ if (type === 'WebRTC.Stats.Report') {
+ console.log(JSON.stringify(event.data, null, 2))
+ } else if (type === 'WebRTC.DataChannel.Message' || type === 'MessageChannel.Receive') {
+ console.log(data)
+ // Non-descript data coming in to handle.
+ // event.data.message.data will be either a String or ArrayBuffer/Blob
+ const {
+ message
+ } = data
+ const { data: messageData } = message
+ if (typeof messageData === 'string') {
+ try {
+ var json = JSON.parse(messageData)
+ // Otherwise is an invoke.
+ if (json && !json.send) {
+ showModal(createMessageContent(json))
+ }
+ } catch (e) {
+ // drop.
+ }
+ } else {
+ showModal(createAudioPlaybackContent(messageData))
+ }
+ }
+ }
+
+ const updateState = () => {
+ startButton.innerText = messageChannel ? 'Close Message Channel' : 'Open Message Channel'
+ sendMessageButton.disabled = !messageChannel
+ sendDataButton.disabled = !messageChannel
+ messageInput.value = ''
+ }
+
+ const startDataSend = async () => {
+ if (messageChannel) {
+ try {
+ console.log('Preparing bytes...')
+ showModal(generateAudioRecordContent(RECORDING_DURATION))
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
+ const recorder = new MediaRecorder(stream)
+
+ let chunks = []
+ recorder.ondataavailable = e => {
+ chunks.push(e.data)
+ }
+
+ recorder.onstop = async () => {
+ let blobChunks = [chunks.shift()]
+ const max = messageChannel.getPeerConnection().sctp.maxMessageSize
+ // 262144 is max bytes able to send on DC in one message.
+ let maxbytes = max - blobChunks[0].size
+ while (chunks.length > 0) {
+ const chunk = chunks.shift()
+ maxbytes -= chunk.size
+ if (maxbytes > 0) {
+ blobChunks.push(chunk)
+ }
+ }
+ const blob = new Blob(blobChunks, { type: 'audio/mp3' })
+ const buffer = await new Response(blob).arrayBuffer()
+ console.log('Sending bytes... ' + buffer.byteLength + ' bytes')
+ console.log(buffer)
+ messageChannel.getDataChannel().send(buffer)
+
+ var audioUrl = window.URL.createObjectURL(blob)
+ var audio = document.querySelector('#snippet')
+ audio.controls = true
+ audio.mimeType = 'audio/mp3'
+ audio.src = audioUrl
+ }
+
+ recorder.start(1000)
+ setTimeout(() => {
+ recorder.stop()
+ stream.getTracks().forEach(track => track.stop())
+ }, RECORDING_DURATION)
+ } catch (error) {
+ console.error(error)
+ alert(error.message)
+ }
+ }
+ }
+
+ const start = async () => {
+ shutdown()
+ try {
+ startButton.disabled = true
+
+ defaultChannelId = dcInput.value
+ defaultUserId = `dc-${Math.floor(Math.random() * 0x10000).toString(16)}`
+ const streamName = `${defaultChannelId}-${defaultUserId}`
+ const config = {
+ ...configuration,
+ ...getAuthenticationParams(),
+ streamName,
+ dataChannelConfiguration: { name: defaultChannelId }
+ }
+ messageChannel = new MessageChannel()
+ messageChannel.on('*', onMessageChannelEvent)
+ await messageChannel.init(config)
+ await messageChannel.open()
+ streamTitle.innerText = streamName
+ } catch (error) {
+ console.error(error)
+ alert(error.message)
+ shutdown()
+ } finally {
+ updateState()
+ startButton.disabled = false
+ }
+ }
+
+ startButton.disabled = false
+ startButton.addEventListener('click', () => {
+ if (messageChannel) {
+ shutdown()
+ } else {
+ start()
+ }
+ })
+ sendMessageButton.addEventListener('click', () => {
+ if (messageChannel) {
+ messageChannel.sendMessage(messageInput.value)
+ messageInput.value = ''
+ }
+ })
+ sendDataButton.addEventListener('click', () => {
+ if (messageChannel) {
+ startDataSend()
+ }
+ })
+
+ const shutdown = async () => {
+ if (messageChannel) {
+ await messageChannel.close()
+ messageChannel.off('*', onMessageChannelEvent)
+ }
+ messageChannel = null
+ updateState()
+ }
+
+ window.addEventListener('pagehide', shutdown)
+ window.addEventListener('beforeunload', shutdown)
+
+})(window, window.red5prosdk)
diff --git a/src/page/test/messageChannel/index.md b/src/page/test/messageChannel/index.md
new file mode 100644
index 00000000..c4cc2b1b
--- /dev/null
+++ b/src/page/test/messageChannel/index.md
@@ -0,0 +1,75 @@
+# MesssageChannel Client
+
+This example demonstrates using the `MessageChannel` client to open a client connection to the server in order to send and receive messages (both textual and binary) without the need of a stream.
+
+> The `MessageChannel` client allows for messaging between clients connected on the same `DataChannel` by name without the need to broadcast or consume a stream (`WHIPClient` and `WHEPClient`, respectively).
+
+# Usage
+
+Because `MessageChannel` is a subclass of `WHIPClient` (the media streaming broadcaster), much of the init setup and event structure is similar.
+
+To create and use a `MessageChannel` client (targeting a standalone server deployment):
+
+```js
+let messageChannel
+try {
+ const streamName = `${uuid}-message-channel`
+ const configuration = {
+ host: 'mydeployment.red5.net',
+ streamName,
+ dataChannelConfiguration: {
+ name: 'my-channel-name'
+ },
+ connectionParams: {
+ nodeGroup: 'default'
+ }
+ }
+ messageChannel = new MessageChannel()
+ messageChannel.on('*', , (event) => console.log(event))
+
+ // See next section: Init Configuration, for more details.
+ await messageChannel.init(configuration)
+ await messageChannel.open()
+} catch (error) {
+ // Something went wrong...
+}
+
+// ... when ready to close the connection ...
+messageChannel?.close()
+```
+
+# Events
+
+Because `MessageChannel` inherits from `WHIPClient`, events unrelated to streaming - such as those related to the underlying WebRTC connection (e.g., `WebRTC.*`) - will be dispatched from `MessageChannel`.
+
+There are a few that are specific to `MessageChannel` that are available and enumerated on the `MessageChannelEventTypes` object:
+
+| Access | Event Type | Meaning |
+| :--- | :--- | :--- |
+| `OPEN` | 'MessageChannel.Open' | When the message channel has successfully opened and available to send and receive messages. |
+| `SEND` | 'MessageChannel.Send' | When the message channel has sent a message along the message channel. _Note: This is not confirmation that the server received the actual message._ |
+| `RECEIVE` | 'MessageChannel.Receive' | When the message channel has received a message. |
+| `CLOSE` | 'MessageChannel.Close' | When the message channel has been closed. |
+| `FAIL` | 'MessageChannel.Fail' | When the message channel has failed to open properly. |
+| `ERROR` | 'MessageChannel.Error' | When an error has occurred in opening or during a message channel session. |
+
+# Send API
+
+The `MessageChannel` has a few options for broadcasting messages out to other clients connected to the channel:
+
+## send(methodName: string, data: any)
+
+The `send` method is an override of the `MessageChannel` underlying `WHIPClient` implementation. It essentially is an override to ensure the message data is delivered on other connected clients to the specified DataChannel.
+
+> The `data` is expected as either a string or an `Object` that can be serialized to JSON.
+
+## sendMessage(message: any)
+
+The `sendMessage` method is a convenience method of which the `send()` call invokes - delivering JSON data to all clients connected to the specified DataChannel
+
+> The `message` is expected as either a string or an `Object` that can be serialized to JSON.
+
+## sendData(data: any)
+
+The `sendData` method will attempt to send any type of data, untouched, along the DataChannel - as such, with it comes great power; use wisely.
+
diff --git a/src/page/test/pubnubClient/index.js b/src/page/test/pubnubClient/index.js
index 9734d9ce..fa7555ba 100644
--- a/src/page/test/pubnubClient/index.js
+++ b/src/page/test/pubnubClient/index.js
@@ -277,6 +277,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
pubnubClient.off('*', onPubNubEvent)
pubnubClient.destroy()
}
+ pubnubClient = null
}
window.addEventListener('pagehide', shutdown)
window.addEventListener('beforeunload', shutdown)
diff --git a/src/page/testbed-menu-sm.html b/src/page/testbed-menu-sm.html
index 5fdd51f1..b48926f0 100644
--- a/src/page/testbed-menu-sm.html
+++ b/src/page/testbed-menu-sm.html
@@ -47,6 +47,7 @@ Red5 Pro HTML Stream Manager Testbed
Publish - Stream Manager Proxy WebSocket
PubNub Client - Stream Manager
+ Message Channel - Stream Manager Proxy
castLabs Publish - DRM Encrypted Publish, Stream Manager Proxy
castLabs Subscribe- DRM Encrypted Playback, Stream Manager Proxy
castLabs Watermarked - Playback, Stream Manager Proxy
diff --git a/src/page/testbed-menu.html b/src/page/testbed-menu.html
index d688e589..8b485bc4 100644
--- a/src/page/testbed-menu.html
+++ b/src/page/testbed-menu.html
@@ -50,6 +50,7 @@ Red5 Pro HTML Testbed
PubNub Client
+ Message Channel
Conference
Two-Way
castLabs Publish - DRM Encrypted Publish
diff --git a/src/template/partial/status-field-message-channel.hbs b/src/template/partial/status-field-message-channel.hbs
new file mode 100644
index 00000000..4ee678d6
--- /dev/null
+++ b/src/template/partial/status-field-message-channel.hbs
@@ -0,0 +1,2 @@
+On hold.
+
diff --git a/static/lib/red5pro/CHANGES.md b/static/lib/red5pro/CHANGES.md
index aa39a28c..67ad69b8 100644
--- a/static/lib/red5pro/CHANGES.md
+++ b/static/lib/red5pro/CHANGES.md
@@ -1,5 +1,9 @@
# Changes
+## 15.3.0
+
+- feat: Introduction of `MessageChannel` for message communication over a data-channel enabled client (Todd Anderson). _There is no underlying media streaming logic in this client._
+
## 15.2.0
- fix: ICE configuration order preference (Todd Anderson).
diff --git a/static/lib/red5pro/README.md b/static/lib/red5pro/README.md
index 37733591..8be7f5b8 100644
--- a/static/lib/red5pro/README.md
+++ b/static/lib/red5pro/README.md
@@ -5,6 +5,7 @@
Quick Start •
Publishing •
Subscribing •
+ Message Channel •
PubNub Client
diff --git a/static/lib/red5pro/docs/api/README.md b/static/lib/red5pro/docs/api/README.md
index a920d105..e3287287 100644
--- a/static/lib/red5pro/docs/api/README.md
+++ b/static/lib/red5pro/docs/api/README.md
@@ -1,4 +1,4 @@
-**Red5 Pro WebRTC SDK v15.2.0**
+**Red5 Pro WebRTC SDK v15.3.0**
***
@@ -9,6 +9,7 @@
Quick Start •
Publishing •
Subscribing •
+ Message Channel •
PubNub Client
diff --git a/static/lib/red5pro/docs/api/_media/hls-subscriber.md b/static/lib/red5pro/docs/api/_media/hls-subscriber.md
index 3df6097a..f61265d9 100644
--- a/static/lib/red5pro/docs/api/_media/hls-subscriber.md
+++ b/static/lib/red5pro/docs/api/_media/hls-subscriber.md
@@ -5,6 +5,7 @@
Quick Start •
Publishing •
Subscribing •
+ Message Channel •
PubNub Client
diff --git a/static/lib/red5pro/docs/api/_media/message-channel.md b/static/lib/red5pro/docs/api/_media/message-channel.md
new file mode 100644
index 00000000..bb300c4d
--- /dev/null
+++ b/static/lib/red5pro/docs/api/_media/message-channel.md
@@ -0,0 +1,283 @@
+
+
+
+
+ Quick Start •
+ Publishing •
+ Subscribing •
+ Message Channel •
+ PubNub Client
+
+
+---
+
+# MessageChannel
+
+The `MessageChannel` client is an ingest-based (read: "broadcast") client that extends `WHIPClient` as its underlying framework and capabilities are very similar, with the differing aspect of `MessageChannel` not supporting any media streaming.
+
+## A Note on WHIP/WHEP & DataChannel
+
+It should be noted if that `WHIPClient` and `WHEPClient` - used for publishing and subscribing streams, respectively - by default, include a messaging channel (a.k.a., `DataChannel`) through their underlying `RTCPeerConnection`.
+
+Due to these clients' streaming nature, that underlying messaging channel will be closed once the respective stream is closed - meaning the messaging channel will not remain open if not broadcasting or consuming a stream.
+
+In most cases, this is common scenario. However, if you would like to maintain a messaging channel _along-side_ a streaming client, you can utilize the `MessageChannel` client.
+
+> Be aware that since the `MessageChannel` is not inherently associated with a stream, synchronizations between messages and any associative, external streams will not be available.
+
+* [Usage](#usage)
+* [Init Configuration](#init-configuration)
+* [Send API](#send-api)
+* [Events](#events)
+* [Statistics](#statistics)
+* [Stream Manager 2.0](#stream-manager-20)
+
+# Usage
+
+Because `MessageChannel` is a subclass of `WHIPClient` (the media streaming broadcaster), much of the init setup and event structure is similar.
+
+To create and use a `MessageChannel` client:
+
+```js
+let messageChannel
+try {
+ messageChannel = new MessageChannel()
+ messageChannel.on('*', , (event) => console.log(event))
+
+ // See next section: Init Configuration, for more details.
+ await messageChannel.init(configuration)
+ await messageChannel.open()
+} catch (error) {
+ // Something went wrong...
+}
+
+// ... when ready to close the connection ...
+messageChannel?.close()
+```
+
+## MessageChannel & the SDK
+
+Dependening on how you include the SDK into your project, you can access the `MessageClient` from the following:
+
+_NPM install_:
+
+```js
+import { MessageChannel } from 'red5pro-webrtc-sdk'
+```
+
+_Browser, CDN_:
+
+```js
+const { MessageChannel } = red5prosdk
+```
+
+> For more in-depth information related to usage, please refer to the [WHIPClient](whip-client.md#usage) documentation.
+
+# Init Configuration
+
+Because `MessageChannel` inherits from `WHIPClient`, its initialization configuration shares the same properties and structure, however many attributes will be ignored as they pertain to streaming media on a `WHIPClient` which have no regard to the role of a `MessageChannel`.
+
+The following properties are respected by the `MessageChannel` client:
+
+| Property | Required | Default | Description |
+| :--- | :---: | :---: | :--- |
+| `host` | [x] | *None* | The IP or address that the WebSocket server resides on. |
+| `streamName` | [x] | *None* | The name of the message channel to use in association. |
+| `protocol` | [x] | `https` | The protocol of the host for the signaling communication. |
+| `port` | [x] | `443` | The port on the host that the Red5 server listens on; `5080` or `443` (insecure or secure, respectively). |
+| `app` | [x] | `live` | The webapp context name that the stream is on. |
+| `endpoint` | [-] | `undefined` | The full URL of the endpoint to stream to. **This is primarily used in Stream Manager 2.0 integration for clients.**
+| `rtcConfiguration` | [-] | _Basic_ | The `RTCConfiguration` to use in setting up `RTCPeerConnection`. [RTCConfiguration](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/RTCPeerConnection#RTCConfiguration_dictionary)|
+| `dataChannelConfiguration` | [-] | `{name: "red5pro"}` | An object used in configuring a n `RTCDataChannel`. _Only used when `includeDataChannel` is defined as `true`_ |
+| `connectionParams` | [-] | `undefined` | An object of connection parameters to send to the server upon connection request. |
+
+## Init Example
+
+The following is an example of using the init configuration for a `MessageChannel` client on a Standalone deployment of the Red5 Server:
+
+```js
+try {
+ // If the standalone Red5 server is hosted over HTTPS, most other attributes can be left to default.
+ const configuration = {
+ host: 'mydeployment.red5.net',
+ streamName: `${uuid}-message-channel`,
+ dataChannelConfiguration: {
+ name: 'my-channel-name'
+ }
+ }
+ const messageChannel = new MessageChannel()
+ messageChannel.on('*', , (event) => console.log(event))
+ await messageChannel.init(configuration)
+ await messageChannel.open()
+} catch (error) {
+ // Something went wrong...
+}
+```
+
+# Send API
+
+The `MessageChannel` has a few options for broadcasting messages out to other clients connected to the channel:
+
+## send(methodName: string, data: any)
+
+The `send` method is an override of the `MessageChannel` underlying `WHIPClient` implementation. It essentially is an override to ensure the message data is delivered on other connected clients to the specified DataChannel.
+
+> The `data` is expected as either a string or an `Object` that can be serialized to JSON.
+
+## sendMessage(message: any)
+
+The `sendMessage` method is a convenience method of which the `send()` call invokes - delivering JSON data to all clients connected to the specified DataChannel
+
+> The `message` is expected as either a string or an `Object` that can be serialized to JSON.
+
+## sendData(data: any)
+
+The `sendData` method will attempt to send any type of data, untouched, along the DataChannel - as such, with it comes great power; use wisely.
+
+# Events
+
+Because `MessageChannel` inherits from `WHIPClient`, events unrelated to streaming - such as those related to the underlying WebRTC connection (e.g., `WebRTC.*`) - will be dispatched from `MessageChannel`.
+
+There are a few that are specific to `MessageChannel` that are available and enumerated on the `MessageChannelEventTypes` object:
+
+| Access | Event Type | Meaning |
+| :--- | :--- | :--- |
+| `OPEN` | 'MessageChannel.Open' | When the message channel has successfully opened and available to send and receive messages. |
+| `SEND` | 'MessageChannel.Send' | When the message channel has sent a message along the message channel. _Note: This is not confirmation that the server received the actual message._ |
+| `RECEIVE` | 'MessageChannel.Receive' | When the message channel has received a message. |
+| `CLOSE` | 'MessageChannel.Close' | When the message channel has been closed. |
+| `FAIL` | 'MessageChannel.Fail' | When the message channel has failed to open properly. |
+| `ERROR` | 'MessageChannel.Error' | When an error has occurred in opening or during a message channel session. |
+
+> Please visit the [WHIPClient](whip-client.md#events) documentation for more in-depth listing of events.
+
+# Statistics
+
+Similar to being able to monitor for statistics on the underlying `RTCPeerConnection` of other clients from the SDK, statistics related to the `MessageChannel` can be monitored as well - though the data gathered will pertain mostly to the connection and `data-channel`.
+
+## Stats Configuration
+
+The configuration used for statistics monitoring has the following structure:
+
+```js
+{
+ // Optional.
+ // If provided, it will POST stats to this endpoint.
+ // If undefined or `data-channel`, it will post stats to message transport.
+ // If null or `event-transport`, it will only emit status events.
+ endpoint: red5prosdk.StatsEndpointType.DATA_CHANNEL,
+ additionalHeaders: undefined,
+ interval: 5000, // Interval to poll stats, in milliseconds.
+ include: [], // Empty array allows SDK to be judicious about what stats to include.
+}
+```
+
+### endpoint
+
+* If the `endpoint` is defined with a URL, the SDK will attempt to make `POST` requests with a JSON body representing each individual report.
+* If the `endpoint` is set to `data-channel` or `undefined`, the SDK will post metadata with type `stats-report` on the underlying message transport (DataChannel) if available.
+* If the `endpoint` is set to `event-transport` or `null`, the SDK will only emit events with the metadata on the `WebRTC.StatsReport` event.
+
+### additionalHeaders
+
+By default, if an `endpoint` is defined, the `POST` request body will be in JSON and have the `{ 'Content-Type': 'application/json' }` header set. If requirements - such as authentication - are required, a map of additional headers can be provided to be sent along with the request.
+
+### interval
+
+The polling interval (in milliseconds) to access the `RTCStatsReport` from the underlying `RTCPeerConnection` of the publisher client.
+
+### include
+
+An array of static type strings. These directly map to the listing of type available for `RTCStatsReport` objects. If left empty or undefined, the SDK will report the statistics it deems suitable for tracking proper broadcast conditions.
+
+e.g.,
+
+```js
+include: ['data-channel', 'transport']
+```
+
+> More information about the statistic types are available at [https://developer.mozilla.org/en-US/docs/Web/API/RTCStatsReport#the_statistic_types](https://developer.mozilla.org/en-US/docs/Web/API/RTCStatsReport#the_statistic_types)
+
+## Invocation
+
+To start statistics monitoring, you have a couple of options:
+
+* You can provide a `stats` attribute with the [stats configuration object](#stats-configuration) to the [init configuration](#webrtc-configuration-parameters).
+* You can call `monitorStats` on the publisher client with the optional [stats configuration object](#stats-configuration) parameter.
+
+> Additionally, you can stop monitoring by calling `unmonitorStats` on the publisher client.
+
+## Additional Information
+
+Attached to the metadata that is reported are additional properties that pertain to the publisher client.
+
+As well, Along with the metadata releated to the `RTCStatsReport` objects emitted by the underlying `RTCPeerConnection`, the statistics monitoring also sends out a few event and action metadata related to the operation of a publisher client.
+
+> See the following section for examples.
+
+## Example of Statistics Metadata
+
+The following is an example of a statistics metadata that is emitted in a `WebRTC.StatsReport` event and POSTed to any defined optional endpoint:
+
+```json
+{
+ "name": "MessageChannelStats",
+ "created": 1771514183637,
+ "fingerprint": "165799de-87ac-4c13-95d3-66c7512080fe",
+ "device": {
+ "appVersion": "5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36",
+ "platform": "MacIntel",
+ "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36",
+ "vendor": "Google Inc."
+ },
+ "client": {
+ "host": "myred5.deploy",
+ "streamName": "dc-1771514183635",
+ "connectionParams": {
+ "capabilities": 4
+ }
+ },
+ "publicIP": "174.169.251.174",
+ "type": "stats-report",
+ "timestamp": 1771514658751,
+ "data": {
+ "id": "D159",
+ "timestamp": 1771514658751.39,
+ "type": "data-channel",
+ "label": "red5pro",
+ "state": "open",
+ "messagesSent": 45,
+ "messagesReceived": 93,
+ "bytesSent": 4815,
+ "bytesReceived": 12556
+ }
+}
+```
+# Stream Manager 2.0
+
+> This section provides information that relate to the release of Stream Manager 2.0 and its integration with WHIP/WHEP clients, and MessageChannel.
+
+The Stream Manager 2.0 simplifies the proxying of web clients to Origin and Edge nodes. As such, an initialization configuration property called `endpoint` was added to the WebRTC SDK. This `endpoint` value should be the full URL path to the proxy endpoint on the Stream Manager as is used as such:
+
+## WHIP Proxy
+
+```javascript
+const host = 'my-deployment.red5.net'
+const streamName = `${uuid}-message-channel`
+const nodeGroup = 'my-node-group'
+const endpoint = `https://${host}/as/v1/proxy/whip/live/${streamName}`
+const config = {
+ endpoint,
+ streamName,
+ connectionParams: {
+ nodeGroup
+ },
+ dataChannelConfiguration: {
+ name: 'my-channel'
+ }
+ // additional configurations
+}
+const messageChannel = await new MessageChannel().init(config)
+messageChannel.on('*', (event) => console.log(event))
+await messageChannel.open()
+```
diff --git a/static/lib/red5pro/docs/api/_media/whep-client.md b/static/lib/red5pro/docs/api/_media/whep-client.md
index 2e5abf7a..c5b27ba8 100644
--- a/static/lib/red5pro/docs/api/_media/whep-client.md
+++ b/static/lib/red5pro/docs/api/_media/whep-client.md
@@ -5,6 +5,7 @@
Quick Start •
Publishing •
Subscribing •
+ Message Channel •
PubNub Client
@@ -253,6 +254,7 @@ The polling interval (in milliseconds) to access the `RTCStatsReport` from the u
An array of static type strings. These directly map to the listing of type available for `RTCStatsReport` objects. If left empty or undefined, the SDK will report the statistics it deems suitable for tracking proper broadcast conditions.
e.g.,
+
```js
include: ['inbound-rtp', 'transport']
```
diff --git a/static/lib/red5pro/docs/api/_media/whip-client.md b/static/lib/red5pro/docs/api/_media/whip-client.md
index ea93e46f..8b33169d 100644
--- a/static/lib/red5pro/docs/api/_media/whip-client.md
+++ b/static/lib/red5pro/docs/api/_media/whip-client.md
@@ -5,6 +5,7 @@ i
Quick Start •
Publishing •
Subscribing •
+ Message Channel •
PubNub Client
@@ -287,7 +288,7 @@ The configuration used for statistics monitoring has the following structure:
// If provided, it will POST stats to this endpoint.
// If undefined or `data-channel`, it will post stats to message transport.
// If null or `event-transport`, it will only emit status events.
- red5prosdk.StatsEndpointType.DATA_CHANNEL,
+ endpoint: red5prosdk.StatsEndpointType.DATA_CHANNEL,
additionalHeaders: undefined,
interval: 5000, // Interval to poll stats, in milliseconds.
include: [], // Empty array allows SDK to be judicious about what stats to include.
@@ -313,6 +314,7 @@ The polling interval (in milliseconds) to access the `RTCStatsReport` from the u
An array of static type strings. These directly map to the listing of type available for `RTCStatsReport` objects. If left empty or undefined, the SDK will report the statistics it deems suitable for tracking proper broadcast conditions.
e.g.,
+
```js
include: ['outbound-rtp', 'transport']
```
diff --git a/static/lib/red5pro/docs/api/classes/Event.md b/static/lib/red5pro/docs/api/classes/Event.md
index fb492269..6c01337c 100644
--- a/static/lib/red5pro/docs/api/classes/Event.md
+++ b/static/lib/red5pro/docs/api/classes/Event.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
@@ -13,6 +13,8 @@ Base class for an Event within the Red5 Pro WebRTC SDK.
- [`SubscriberEvent`](SubscriberEvent.md)
- [`PublisherEvent`](PublisherEvent.md)
- [`MessageTransportStateEvent`](MessageTransportStateEvent.md)
+- [`PubNubEvent`](PubNubEvent.md)
+- [`MessageChannelEvent`](MessageChannelEvent.md)
## Constructors
diff --git a/static/lib/red5pro/docs/api/classes/EventEmitter.md b/static/lib/red5pro/docs/api/classes/EventEmitter.md
index fbc75da6..14ccfd87 100644
--- a/static/lib/red5pro/docs/api/classes/EventEmitter.md
+++ b/static/lib/red5pro/docs/api/classes/EventEmitter.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/classes/HLSSubscriber.md b/static/lib/red5pro/docs/api/classes/HLSSubscriber.md
index bcd3c579..6a9079fc 100644
--- a/static/lib/red5pro/docs/api/classes/HLSSubscriber.md
+++ b/static/lib/red5pro/docs/api/classes/HLSSubscriber.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/classes/LiveSeekClient.md b/static/lib/red5pro/docs/api/classes/LiveSeekClient.md
index 2adc8d69..a3682121 100644
--- a/static/lib/red5pro/docs/api/classes/LiveSeekClient.md
+++ b/static/lib/red5pro/docs/api/classes/LiveSeekClient.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
@@ -540,7 +540,7 @@ The time to seek to.
### send()
-> **send**(`methodName`, `data`): `undefined` \| `Promise`\<`boolean`\>
+> **send**(`methodName`, `data`): `Promise`\<`undefined` \| `boolean`\>
Send a message to the Red5 Pro Server over the message transport (DataChannel).
@@ -560,7 +560,7 @@ The data to send.
#### Returns
-`undefined` \| `Promise`\<`boolean`\>
+`Promise`\<`undefined` \| `boolean`\>
#### Inherited from
diff --git a/static/lib/red5pro/docs/api/classes/MessageChannel.md b/static/lib/red5pro/docs/api/classes/MessageChannel.md
new file mode 100644
index 00000000..3b1b6d4f
--- /dev/null
+++ b/static/lib/red5pro/docs/api/classes/MessageChannel.md
@@ -0,0 +1,726 @@
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
+
+***
+
+[Red5 Pro WebRTC SDK](../globals.md) / MessageChannel
+
+# Class: MessageChannel
+
+MessageChannel is a subclass of WHIPClient that provides a data channel for sending and receiving messages only.
+_There is no underlying media streaming logic in this client._
+
+This ingest-based client is useful for sending and receiving messages to and from the server over a designated data channel.
+
+## Extends
+
+- [`WHIPClient`](WHIPClient.md)
+
+## Constructors
+
+### Constructor
+
+> **new MessageChannel**(`url`, `additionalOptions?`): `MessageChannel`
+
+#### Parameters
+
+##### url
+
+`undefined` | `string`
+
+##### additionalOptions?
+
+[`RTCWhipPublisherConfigType`](../type-aliases/RTCWhipPublisherConfigType.md)
+
+#### Returns
+
+`MessageChannel`
+
+#### Overrides
+
+[`WHIPClient`](WHIPClient.md).[`constructor`](WHIPClient.md#constructor)
+
+## Accessors
+
+### options
+
+#### Get Signature
+
+> **get** **options**(): `undefined` \| [`RTCWhipPublisherConfigType`](../type-aliases/RTCWhipPublisherConfigType.md)
+
+Get the options for the WHIPClient.
+
+##### Returns
+
+`undefined` \| [`RTCWhipPublisherConfigType`](../type-aliases/RTCWhipPublisherConfigType.md)
+
+#### Inherited from
+
+[`WHIPClient`](WHIPClient.md).[`options`](WHIPClient.md#options)
+
+## Methods
+
+### callServer()
+
+> **callServer**(`methodName`, `args`): `Promise`\<`any`\>
+
+Call a method on the server.
+
+#### Parameters
+
+##### methodName
+
+`string`
+
+The name of the method to call.
+
+##### args
+
+`any`
+
+The arguments to call the method with.
+
+#### Returns
+
+`Promise`\<`any`\>
+
+#### Inherited from
+
+[`WHIPClient`](WHIPClient.md).[`callServer`](WHIPClient.md#callserver)
+
+***
+
+### close()
+
+> **close**(): `Promise`\<`void`\>
+
+Close the MessageChannel.
+
+#### Returns
+
+`Promise`\<`void`\>
+
+***
+
+### emit()
+
+> **emit**(`type`, `data`): `void`
+
+Emit an event on the WHIPClient.
+
+#### Parameters
+
+##### type
+
+`string`
+
+The type of event to emit.
+
+##### data
+
+`any`
+
+The data to emit.
+
+#### Returns
+
+`void`
+
+#### Inherited from
+
+[`WHIPClient`](WHIPClient.md).[`emit`](WHIPClient.md#emit)
+
+***
+
+### getDataChannel()
+
+> **getDataChannel**(): `undefined` \| `RTCDataChannel`
+
+Get the DataChannel for the WHIPClient.
+
+#### Returns
+
+`undefined` \| `RTCDataChannel`
+
+#### Inherited from
+
+[`WHIPClient`](WHIPClient.md).[`getDataChannel`](WHIPClient.md#getdatachannel)
+
+***
+
+### getMediaStream()
+
+> **getMediaStream**(): `undefined` \| `MediaStream`
+
+Get the MediaStream generated for the WHIPClient.
+
+#### Returns
+
+`undefined` \| `MediaStream`
+
+#### Inherited from
+
+[`WHIPClient`](WHIPClient.md).[`getMediaStream`](WHIPClient.md#getmediastream)
+
+***
+
+### getMessageTransport()
+
+> **getMessageTransport**(): `undefined` \| `MessageTransport`
+
+Get the MessageTransport for the WHIPClient.
+
+#### Returns
+
+`undefined` \| `MessageTransport`
+
+#### Inherited from
+
+[`WHIPClient`](WHIPClient.md).[`getMessageTransport`](WHIPClient.md#getmessagetransport)
+
+***
+
+### getOptions()
+
+> **getOptions**(): `undefined` \| [`RTCWhipPublisherConfigType`](../type-aliases/RTCWhipPublisherConfigType.md)
+
+Get the options for the WHIPClient.
+
+#### Returns
+
+`undefined` \| [`RTCWhipPublisherConfigType`](../type-aliases/RTCWhipPublisherConfigType.md)
+
+#### Inherited from
+
+[`WHIPClient`](WHIPClient.md).[`getOptions`](WHIPClient.md#getoptions)
+
+***
+
+### getPeerConnection()
+
+> **getPeerConnection**(): `undefined` \| `RTCPeerConnection`
+
+Get the PeerConnection for the WHIPClient.
+
+#### Returns
+
+`undefined` \| `RTCPeerConnection`
+
+#### Inherited from
+
+[`WHIPClient`](WHIPClient.md).[`getPeerConnection`](WHIPClient.md#getpeerconnection)
+
+***
+
+### getPubNubClient()
+
+> **getPubNubClient**(): `undefined` \| [`PubNubClient`](PubNubClient.md)
+
+Get the PubNub client for the WHIPClient.
+
+#### Returns
+
+`undefined` \| [`PubNubClient`](PubNubClient.md)
+
+#### Inherited from
+
+[`WHIPClient`](WHIPClient.md).[`getPubNubClient`](WHIPClient.md#getpubnubclient)
+
+***
+
+### getType()
+
+> **getType**(): `string`
+
+Get the type of the MessageChannel.
+
+#### Returns
+
+`string`
+
+#### Overrides
+
+[`WHIPClient`](WHIPClient.md).[`getType`](WHIPClient.md#gettype)
+
+***
+
+### init()
+
+> **init**(`options`): `Promise`\<`MessageChannel`\>
+
+Initialize the MessageChannel.
+
+#### Parameters
+
+##### options
+
+[`RTCWhipPublisherConfigType`](../type-aliases/RTCWhipPublisherConfigType.md)
+
+The options to initialize the MessageChannel with. See [RTCWhipPublisherConfigType](../type-aliases/RTCWhipPublisherConfigType.md) for more details.
+
+#### Returns
+
+`Promise`\<`MessageChannel`\>
+
+#### Overrides
+
+[`WHIPClient`](WHIPClient.md).[`init`](WHIPClient.md#init)
+
+***
+
+### initWithStream()
+
+> **initWithStream**(`options`, `stream`): `Promise`\<`MessageChannel`\>
+
+Initialize the WHIPClient with a MediaStream. Doing so will skip the SDK attempting to generate a MediaStream through browser-based media APIs.
+
+#### Parameters
+
+##### options
+
+[`RTCWhipPublisherConfigType`](../type-aliases/RTCWhipPublisherConfigType.md)
+
+The options to use for initialization.
+
+##### stream
+
+`MediaStream`
+
+The stream to use for initialization.
+
+#### Returns
+
+`Promise`\<`MessageChannel`\>
+
+#### Inherited from
+
+[`WHIPClient`](WHIPClient.md).[`initWithStream`](WHIPClient.md#initwithstream)
+
+***
+
+### monitorStats()
+
+> **monitorStats**(`stats?`): [`WHIPClient`](WHIPClient.md)
+
+Monitor the statistics of the MediaStream being published to the server over the underlying RTCPeerConnection..
+
+#### Parameters
+
+##### stats?
+
+[`StatsConfig`](../type-aliases/StatsConfig.md)
+
+The statistics configuration.
+
+#### Returns
+
+[`WHIPClient`](WHIPClient.md)
+
+#### Inherited from
+
+[`WHIPClient`](WHIPClient.md).[`monitorStats`](WHIPClient.md#monitorstats)
+
+***
+
+### muteAudio()
+
+> **muteAudio**(): `void`
+
+Mute the audio being published to the server.
+
+#### Returns
+
+`void`
+
+#### Inherited from
+
+[`WHIPClient`](WHIPClient.md).[`muteAudio`](WHIPClient.md#muteaudio)
+
+***
+
+### muteVideo()
+
+> **muteVideo**(): `void`
+
+Mute the video being published to the server.
+
+#### Returns
+
+`void`
+
+#### Inherited from
+
+[`WHIPClient`](WHIPClient.md).[`muteVideo`](WHIPClient.md#mutevideo)
+
+***
+
+### off()
+
+> **off**(`type`, `fn`): `void`
+
+Remove an event listener from the WHIPClient.
+
+#### Parameters
+
+##### type
+
+`string`
+
+The type of event to remove the listener from.
+
+##### fn
+
+(`event`) => `void`
+
+The function to remove the listener from.
+
+#### Returns
+
+`void`
+
+#### Inherited from
+
+[`WHIPClient`](WHIPClient.md).[`off`](WHIPClient.md#off)
+
+***
+
+### on()
+
+> **on**(`type`, `fn`): `void`
+
+Add an event listener to the WHIPClient.
+
+#### Parameters
+
+##### type
+
+`string`
+
+The type of event to listen for.
+
+##### fn
+
+(`event`) => `void`
+
+The function to call when the event is triggered.
+
+#### Returns
+
+`void`
+
+#### Inherited from
+
+[`WHIPClient`](WHIPClient.md).[`on`](WHIPClient.md#on)
+
+***
+
+### open()
+
+> **open**(`inactivePingIntervalMS`): `Promise`\<`MessageChannel`\>
+
+Open the MessageChannel.
+
+#### Parameters
+
+##### inactivePingIntervalMS
+
+`number` = `10000`
+
+The interval in milliseconds to send an inactive ping.
+
+#### Returns
+
+`Promise`\<`MessageChannel`\>
+
+***
+
+### publish()
+
+> **publish**(): `Promise`\<`MessageChannel`\>
+
+Publish the MediaStream to the server.
+
+#### Returns
+
+`Promise`\<`MessageChannel`\>
+
+#### Overrides
+
+[`WHIPClient`](WHIPClient.md).[`publish`](WHIPClient.md#publish)
+
+***
+
+### send()
+
+> **send**(`methodName`, `data`): `Promise`\<`undefined` \| `boolean`\>
+
+Send a JSON message to the server over the data channel.
+ - Overrides the send method in the WHIPClient class to properly wrap the data in a message object with methodName.
+
+#### Parameters
+
+##### methodName
+
+`string`
+
+The name of the method to send.
+
+##### data
+
+`any`
+
+The data to send.
+
+#### Returns
+
+`Promise`\<`undefined` \| `boolean`\>
+
+#### Overrides
+
+[`WHIPClient`](WHIPClient.md).[`send`](WHIPClient.md#send)
+
+***
+
+### sendData()
+
+> **sendData**(`data`): `Promise`\<`boolean`\>
+
+Send data to the server over the data channel.
+
+#### Parameters
+
+##### data
+
+`any`
+
+The data to send. Can be of any type, such as an arraybuffer.
+
+#### Returns
+
+`Promise`\<`boolean`\>
+
+***
+
+### sendLog()
+
+> **sendLog**(`level`, `message`): `void`
+
+Send a log message to the server.
+
+#### Parameters
+
+##### level
+
+`string`
+
+The level of the log message.
+
+##### message
+
+`any`
+
+The message to send.
+
+#### Returns
+
+`void`
+
+#### Inherited from
+
+[`WHIPClient`](WHIPClient.md).[`sendLog`](WHIPClient.md#sendlog)
+
+***
+
+### sendMessage()
+
+> **sendMessage**(`message`): `Promise`\<`boolean`\>
+
+Send a message to the server over the data channel. This will attempt to wrap and send the message as a JSON payload.
+
+#### Parameters
+
+##### message
+
+`any`
+
+The message to send.
+
+#### Returns
+
+`Promise`\<`boolean`\>
+
+#### See
+
+[sendData](#senddata) for sending raw data to the server over the data channel.
+
+***
+
+### sendPubNub()
+
+> **sendPubNub**(`channel`, `message`): `Promise`\<`boolean`\>
+
+Send a message to the PubNub channel.
+
+#### Parameters
+
+##### channel
+
+`string`
+
+The channel to send the message to.
+
+##### message
+
+`any`
+
+The message to send.
+
+#### Returns
+
+`Promise`\<`boolean`\>
+
+#### Inherited from
+
+[`WHIPClient`](WHIPClient.md).[`sendPubNub`](WHIPClient.md#sendpubnub)
+
+***
+
+### subscribePubNub()
+
+> **subscribePubNub**(`channel`, `options`): `Promise`\<`boolean`\>
+
+Subscribe to a PubNub channel.
+
+#### Parameters
+
+##### channel
+
+`string`
+
+The channel to subscribe to.
+
+##### options
+
+`any`
+
+The options to use for subscription.
+
+#### Returns
+
+`Promise`\<`boolean`\>
+
+#### Inherited from
+
+[`WHIPClient`](WHIPClient.md).[`subscribePubNub`](WHIPClient.md#subscribepubnub)
+
+***
+
+### trigger()
+
+> **trigger**(`event`): `void`
+
+Trigger an event on the MessageChannel.
+
+#### Parameters
+
+##### event
+
+[`Event`](Event.md)
+
+The event to trigger.
+ - Overrides the trigger method in the WHIPClient class to properly trigger the event on the MessageChannel.
+
+#### Returns
+
+`void`
+
+#### Overrides
+
+[`WHIPClient`](WHIPClient.md).[`trigger`](WHIPClient.md#trigger)
+
+***
+
+### unmonitorStats()
+
+> **unmonitorStats**(): [`WHIPClient`](WHIPClient.md)
+
+Unmonitor the statistics of the MediaStream being published to the server over the underlying RTCPeerConnection.
+
+#### Returns
+
+[`WHIPClient`](WHIPClient.md)
+
+#### Inherited from
+
+[`WHIPClient`](WHIPClient.md).[`unmonitorStats`](WHIPClient.md#unmonitorstats)
+
+***
+
+### unmuteAudio()
+
+> **unmuteAudio**(): `void`
+
+Unmute the audio being published to the server.
+
+#### Returns
+
+`void`
+
+#### Inherited from
+
+[`WHIPClient`](WHIPClient.md).[`unmuteAudio`](WHIPClient.md#unmuteaudio)
+
+***
+
+### unmuteVideo()
+
+> **unmuteVideo**(): `void`
+
+Unmute the video being published to the server.
+
+#### Returns
+
+`void`
+
+#### Inherited from
+
+[`WHIPClient`](WHIPClient.md).[`unmuteVideo`](WHIPClient.md#unmutevideo)
+
+***
+
+### unpublish()
+
+> **unpublish**(): `Promise`\<`void`\>
+
+Unpublish the MediaStream from the server.
+
+#### Returns
+
+`Promise`\<`void`\>
+
+#### Overrides
+
+[`WHIPClient`](WHIPClient.md).[`unpublish`](WHIPClient.md#unpublish)
+
+***
+
+### unsubscribePubNub()
+
+> **unsubscribePubNub**(`channel`): `Promise`\<`boolean`\>
+
+Unsubscribe from a PubNub channel.
+
+#### Parameters
+
+##### channel
+
+`string`
+
+The channel to unsubscribe from.
+
+#### Returns
+
+`Promise`\<`boolean`\>
+
+#### Inherited from
+
+[`WHIPClient`](WHIPClient.md).[`unsubscribePubNub`](WHIPClient.md#unsubscribepubnub)
diff --git a/static/lib/red5pro/docs/api/classes/MessageChannelEvent.md b/static/lib/red5pro/docs/api/classes/MessageChannelEvent.md
new file mode 100644
index 00000000..7d527765
--- /dev/null
+++ b/static/lib/red5pro/docs/api/classes/MessageChannelEvent.md
@@ -0,0 +1,99 @@
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
+
+***
+
+[Red5 Pro WebRTC SDK](../globals.md) / MessageChannelEvent
+
+# Class: MessageChannelEvent
+
+Event for a MessageChannel within the Red5 Pro WebRTC SDK.
+
+## Extends
+
+- [`Event`](Event.md)
+
+## Constructors
+
+### Constructor
+
+> **new MessageChannelEvent**(`type`, `messageChannel`, `data?`): `MessageChannelEvent`
+
+Constructor for a MessageChannelEvent.
+
+#### Parameters
+
+##### type
+
+`string`
+
+The type of event.
+
+##### messageChannel
+
+`any`
+
+The message channel (MessageChannel) that triggered the event.
+
+##### data?
+
+`any`
+
+The data associated with the event.
+
+#### Returns
+
+`MessageChannelEvent`
+
+#### Overrides
+
+[`Event`](Event.md).[`constructor`](Event.md#constructor)
+
+## Accessors
+
+### data
+
+#### Get Signature
+
+> **get** **data**(): `any`
+
+Get the data associated with the event.
+
+##### Returns
+
+`any`
+
+#### Inherited from
+
+[`Event`](Event.md).[`data`](Event.md#data)
+
+***
+
+### messageChannel
+
+#### Get Signature
+
+> **get** **messageChannel**(): `any`
+
+Get the message channel (MessageChannel) that triggered the event.
+
+##### Returns
+
+`any`
+
+***
+
+### type
+
+#### Get Signature
+
+> **get** **type**(): `string`
+
+Get the type of event.
+
+##### Returns
+
+`string`
+
+#### Inherited from
+
+[`Event`](Event.md).[`type`](Event.md#type)
diff --git a/static/lib/red5pro/docs/api/classes/MessageTransportStateEvent.md b/static/lib/red5pro/docs/api/classes/MessageTransportStateEvent.md
index e1a8e1d8..f203b707 100644
--- a/static/lib/red5pro/docs/api/classes/MessageTransportStateEvent.md
+++ b/static/lib/red5pro/docs/api/classes/MessageTransportStateEvent.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/classes/PlaybackController.md b/static/lib/red5pro/docs/api/classes/PlaybackController.md
index 59facc2b..8e3b228b 100644
--- a/static/lib/red5pro/docs/api/classes/PlaybackController.md
+++ b/static/lib/red5pro/docs/api/classes/PlaybackController.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/classes/PlaybackControls.md b/static/lib/red5pro/docs/api/classes/PlaybackControls.md
index b0dda0c6..3d040d00 100644
--- a/static/lib/red5pro/docs/api/classes/PlaybackControls.md
+++ b/static/lib/red5pro/docs/api/classes/PlaybackControls.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/classes/PubNubClient.md b/static/lib/red5pro/docs/api/classes/PubNubClient.md
index 6424e4c5..b890a305 100644
--- a/static/lib/red5pro/docs/api/classes/PubNubClient.md
+++ b/static/lib/red5pro/docs/api/classes/PubNubClient.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/classes/PubNubEvent.md b/static/lib/red5pro/docs/api/classes/PubNubEvent.md
new file mode 100644
index 00000000..154b03bc
--- /dev/null
+++ b/static/lib/red5pro/docs/api/classes/PubNubEvent.md
@@ -0,0 +1,99 @@
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
+
+***
+
+[Red5 Pro WebRTC SDK](../globals.md) / PubNubEvent
+
+# Class: PubNubEvent
+
+Event for a PubNub within the Red5 Pro WebRTC SDK.
+
+## Extends
+
+- [`Event`](Event.md)
+
+## Constructors
+
+### Constructor
+
+> **new PubNubEvent**(`type`, `pubnub`, `data?`): `PubNubEvent`
+
+Constructor for a PubNubEvent.
+
+#### Parameters
+
+##### type
+
+`string`
+
+The type of event.
+
+##### pubnub
+
+`any`
+
+The pubnub (PubNubClient) that triggered the event.
+
+##### data?
+
+`any`
+
+The data associated with the event.
+
+#### Returns
+
+`PubNubEvent`
+
+#### Overrides
+
+[`Event`](Event.md).[`constructor`](Event.md#constructor)
+
+## Accessors
+
+### data
+
+#### Get Signature
+
+> **get** **data**(): `any`
+
+Get the data associated with the event.
+
+##### Returns
+
+`any`
+
+#### Inherited from
+
+[`Event`](Event.md).[`data`](Event.md#data)
+
+***
+
+### pubnub
+
+#### Get Signature
+
+> **get** **pubnub**(): `any`
+
+Get the pubnub (PubNubClient) that triggered the event.
+
+##### Returns
+
+`any`
+
+***
+
+### type
+
+#### Get Signature
+
+> **get** **type**(): `string`
+
+Get the type of event.
+
+##### Returns
+
+`string`
+
+#### Inherited from
+
+[`Event`](Event.md).[`type`](Event.md#type)
diff --git a/static/lib/red5pro/docs/api/classes/PublisherEvent.md b/static/lib/red5pro/docs/api/classes/PublisherEvent.md
index ab087443..4475bd48 100644
--- a/static/lib/red5pro/docs/api/classes/PublisherEvent.md
+++ b/static/lib/red5pro/docs/api/classes/PublisherEvent.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/classes/SourceHandler.md b/static/lib/red5pro/docs/api/classes/SourceHandler.md
index 713d1af3..297ba19a 100644
--- a/static/lib/red5pro/docs/api/classes/SourceHandler.md
+++ b/static/lib/red5pro/docs/api/classes/SourceHandler.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/classes/SourceHandlerImpl.md b/static/lib/red5pro/docs/api/classes/SourceHandlerImpl.md
index 7e3b38ed..ae4d2332 100644
--- a/static/lib/red5pro/docs/api/classes/SourceHandlerImpl.md
+++ b/static/lib/red5pro/docs/api/classes/SourceHandlerImpl.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/classes/SubscriberEvent.md b/static/lib/red5pro/docs/api/classes/SubscriberEvent.md
index b9a85f87..ffb82911 100644
--- a/static/lib/red5pro/docs/api/classes/SubscriberEvent.md
+++ b/static/lib/red5pro/docs/api/classes/SubscriberEvent.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/classes/WHEPClient.md b/static/lib/red5pro/docs/api/classes/WHEPClient.md
index e84858c4..c180f61b 100644
--- a/static/lib/red5pro/docs/api/classes/WHEPClient.md
+++ b/static/lib/red5pro/docs/api/classes/WHEPClient.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
@@ -479,7 +479,7 @@ The time to seek to.
### send()
-> **send**(`methodName`, `data`): `undefined` \| `Promise`\<`boolean`\>
+> **send**(`methodName`, `data`): `Promise`\<`undefined` \| `boolean`\>
Send a message to the Red5 Pro Server over the message transport (DataChannel).
@@ -499,7 +499,7 @@ The data to send.
#### Returns
-`undefined` \| `Promise`\<`boolean`\>
+`Promise`\<`undefined` \| `boolean`\>
***
diff --git a/static/lib/red5pro/docs/api/classes/WHIPClient.md b/static/lib/red5pro/docs/api/classes/WHIPClient.md
index a1a254dc..634c3377 100644
--- a/static/lib/red5pro/docs/api/classes/WHIPClient.md
+++ b/static/lib/red5pro/docs/api/classes/WHIPClient.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
@@ -15,6 +15,10 @@ This provides a standardized - and _blazingly fast_ - way to establish and publi
- [`EventEmitter`](EventEmitter.md)
+## Extended by
+
+- [`MessageChannel`](MessageChannel.md)
+
## Constructors
### Constructor
@@ -376,7 +380,7 @@ The name of the stream to publish.
### send()
-> **send**(`methodName`, `data`): `undefined` \| `Promise`\<`boolean`\>
+> **send**(`methodName`, `data`): `Promise`\<`undefined` \| `boolean`\>
Send a message to the server.
@@ -396,7 +400,7 @@ The data to send.
#### Returns
-`undefined` \| `Promise`\<`boolean`\>
+`Promise`\<`undefined` \| `boolean`\>
***
diff --git a/static/lib/red5pro/docs/api/enumerations/MessageChannelEventTypes.md b/static/lib/red5pro/docs/api/enumerations/MessageChannelEventTypes.md
new file mode 100644
index 00000000..0342417e
--- /dev/null
+++ b/static/lib/red5pro/docs/api/enumerations/MessageChannelEventTypes.md
@@ -0,0 +1,43 @@
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
+
+***
+
+[Red5 Pro WebRTC SDK](../globals.md) / MessageChannelEventTypes
+
+# Enumeration: MessageChannelEventTypes
+
+## Enumeration Members
+
+### CLOSE
+
+> **CLOSE**: `"MessageChannel.Close"`
+
+***
+
+### ERROR
+
+> **ERROR**: `"MessageChannel.Error"`
+
+***
+
+### FAIL
+
+> **FAIL**: `"MessageChannel.Fail"`
+
+***
+
+### OPEN
+
+> **OPEN**: `"MessageChannel.Open"`
+
+***
+
+### RECEIVE
+
+> **RECEIVE**: `"MessageChannel.Receive"`
+
+***
+
+### SEND
+
+> **SEND**: `"MessageChannel.Send"`
diff --git a/static/lib/red5pro/docs/api/enumerations/MessageTransportStateEventTypes.md b/static/lib/red5pro/docs/api/enumerations/MessageTransportStateEventTypes.md
index 579dddaf..d8584a60 100644
--- a/static/lib/red5pro/docs/api/enumerations/MessageTransportStateEventTypes.md
+++ b/static/lib/red5pro/docs/api/enumerations/MessageTransportStateEventTypes.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/enumerations/PlaybackAudioEncoder.md b/static/lib/red5pro/docs/api/enumerations/PlaybackAudioEncoder.md
index a8c3b08e..7c112748 100644
--- a/static/lib/red5pro/docs/api/enumerations/PlaybackAudioEncoder.md
+++ b/static/lib/red5pro/docs/api/enumerations/PlaybackAudioEncoder.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/enumerations/PlaybackState.md b/static/lib/red5pro/docs/api/enumerations/PlaybackState.md
index 7d2454d5..b23a02a3 100644
--- a/static/lib/red5pro/docs/api/enumerations/PlaybackState.md
+++ b/static/lib/red5pro/docs/api/enumerations/PlaybackState.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/enumerations/PlaybackVideoEncoder.md b/static/lib/red5pro/docs/api/enumerations/PlaybackVideoEncoder.md
index 3dd40424..d667f685 100644
--- a/static/lib/red5pro/docs/api/enumerations/PlaybackVideoEncoder.md
+++ b/static/lib/red5pro/docs/api/enumerations/PlaybackVideoEncoder.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/enumerations/PublishAudioEncoder.md b/static/lib/red5pro/docs/api/enumerations/PublishAudioEncoder.md
index 983e3fb6..1077aecd 100644
--- a/static/lib/red5pro/docs/api/enumerations/PublishAudioEncoder.md
+++ b/static/lib/red5pro/docs/api/enumerations/PublishAudioEncoder.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/enumerations/PublishVideoEncoder.md b/static/lib/red5pro/docs/api/enumerations/PublishVideoEncoder.md
index e4c0833e..7ce889a3 100644
--- a/static/lib/red5pro/docs/api/enumerations/PublishVideoEncoder.md
+++ b/static/lib/red5pro/docs/api/enumerations/PublishVideoEncoder.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/enumerations/PublisherEventTypes.md b/static/lib/red5pro/docs/api/enumerations/PublisherEventTypes.md
index e8c7c0b4..62f8c982 100644
--- a/static/lib/red5pro/docs/api/enumerations/PublisherEventTypes.md
+++ b/static/lib/red5pro/docs/api/enumerations/PublisherEventTypes.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/enumerations/RTCPublisherEventTypes.md b/static/lib/red5pro/docs/api/enumerations/RTCPublisherEventTypes.md
index bac86223..e4cd2256 100644
--- a/static/lib/red5pro/docs/api/enumerations/RTCPublisherEventTypes.md
+++ b/static/lib/red5pro/docs/api/enumerations/RTCPublisherEventTypes.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/enumerations/RTCSubscriberEventTypes.md b/static/lib/red5pro/docs/api/enumerations/RTCSubscriberEventTypes.md
index 6e5a6cf2..8bf741b6 100644
--- a/static/lib/red5pro/docs/api/enumerations/RTCSubscriberEventTypes.md
+++ b/static/lib/red5pro/docs/api/enumerations/RTCSubscriberEventTypes.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/enumerations/StatsEndpointType.md b/static/lib/red5pro/docs/api/enumerations/StatsEndpointType.md
index 9cfb6969..7001f532 100644
--- a/static/lib/red5pro/docs/api/enumerations/StatsEndpointType.md
+++ b/static/lib/red5pro/docs/api/enumerations/StatsEndpointType.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/enumerations/SubscriberEventTypes.md b/static/lib/red5pro/docs/api/enumerations/SubscriberEventTypes.md
index c626c2bd..7b6da984 100644
--- a/static/lib/red5pro/docs/api/enumerations/SubscriberEventTypes.md
+++ b/static/lib/red5pro/docs/api/enumerations/SubscriberEventTypes.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/functions/getRecordedLogs.md b/static/lib/red5pro/docs/api/functions/getRecordedLogs.md
index 762a2896..813f1215 100644
--- a/static/lib/red5pro/docs/api/functions/getRecordedLogs.md
+++ b/static/lib/red5pro/docs/api/functions/getRecordedLogs.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/functions/getVersion.md b/static/lib/red5pro/docs/api/functions/getVersion.md
index 915d5ff8..1c83a7e0 100644
--- a/static/lib/red5pro/docs/api/functions/getVersion.md
+++ b/static/lib/red5pro/docs/api/functions/getVersion.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/functions/setLogLevel.md b/static/lib/red5pro/docs/api/functions/setLogLevel.md
index 687c2c7a..ada7e171 100644
--- a/static/lib/red5pro/docs/api/functions/setLogLevel.md
+++ b/static/lib/red5pro/docs/api/functions/setLogLevel.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/globals.md b/static/lib/red5pro/docs/api/globals.md
index f2d1ac64..e733c883 100644
--- a/static/lib/red5pro/docs/api/globals.md
+++ b/static/lib/red5pro/docs/api/globals.md
@@ -1,13 +1,14 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](README.md)
***
-# Red5 Pro WebRTC SDK v15.2.0
+# Red5 Pro WebRTC SDK v15.3.0
Red5 Pro WebRTC SDK
## Enumerations
+- [MessageChannelEventTypes](enumerations/MessageChannelEventTypes.md)
- [MessageTransportStateEventTypes](enumerations/MessageTransportStateEventTypes.md)
- [PlaybackAudioEncoder](enumerations/PlaybackAudioEncoder.md)
- [PlaybackState](enumerations/PlaybackState.md)
@@ -26,11 +27,14 @@ Red5 Pro WebRTC SDK
- [EventEmitter](classes/EventEmitter.md)
- [HLSSubscriber](classes/HLSSubscriber.md)
- [LiveSeekClient](classes/LiveSeekClient.md)
+- [MessageChannel](classes/MessageChannel.md)
+- [MessageChannelEvent](classes/MessageChannelEvent.md)
- [MessageTransportStateEvent](classes/MessageTransportStateEvent.md)
- [PlaybackController](classes/PlaybackController.md)
- [PlaybackControls](classes/PlaybackControls.md)
- [PublisherEvent](classes/PublisherEvent.md)
- [PubNubClient](classes/PubNubClient.md)
+- [PubNubEvent](classes/PubNubEvent.md)
- [SourceHandler](classes/SourceHandler.md)
- [SourceHandlerImpl](classes/SourceHandlerImpl.md)
- [SubscriberEvent](classes/SubscriberEvent.md)
@@ -58,6 +62,7 @@ Red5 Pro WebRTC SDK
## Variables
+- [Capability](variables/Capability.md)
- [default](variables/default.md)
- [defaultHLSSubscriberConfig](variables/defaultHLSSubscriberConfig.md)
- [defaultLiveSeekConfig](variables/defaultLiveSeekConfig.md)
diff --git a/static/lib/red5pro/docs/api/interfaces/EventEmitterInterface.md b/static/lib/red5pro/docs/api/interfaces/EventEmitterInterface.md
index 3a14c528..466cc348 100644
--- a/static/lib/red5pro/docs/api/interfaces/EventEmitterInterface.md
+++ b/static/lib/red5pro/docs/api/interfaces/EventEmitterInterface.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/type-aliases/BandwidthConfig.md b/static/lib/red5pro/docs/api/type-aliases/BandwidthConfig.md
index 1abed477..a84a99e6 100644
--- a/static/lib/red5pro/docs/api/type-aliases/BandwidthConfig.md
+++ b/static/lib/red5pro/docs/api/type-aliases/BandwidthConfig.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/type-aliases/HLSSubscriberConfigType.md b/static/lib/red5pro/docs/api/type-aliases/HLSSubscriberConfigType.md
index 0bfea2f7..16ebf0ee 100644
--- a/static/lib/red5pro/docs/api/type-aliases/HLSSubscriberConfigType.md
+++ b/static/lib/red5pro/docs/api/type-aliases/HLSSubscriberConfigType.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/type-aliases/LiveSeekConfigType.md b/static/lib/red5pro/docs/api/type-aliases/LiveSeekConfigType.md
index b8390ebd..c2a9dd84 100644
--- a/static/lib/red5pro/docs/api/type-aliases/LiveSeekConfigType.md
+++ b/static/lib/red5pro/docs/api/type-aliases/LiveSeekConfigType.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/type-aliases/LiveSeekOptions.md b/static/lib/red5pro/docs/api/type-aliases/LiveSeekOptions.md
index afce9216..f08201c1 100644
--- a/static/lib/red5pro/docs/api/type-aliases/LiveSeekOptions.md
+++ b/static/lib/red5pro/docs/api/type-aliases/LiveSeekOptions.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/type-aliases/MediaConstraintRange.md b/static/lib/red5pro/docs/api/type-aliases/MediaConstraintRange.md
index bfab138e..f6ac7e20 100644
--- a/static/lib/red5pro/docs/api/type-aliases/MediaConstraintRange.md
+++ b/static/lib/red5pro/docs/api/type-aliases/MediaConstraintRange.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/type-aliases/MediaConstraints.md b/static/lib/red5pro/docs/api/type-aliases/MediaConstraints.md
index 333fef12..e7e56194 100644
--- a/static/lib/red5pro/docs/api/type-aliases/MediaConstraints.md
+++ b/static/lib/red5pro/docs/api/type-aliases/MediaConstraints.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/type-aliases/RTCPublisherConfigType.md b/static/lib/red5pro/docs/api/type-aliases/RTCPublisherConfigType.md
index 27f26a2e..5e8bcba1 100644
--- a/static/lib/red5pro/docs/api/type-aliases/RTCPublisherConfigType.md
+++ b/static/lib/red5pro/docs/api/type-aliases/RTCPublisherConfigType.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/type-aliases/RTCSubscriberConfigType.md b/static/lib/red5pro/docs/api/type-aliases/RTCSubscriberConfigType.md
index e75f194d..64f592b9 100644
--- a/static/lib/red5pro/docs/api/type-aliases/RTCSubscriberConfigType.md
+++ b/static/lib/red5pro/docs/api/type-aliases/RTCSubscriberConfigType.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/type-aliases/RTCWhepSubscriberConfigType.md b/static/lib/red5pro/docs/api/type-aliases/RTCWhepSubscriberConfigType.md
index f01410d6..d10c7bc1 100644
--- a/static/lib/red5pro/docs/api/type-aliases/RTCWhepSubscriberConfigType.md
+++ b/static/lib/red5pro/docs/api/type-aliases/RTCWhepSubscriberConfigType.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/type-aliases/RTCWhipPublisherConfigType.md b/static/lib/red5pro/docs/api/type-aliases/RTCWhipPublisherConfigType.md
index 4845ca4c..06457f60 100644
--- a/static/lib/red5pro/docs/api/type-aliases/RTCWhipPublisherConfigType.md
+++ b/static/lib/red5pro/docs/api/type-aliases/RTCWhipPublisherConfigType.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/type-aliases/StatsConfig.md b/static/lib/red5pro/docs/api/type-aliases/StatsConfig.md
index 73cf3734..7971e60b 100644
--- a/static/lib/red5pro/docs/api/type-aliases/StatsConfig.md
+++ b/static/lib/red5pro/docs/api/type-aliases/StatsConfig.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/type-aliases/VideoConstraints.md b/static/lib/red5pro/docs/api/type-aliases/VideoConstraints.md
index fb6f39d0..6294fcb3 100644
--- a/static/lib/red5pro/docs/api/type-aliases/VideoConstraints.md
+++ b/static/lib/red5pro/docs/api/type-aliases/VideoConstraints.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/variables/Capability.md b/static/lib/red5pro/docs/api/variables/Capability.md
new file mode 100644
index 00000000..767ff411
--- /dev/null
+++ b/static/lib/red5pro/docs/api/variables/Capability.md
@@ -0,0 +1,19 @@
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
+
+***
+
+[Red5 Pro WebRTC SDK](../globals.md) / Capability
+
+# Variable: Capability
+
+> `const` **Capability**: `object`
+
+## Type Declaration
+
+### datachannel
+
+> `readonly` **datachannel**: `4` = `4`
+
+### stream
+
+> `readonly` **stream**: `3` = `3`
diff --git a/static/lib/red5pro/docs/api/variables/LOG_LEVELS.md b/static/lib/red5pro/docs/api/variables/LOG_LEVELS.md
index b2b83744..7f2e9c62 100644
--- a/static/lib/red5pro/docs/api/variables/LOG_LEVELS.md
+++ b/static/lib/red5pro/docs/api/variables/LOG_LEVELS.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/variables/PlaybackStateReadableMap.md b/static/lib/red5pro/docs/api/variables/PlaybackStateReadableMap.md
index ee043b40..159cc85f 100644
--- a/static/lib/red5pro/docs/api/variables/PlaybackStateReadableMap.md
+++ b/static/lib/red5pro/docs/api/variables/PlaybackStateReadableMap.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/variables/default.md b/static/lib/red5pro/docs/api/variables/default.md
index 1abc0e35..d769e772 100644
--- a/static/lib/red5pro/docs/api/variables/default.md
+++ b/static/lib/red5pro/docs/api/variables/default.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
@@ -10,6 +10,18 @@
## Type Declaration
+### Capability
+
+> **Capability**: `object`
+
+#### Capability.datachannel
+
+> `readonly` **datachannel**: `4` = `4`
+
+#### Capability.stream
+
+> `readonly` **stream**: `3` = `3`
+
### defaultStatsConfig
> **defaultStatsConfig**: [`StatsConfig`](../type-aliases/StatsConfig.md)
@@ -80,6 +92,18 @@ Get the version of the SDK.
> `readonly` **WARN**: `"warn"` = `'warn'`
+### MessageChannel
+
+> **MessageChannel**: *typeof* [`MessageChannel`](../classes/MessageChannel.md)
+
+### MessageChannelEvent
+
+> **MessageChannelEvent**: *typeof* [`MessageChannelEvent`](../classes/MessageChannelEvent.md)
+
+### MessageChannelEventTypes
+
+> **MessageChannelEventTypes**: *typeof* [`MessageChannelEventTypes`](../enumerations/MessageChannelEventTypes.md)
+
### MessageTransportStateEvent
> **MessageTransportStateEvent**: *typeof* [`MessageTransportStateEvent`](../classes/MessageTransportStateEvent.md)
@@ -146,7 +170,7 @@ Get the version of the SDK.
### PubNubEvent
-> **PubNubEvent**: *typeof* `PubNubEvent`
+> **PubNubEvent**: *typeof* [`PubNubEvent`](../classes/PubNubEvent.md)
### PubNubEventTypes
diff --git a/static/lib/red5pro/docs/api/variables/defaultHLSSubscriberConfig.md b/static/lib/red5pro/docs/api/variables/defaultHLSSubscriberConfig.md
index e52e10a0..234fd110 100644
--- a/static/lib/red5pro/docs/api/variables/defaultHLSSubscriberConfig.md
+++ b/static/lib/red5pro/docs/api/variables/defaultHLSSubscriberConfig.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/variables/defaultLiveSeekConfig.md b/static/lib/red5pro/docs/api/variables/defaultLiveSeekConfig.md
index e247db57..c89b834a 100644
--- a/static/lib/red5pro/docs/api/variables/defaultLiveSeekConfig.md
+++ b/static/lib/red5pro/docs/api/variables/defaultLiveSeekConfig.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/variables/defaultStatsConfig.md b/static/lib/red5pro/docs/api/variables/defaultStatsConfig.md
index cd33dabe..f82689ac 100644
--- a/static/lib/red5pro/docs/api/variables/defaultStatsConfig.md
+++ b/static/lib/red5pro/docs/api/variables/defaultStatsConfig.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/variables/defaultWhepSubscriberConfig.md b/static/lib/red5pro/docs/api/variables/defaultWhepSubscriberConfig.md
index 6070df32..1b40f1d7 100644
--- a/static/lib/red5pro/docs/api/variables/defaultWhepSubscriberConfig.md
+++ b/static/lib/red5pro/docs/api/variables/defaultWhepSubscriberConfig.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/api/variables/defaultWhipPublisherConfig.md b/static/lib/red5pro/docs/api/variables/defaultWhipPublisherConfig.md
index aff1884b..d538a5f0 100644
--- a/static/lib/red5pro/docs/api/variables/defaultWhipPublisherConfig.md
+++ b/static/lib/red5pro/docs/api/variables/defaultWhipPublisherConfig.md
@@ -1,4 +1,4 @@
-[**Red5 Pro WebRTC SDK v15.2.0**](../README.md)
+[**Red5 Pro WebRTC SDK v15.3.0**](../README.md)
***
diff --git a/static/lib/red5pro/docs/hls-subscriber.md b/static/lib/red5pro/docs/hls-subscriber.md
index 3df6097a..f61265d9 100644
--- a/static/lib/red5pro/docs/hls-subscriber.md
+++ b/static/lib/red5pro/docs/hls-subscriber.md
@@ -5,6 +5,7 @@
Quick Start •
Publishing •
Subscribing •
+ Message Channel •
PubNub Client
diff --git a/static/lib/red5pro/docs/message-channel.md b/static/lib/red5pro/docs/message-channel.md
new file mode 100644
index 00000000..bb300c4d
--- /dev/null
+++ b/static/lib/red5pro/docs/message-channel.md
@@ -0,0 +1,283 @@
+
+
+
+
+ Quick Start •
+ Publishing •
+ Subscribing •
+ Message Channel •
+ PubNub Client
+
+
+---
+
+# MessageChannel
+
+The `MessageChannel` client is an ingest-based (read: "broadcast") client that extends `WHIPClient` as its underlying framework and capabilities are very similar, with the differing aspect of `MessageChannel` not supporting any media streaming.
+
+## A Note on WHIP/WHEP & DataChannel
+
+It should be noted if that `WHIPClient` and `WHEPClient` - used for publishing and subscribing streams, respectively - by default, include a messaging channel (a.k.a., `DataChannel`) through their underlying `RTCPeerConnection`.
+
+Due to these clients' streaming nature, that underlying messaging channel will be closed once the respective stream is closed - meaning the messaging channel will not remain open if not broadcasting or consuming a stream.
+
+In most cases, this is common scenario. However, if you would like to maintain a messaging channel _along-side_ a streaming client, you can utilize the `MessageChannel` client.
+
+> Be aware that since the `MessageChannel` is not inherently associated with a stream, synchronizations between messages and any associative, external streams will not be available.
+
+* [Usage](#usage)
+* [Init Configuration](#init-configuration)
+* [Send API](#send-api)
+* [Events](#events)
+* [Statistics](#statistics)
+* [Stream Manager 2.0](#stream-manager-20)
+
+# Usage
+
+Because `MessageChannel` is a subclass of `WHIPClient` (the media streaming broadcaster), much of the init setup and event structure is similar.
+
+To create and use a `MessageChannel` client:
+
+```js
+let messageChannel
+try {
+ messageChannel = new MessageChannel()
+ messageChannel.on('*', , (event) => console.log(event))
+
+ // See next section: Init Configuration, for more details.
+ await messageChannel.init(configuration)
+ await messageChannel.open()
+} catch (error) {
+ // Something went wrong...
+}
+
+// ... when ready to close the connection ...
+messageChannel?.close()
+```
+
+## MessageChannel & the SDK
+
+Dependening on how you include the SDK into your project, you can access the `MessageClient` from the following:
+
+_NPM install_:
+
+```js
+import { MessageChannel } from 'red5pro-webrtc-sdk'
+```
+
+_Browser, CDN_:
+
+```js
+const { MessageChannel } = red5prosdk
+```
+
+> For more in-depth information related to usage, please refer to the [WHIPClient](whip-client.md#usage) documentation.
+
+# Init Configuration
+
+Because `MessageChannel` inherits from `WHIPClient`, its initialization configuration shares the same properties and structure, however many attributes will be ignored as they pertain to streaming media on a `WHIPClient` which have no regard to the role of a `MessageChannel`.
+
+The following properties are respected by the `MessageChannel` client:
+
+| Property | Required | Default | Description |
+| :--- | :---: | :---: | :--- |
+| `host` | [x] | *None* | The IP or address that the WebSocket server resides on. |
+| `streamName` | [x] | *None* | The name of the message channel to use in association. |
+| `protocol` | [x] | `https` | The protocol of the host for the signaling communication. |
+| `port` | [x] | `443` | The port on the host that the Red5 server listens on; `5080` or `443` (insecure or secure, respectively). |
+| `app` | [x] | `live` | The webapp context name that the stream is on. |
+| `endpoint` | [-] | `undefined` | The full URL of the endpoint to stream to. **This is primarily used in Stream Manager 2.0 integration for clients.**
+| `rtcConfiguration` | [-] | _Basic_ | The `RTCConfiguration` to use in setting up `RTCPeerConnection`. [RTCConfiguration](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/RTCPeerConnection#RTCConfiguration_dictionary)|
+| `dataChannelConfiguration` | [-] | `{name: "red5pro"}` | An object used in configuring a n `RTCDataChannel`. _Only used when `includeDataChannel` is defined as `true`_ |
+| `connectionParams` | [-] | `undefined` | An object of connection parameters to send to the server upon connection request. |
+
+## Init Example
+
+The following is an example of using the init configuration for a `MessageChannel` client on a Standalone deployment of the Red5 Server:
+
+```js
+try {
+ // If the standalone Red5 server is hosted over HTTPS, most other attributes can be left to default.
+ const configuration = {
+ host: 'mydeployment.red5.net',
+ streamName: `${uuid}-message-channel`,
+ dataChannelConfiguration: {
+ name: 'my-channel-name'
+ }
+ }
+ const messageChannel = new MessageChannel()
+ messageChannel.on('*', , (event) => console.log(event))
+ await messageChannel.init(configuration)
+ await messageChannel.open()
+} catch (error) {
+ // Something went wrong...
+}
+```
+
+# Send API
+
+The `MessageChannel` has a few options for broadcasting messages out to other clients connected to the channel:
+
+## send(methodName: string, data: any)
+
+The `send` method is an override of the `MessageChannel` underlying `WHIPClient` implementation. It essentially is an override to ensure the message data is delivered on other connected clients to the specified DataChannel.
+
+> The `data` is expected as either a string or an `Object` that can be serialized to JSON.
+
+## sendMessage(message: any)
+
+The `sendMessage` method is a convenience method of which the `send()` call invokes - delivering JSON data to all clients connected to the specified DataChannel
+
+> The `message` is expected as either a string or an `Object` that can be serialized to JSON.
+
+## sendData(data: any)
+
+The `sendData` method will attempt to send any type of data, untouched, along the DataChannel - as such, with it comes great power; use wisely.
+
+# Events
+
+Because `MessageChannel` inherits from `WHIPClient`, events unrelated to streaming - such as those related to the underlying WebRTC connection (e.g., `WebRTC.*`) - will be dispatched from `MessageChannel`.
+
+There are a few that are specific to `MessageChannel` that are available and enumerated on the `MessageChannelEventTypes` object:
+
+| Access | Event Type | Meaning |
+| :--- | :--- | :--- |
+| `OPEN` | 'MessageChannel.Open' | When the message channel has successfully opened and available to send and receive messages. |
+| `SEND` | 'MessageChannel.Send' | When the message channel has sent a message along the message channel. _Note: This is not confirmation that the server received the actual message._ |
+| `RECEIVE` | 'MessageChannel.Receive' | When the message channel has received a message. |
+| `CLOSE` | 'MessageChannel.Close' | When the message channel has been closed. |
+| `FAIL` | 'MessageChannel.Fail' | When the message channel has failed to open properly. |
+| `ERROR` | 'MessageChannel.Error' | When an error has occurred in opening or during a message channel session. |
+
+> Please visit the [WHIPClient](whip-client.md#events) documentation for more in-depth listing of events.
+
+# Statistics
+
+Similar to being able to monitor for statistics on the underlying `RTCPeerConnection` of other clients from the SDK, statistics related to the `MessageChannel` can be monitored as well - though the data gathered will pertain mostly to the connection and `data-channel`.
+
+## Stats Configuration
+
+The configuration used for statistics monitoring has the following structure:
+
+```js
+{
+ // Optional.
+ // If provided, it will POST stats to this endpoint.
+ // If undefined or `data-channel`, it will post stats to message transport.
+ // If null or `event-transport`, it will only emit status events.
+ endpoint: red5prosdk.StatsEndpointType.DATA_CHANNEL,
+ additionalHeaders: undefined,
+ interval: 5000, // Interval to poll stats, in milliseconds.
+ include: [], // Empty array allows SDK to be judicious about what stats to include.
+}
+```
+
+### endpoint
+
+* If the `endpoint` is defined with a URL, the SDK will attempt to make `POST` requests with a JSON body representing each individual report.
+* If the `endpoint` is set to `data-channel` or `undefined`, the SDK will post metadata with type `stats-report` on the underlying message transport (DataChannel) if available.
+* If the `endpoint` is set to `event-transport` or `null`, the SDK will only emit events with the metadata on the `WebRTC.StatsReport` event.
+
+### additionalHeaders
+
+By default, if an `endpoint` is defined, the `POST` request body will be in JSON and have the `{ 'Content-Type': 'application/json' }` header set. If requirements - such as authentication - are required, a map of additional headers can be provided to be sent along with the request.
+
+### interval
+
+The polling interval (in milliseconds) to access the `RTCStatsReport` from the underlying `RTCPeerConnection` of the publisher client.
+
+### include
+
+An array of static type strings. These directly map to the listing of type available for `RTCStatsReport` objects. If left empty or undefined, the SDK will report the statistics it deems suitable for tracking proper broadcast conditions.
+
+e.g.,
+
+```js
+include: ['data-channel', 'transport']
+```
+
+> More information about the statistic types are available at [https://developer.mozilla.org/en-US/docs/Web/API/RTCStatsReport#the_statistic_types](https://developer.mozilla.org/en-US/docs/Web/API/RTCStatsReport#the_statistic_types)
+
+## Invocation
+
+To start statistics monitoring, you have a couple of options:
+
+* You can provide a `stats` attribute with the [stats configuration object](#stats-configuration) to the [init configuration](#webrtc-configuration-parameters).
+* You can call `monitorStats` on the publisher client with the optional [stats configuration object](#stats-configuration) parameter.
+
+> Additionally, you can stop monitoring by calling `unmonitorStats` on the publisher client.
+
+## Additional Information
+
+Attached to the metadata that is reported are additional properties that pertain to the publisher client.
+
+As well, Along with the metadata releated to the `RTCStatsReport` objects emitted by the underlying `RTCPeerConnection`, the statistics monitoring also sends out a few event and action metadata related to the operation of a publisher client.
+
+> See the following section for examples.
+
+## Example of Statistics Metadata
+
+The following is an example of a statistics metadata that is emitted in a `WebRTC.StatsReport` event and POSTed to any defined optional endpoint:
+
+```json
+{
+ "name": "MessageChannelStats",
+ "created": 1771514183637,
+ "fingerprint": "165799de-87ac-4c13-95d3-66c7512080fe",
+ "device": {
+ "appVersion": "5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36",
+ "platform": "MacIntel",
+ "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36",
+ "vendor": "Google Inc."
+ },
+ "client": {
+ "host": "myred5.deploy",
+ "streamName": "dc-1771514183635",
+ "connectionParams": {
+ "capabilities": 4
+ }
+ },
+ "publicIP": "174.169.251.174",
+ "type": "stats-report",
+ "timestamp": 1771514658751,
+ "data": {
+ "id": "D159",
+ "timestamp": 1771514658751.39,
+ "type": "data-channel",
+ "label": "red5pro",
+ "state": "open",
+ "messagesSent": 45,
+ "messagesReceived": 93,
+ "bytesSent": 4815,
+ "bytesReceived": 12556
+ }
+}
+```
+# Stream Manager 2.0
+
+> This section provides information that relate to the release of Stream Manager 2.0 and its integration with WHIP/WHEP clients, and MessageChannel.
+
+The Stream Manager 2.0 simplifies the proxying of web clients to Origin and Edge nodes. As such, an initialization configuration property called `endpoint` was added to the WebRTC SDK. This `endpoint` value should be the full URL path to the proxy endpoint on the Stream Manager as is used as such:
+
+## WHIP Proxy
+
+```javascript
+const host = 'my-deployment.red5.net'
+const streamName = `${uuid}-message-channel`
+const nodeGroup = 'my-node-group'
+const endpoint = `https://${host}/as/v1/proxy/whip/live/${streamName}`
+const config = {
+ endpoint,
+ streamName,
+ connectionParams: {
+ nodeGroup
+ },
+ dataChannelConfiguration: {
+ name: 'my-channel'
+ }
+ // additional configurations
+}
+const messageChannel = await new MessageChannel().init(config)
+messageChannel.on('*', (event) => console.log(event))
+await messageChannel.open()
+```
diff --git a/static/lib/red5pro/docs/whep-client.md b/static/lib/red5pro/docs/whep-client.md
index 2e5abf7a..c5b27ba8 100644
--- a/static/lib/red5pro/docs/whep-client.md
+++ b/static/lib/red5pro/docs/whep-client.md
@@ -5,6 +5,7 @@
Quick Start •
Publishing •
Subscribing •
+ Message Channel •
PubNub Client
@@ -253,6 +254,7 @@ The polling interval (in milliseconds) to access the `RTCStatsReport` from the u
An array of static type strings. These directly map to the listing of type available for `RTCStatsReport` objects. If left empty or undefined, the SDK will report the statistics it deems suitable for tracking proper broadcast conditions.
e.g.,
+
```js
include: ['inbound-rtp', 'transport']
```
diff --git a/static/lib/red5pro/docs/whip-client.md b/static/lib/red5pro/docs/whip-client.md
index ea93e46f..8b33169d 100644
--- a/static/lib/red5pro/docs/whip-client.md
+++ b/static/lib/red5pro/docs/whip-client.md
@@ -5,6 +5,7 @@ i
Quick Start •
Publishing •
Subscribing •
+ Message Channel •
PubNub Client
@@ -287,7 +288,7 @@ The configuration used for statistics monitoring has the following structure:
// If provided, it will POST stats to this endpoint.
// If undefined or `data-channel`, it will post stats to message transport.
// If null or `event-transport`, it will only emit status events.
- red5prosdk.StatsEndpointType.DATA_CHANNEL,
+ endpoint: red5prosdk.StatsEndpointType.DATA_CHANNEL,
additionalHeaders: undefined,
interval: 5000, // Interval to poll stats, in milliseconds.
include: [], // Empty array allows SDK to be judicious about what stats to include.
@@ -313,6 +314,7 @@ The polling interval (in milliseconds) to access the `RTCStatsReport` from the u
An array of static type strings. These directly map to the listing of type available for `RTCStatsReport` objects. If left empty or undefined, the SDK will report the statistics it deems suitable for tracking proper broadcast conditions.
e.g.,
+
```js
include: ['outbound-rtp', 'transport']
```
diff --git a/static/lib/red5pro/index.d.ts b/static/lib/red5pro/index.d.ts
index 5c556af6..bdf6141e 100644
--- a/static/lib/red5pro/index.d.ts
+++ b/static/lib/red5pro/index.d.ts
@@ -8,12 +8,13 @@ import { Logger } from 'browser-bunyan';
import EventEmitter$1 from 'core/event-emitter';
import { RTCWhipPublisherConfigType } from 'configuration/publisher';
export { BandwidthConfig, MediaConstraintRange, MediaConstraints, RTCPublisherConfigType, RTCWhipPublisherConfigType, VideoConstraints, defaultWhipPublisherConfig } from 'configuration/publisher';
-import { Event as Event$1, SubscriberEvent, PublisherEvent, MessageTransportStateEvent, PubNubEvent } from 'event';
-export { Event, MessageTransportStateEvent, PublisherEvent, SubscriberEvent } from 'event';
+import { Event as Event$1, SubscriberEvent, PublisherEvent, MessageTransportStateEvent, PubNubEvent, MessageChannelEvent } from 'event';
+export { Event, MessageChannelEvent, MessageTransportStateEvent, PubNubEvent, PublisherEvent, SubscriberEvent } from 'event';
import { MessageTransport } from 'types/message-transport';
import StatsConfig, { EndpointType } from 'configuration/stats';
export { default as StatsConfig, EndpointType as StatsEndpointType, defaultStatsConfig } from 'configuration/stats';
import PubNubClient$1 from 'pubnub';
+import RTCStatsMonitor from 'stats';
import { RTCWhepSubscriberConfigType, HLSSubscriberConfigType } from 'configuration/subscriber';
export { HLSSubscriberConfigType, RTCSubscriberConfigType, RTCWhepSubscriberConfigType, defaultHLSSubscriberConfig, defaultWhepSubscriberConfig } from 'configuration/subscriber';
import WhipWhepSignalingHelper from 'helper/wish-signal-helper';
@@ -21,11 +22,13 @@ import { PlaybackView } from 'view/playback';
import RTCPeerConnectionSubscriber from 'helper/peer-connection-sub';
import RTCSubscriberStats from 'stats/subscriber-stats';
import { RenegotiationPolicyType } from 'configuration';
+import WHIPClient$1 from 'publisher/whip';
import { LiveSeekConfigType } from 'configuration/liveseek';
export { LiveSeekConfigType, LiveSeekOptions, defaultLiveSeekConfig } from 'configuration/liveseek';
import { PubnubConfigType } from 'configuration/pubnub';
-import { PublisherEventTypes, SubscriberEventTypes, RTCPublisherEventTypes, RTCSubscriberEventTypes, MessageTransportStateEventTypes } from 'event/event-types';
-export { MessageTransportStateEventTypes, PublisherEventTypes, RTCPublisherEventTypes, RTCSubscriberEventTypes, SubscriberEventTypes } from 'event/event-types';
+import { PublisherEventTypes, SubscriberEventTypes, RTCPublisherEventTypes, RTCSubscriberEventTypes, MessageTransportStateEventTypes, MessageChannelEventTypes } from 'event/event-types';
+export { MessageChannelEventTypes, MessageTransportStateEventTypes, PublisherEventTypes, RTCPublisherEventTypes, RTCSubscriberEventTypes, SubscriberEventTypes } from 'event/event-types';
+export { default as Capability } from 'types/capabilities';
import { PubNubEventTypes } from 'event/pubnub';
declare const LEVELS: {
@@ -75,9 +78,11 @@ declare class WHIPClient extends EventEmitter$1 {
* @param {RTCWhipPublisherConfigType} additionalOptions Optional additional options to override defaults.
*/
constructor(url?: string | undefined, element?: HTMLMediaElement | undefined, additionalOptions?: RTCWhipPublisherConfigType | undefined);
- private internalInit;
+ protected internalInit(options: RTCWhipPublisherConfigType): Promise;
private generateMediaStream;
- private getAndPreviewStreamIfAvailable;
+ protected getAndPreviewStreamIfAvailable(): Promise;
+ protected establishStatsMonitor(statisticsConfiguration: StatsConfig): RTCStatsMonitor;
+ protected postStatsMonitorEvent(eventType: string, data?: any): void;
private reorderCodecPreferences;
private postOffer;
private postCandidateFragments;
@@ -167,9 +172,9 @@ declare class WHIPClient extends EventEmitter$1 {
*
* @param {string} methodName - The name of the method to send.
* @param {any} data - The data to send.
- * @returns {void}
+ * @returns {Promise}
*/
- send(methodName: string, data: any): Promise | undefined;
+ send(methodName: string, data: any): Promise;
/**
* Send a message to the PubNub channel.
*
@@ -254,12 +259,12 @@ declare class WHIPClient extends EventEmitter$1 {
private _onSendReceived;
private _onMetaData;
private _onConnectionClosed;
- private _onDataChannelOpen;
- private _onDataChannelClose;
- private _onDataChannelMessage;
+ protected _onDataChannelOpen(dataChannel: RTCDataChannel): void;
+ protected _onDataChannelClose(dataChannel: RTCDataChannel): void;
+ protected _onDataChannelMessage(dataChannel: RTCDataChannel | undefined, message: MessageEvent): void;
private _onPeerConnectionTrackAdd;
private _onPeerConnectionOpen;
- private _onPeerConnectionFail;
+ protected _onPeerConnectionFail(): void;
private _onPeerConnectionClose;
private _onIceCandidate;
private _onUnpublish;
@@ -267,11 +272,11 @@ declare class WHIPClient extends EventEmitter$1 {
private _onInsufficientBandwidth;
private _onSufficientBandwidth;
private _onRecoveringBandwidth;
- private _onSDPSuccess;
- private _onSDPError;
+ protected _onSDPSuccess(receipt?: any | undefined): void;
+ protected _onSDPError(receipt?: any | undefined): void;
private _onOrientationChange;
- private _onStatisticsEndpointChange;
- private _onStatsReport;
+ protected _onStatisticsEndpointChange(statisticsEndpoint: string): void;
+ protected _onStatsReport(connection: RTCPeerConnection, report: any): void;
/**
* Add an event listener to the WHIPClient.
*
@@ -612,8 +617,9 @@ declare class WHEPClient extends PlaybackController {
*
* @param {string} methodName - The method name to send.
* @param {any} data - The data to send.
+ * @returns {Promise}
*/
- send(methodName: string, data: any): Promise | undefined;
+ send(methodName: string, data: any): Promise;
/**
* Send a message to the PubNub channel.
*
@@ -866,6 +872,126 @@ declare class WHEPClient extends PlaybackController {
getType(): string;
}
+/**
+ * MessageChannel is a subclass of WHIPClient that provides a data channel for sending and receiving messages only.
+ * _There is no underlying media streaming logic in this client._
+ *
+ * This ingest-based client is useful for sending and receiving messages to and from the server over a designated data channel.
+ */
+declare class MessageChannel extends WHIPClient$1 {
+ private _inactivePingIntervalMS;
+ private _inactivePingTimeout;
+ constructor(url: string | undefined, additionalOptions?: RTCWhipPublisherConfigType | undefined);
+ /**
+ * Internally initialize the MessageChannel.
+ * @param {RTCWhipPublisherConfigType} options - The options to initialize the MessageChannel with. See {@link RTCWhipPublisherConfigType} for more details.
+ * @returns {Promise}
+ * @override - Overrides the internalInit method in the WHIPClient class to properly initialize and open the MessageChannel.
+ * @private
+ */
+ protected internalInit(options: RTCWhipPublisherConfigType): Promise;
+ /**
+ * Establish the stats monitor for the MessageChannel.
+ * @param {StatsConfig} statisticsConfiguration - The statistics configuration.
+ * @returns {RTCStatsMonitor}
+ * @override - Overrides the establishStatsMonitor method in the WHIPClient class to properly establish the stats monitor for the MessageChannel.
+ * @private
+ */
+ protected establishStatsMonitor(statisticsConfiguration: StatsConfig): RTCStatsMonitor;
+ /**
+ * Initialize the MessageChannel.
+ * @param {RTCWhipPublisherConfigType} options - The options to initialize the MessageChannel with. See {@link RTCWhipPublisherConfigType} for more details.
+ * @returns {Promise}
+ */
+ init(options: RTCWhipPublisherConfigType): Promise;
+ /**
+ * Disallow MediaStream generation for this client.
+ * @private
+ */
+ protected getAndPreviewStreamIfAvailable(): Promise;
+ /**
+ * Start the inactive ping to keep the data channel open during inactivity (no messages sent).
+ * @private
+ */
+ private _startInactivePing;
+ /**
+ * Stop the inactive ping.
+ * @private
+ */
+ private _stopInactivePing;
+ /**
+ * Open the MessageChannel.
+ * @param {number} inactivePingIntervalMS - The interval in milliseconds to send an inactive ping.
+ * @returns {Promise}
+ */
+ open(inactivePingIntervalMS?: number): Promise;
+ /**
+ * Close the MessageChannel.
+ */
+ close(): Promise;
+ publish(): Promise;
+ unpublish(): Promise;
+ /**
+ * Send a JSON message to the server over the data channel.
+ * @override - Overrides the send method in the WHIPClient class to properly wrap the data in a message object with methodName.
+ * @param {string} methodName - The name of the method to send.
+ * @param {any} data - The data to send.
+ * @returns {Promise}
+ */
+ send(methodName: string, data: any): Promise;
+ /**
+ * Send a message to the server over the data channel. This will attempt to wrap and send the message as a JSON payload.
+ * @param {any} message - The message to send.
+ * @returns {Promise}
+ * @see {@link sendData} for sending raw data to the server over the data channel.
+ */
+ sendMessage(message: any): Promise;
+ /**
+ * Send data to the server over the data channel.
+ * @param {any} data - The data to send. Can be of any type, such as an arraybuffer.
+ * @returns {Promise}
+ */
+ sendData(data: any): Promise;
+ /**
+ * Start the inactive ping when the data channel is opened.
+ * @private
+ */
+ protected _onDataChannelOpen(dataChannel: RTCDataChannel): void;
+ /**
+ * Handle an incoming data channel message.
+ * @param dataChannel - The data channel that received the message.
+ * @param message - The message event.
+ * @private
+ */
+ protected _onDataChannelMessage(dataChannel: RTCDataChannel | undefined, message: MessageEvent): void;
+ /**
+ * Stop the inactive ping when the data channel is closed.
+ * @private
+ */
+ protected _onDataChannelClose(dataChannel: RTCDataChannel): void;
+ /**
+ * Handle a peer connection failure.
+ * @private
+ */
+ protected _onPeerConnectionFail(): void;
+ /**
+ * Handle an error on the data channel.
+ * @private
+ */
+ protected _onSDPError(receipt?: any | undefined): void;
+ /**
+ * Trigger an event on the MessageChannel.
+ * @param {Event} event - The event to trigger.
+ * @override - Overrides the trigger method in the WHIPClient class to properly trigger the event on the MessageChannel.
+ */
+ trigger(event: Event$1): void;
+ /**
+ * Get the type of the MessageChannel.
+ * @returns {string}
+ */
+ getType(): string;
+}
+
/**
* HLS Subscriber. Supports playback of HLS streams using the native HLS player in browsers that support it (i.e., Mobile and Desktop Safari).
*/
@@ -1206,22 +1332,29 @@ declare const _default: {
PublisherEvent: typeof PublisherEvent;
MessageTransportStateEvent: typeof MessageTransportStateEvent;
PubNubEvent: typeof PubNubEvent;
+ MessageChannelEvent: typeof MessageChannelEvent;
PublisherEventTypes: typeof PublisherEventTypes;
SubscriberEventTypes: typeof SubscriberEventTypes;
RTCPublisherEventTypes: typeof RTCPublisherEventTypes;
RTCSubscriberEventTypes: typeof RTCSubscriberEventTypes;
MessageTransportStateEventTypes: typeof MessageTransportStateEventTypes;
+ MessageChannelEventTypes: typeof MessageChannelEventTypes;
PubNubEventTypes: typeof PubNubEventTypes;
WHIPClient: typeof WHIPClient;
WHEPClient: typeof WHEPClient;
HLSSubscriber: typeof HLSSubscriber;
LiveSeekClient: typeof LiveSeekClient;
PubNubClient: typeof PubNubClient;
+ MessageChannel: typeof MessageChannel;
+ Capability: {
+ readonly stream: 3;
+ readonly datachannel: 4;
+ };
defaultWhepSubscriberConfig: RTCWhepSubscriberConfigType;
defaultWhipPublisherConfig: RTCWhipPublisherConfigType;
defaultStatsConfig: StatsConfig;
StatsEndpointType: typeof EndpointType;
};
-export { EventEmitter, HLSSubscriber, LEVELS as LOG_LEVELS, LiveSeekClient, PlaybackController, PlaybackControls, PubNubClient, SourceHandler, SourceHandlerImpl, WHEPClient, WHIPClient, _default as default, getLogger, getRecordedLogs, getVersion, setLogLevel };
+export { EventEmitter, HLSSubscriber, LEVELS as LOG_LEVELS, LiveSeekClient, MessageChannel, PlaybackController, PlaybackControls, PubNubClient, SourceHandler, SourceHandlerImpl, WHEPClient, WHIPClient, _default as default, getLogger, getRecordedLogs, getVersion, setLogLevel };
export type { EventEmitterInterface };
diff --git a/static/lib/red5pro/red5pro-sdk.esm.min.js b/static/lib/red5pro/red5pro-sdk.esm.min.js
index b1442eb8..7eec70e5 100644
--- a/static/lib/red5pro/red5pro-sdk.esm.min.js
+++ b/static/lib/red5pro/red5pro-sdk.esm.min.js
@@ -2,7 +2,7 @@
*
* red5pro-html-sdk - Red5 Pro HTML SDK
* Author: Infrared5 Inc.
- * Version: 15.2.0
+ * Version: 15.3.0
* Url: https://www.red5.net
*
* Copyright © 2015 Infrared5, Inc. All rights reserved.
@@ -31,4 +31,4 @@
*
*/
-var e,t,i,n;!function(e){e.OPUS="OPUS",e.NONE="NONE"}(e||(e={})),function(e){e.VP8="VP8",e.H264="H264",e.H265="H265",e.NONE="NONE"}(t||(t={})),function(e){e[e.UNAVAILABLE=1e3]="UNAVAILABLE",e[e.AVAILABLE=0]="AVAILABLE",e[e.IDLE=1]="IDLE",e[e.PLAYING=2]="PLAYING",e[e.PAUSED=3]="PAUSED"}(i||(i={})),function(e){e.UNAVAILABLE="Playback.UNAVAILABLE",e.AVAILABLE="Playback.AVAILABLE",e.IDLE="Playback.IDLE",e.PLAYING="Playback.PLAYING",e.PAUSED="Playback.PAUSED"}(n||(n={}));const s={[i.UNAVAILABLE]:n.UNAVAILABLE,[i.AVAILABLE]:n.AVAILABLE,[i.IDLE]:n.IDLE,[i.PLAYING]:n.PLAYING,[i.PAUSED]:n.PAUSED};var o,a,r,l;!function(e){e.RTMP="rtmp",e.RTC="rtc"}(o||(o={})),function(e){e.LIVE="live",e.RECORD="record",e.APPEND="append"}(a||(a={})),function(e){e.OPUS="OPUS"}(r||(r={})),function(e){e.VP8="VP8",e.H264="H264",e.H265="H265"}(l||(l={}));var d={trace:10,debug:20,info:30,warn:40,error:50,fatal:60},h={};function c(e){return"string"==typeof e?d[e.toLowerCase()]:e}function u(e,t){return u=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e},u(e,t)}function _(e,t,i){return _=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){}))),!0}catch(e){return!1}}()?Reflect.construct:function(e,t,i){var n=[null];n.push.apply(n,t);var s=new(Function.bind.apply(e,n));return i&&u(s,i.prototype),s},_.apply(null,arguments)}function p(e){if(null==e)return e;if(Array.isArray(e))return e.slice();if("object"==typeof e){var t={};return Object.keys(e).forEach((function(i){t[i]=e[i]})),t}return e}function g(e){return void 0===e?"undefined":null===e?"null":Array.isArray(e)?"[ "+e.map((function(e){return g(e)})).join(", ")+" ]":"object"==typeof e?JSON.stringify(e):"function"==typeof e?"[Function: "+e.name+"]":"boolean"==typeof e||"number"==typeof e?e:"'"+e.toString()+"'"}function m(e){if("string"!=typeof e){for(var t=new Array(arguments.length),i=0;i=o)return e;switch(e){case"%s":return String(s[n++]);case"%d":return Number(s[n++]);case"%j":try{return JSON.stringify(s[n++])}catch(e){return"[Circular]"}default:return e}})),r=s[n];ne||(s=function(s){var o;s[0]instanceof Error?(i={err:t.serializers&&t.serializers.err?t.serializers.err(s[0]):T.err(s[0])},o={err:!0},n=1===s.length?[i.err.message]:Array.prototype.slice.call(s,1)):"object"!=typeof s[0]&&null!==s[0]||Array.isArray(s[0])?(i=null,n=Array.prototype.slice.call(s)):(i=s[0],n=1===s.length&&i.err&&i.err instanceof Error?[i.err.message]:Array.prototype.slice.call(s,1));var a=p(t.fields);a.level=e;var r=i?p(i):null;if(r&&(t.serializers&&t._applySerializers(r,o),Object.keys(r).forEach((function(e){a[e]=r[e]}))),a.levelName=h[e],a.msg=n.length?m.apply(t,n):"",a.time||(a.time=new Date),t.src&&!a.src)try{throw new Error("call-stack-error")}catch(e){var l=e.stack?function(e,t){var i=e.split("\n");i[0]&&i[0].indexOf("call-stack-error")>=0&&i.shift();var n=i[t],s=null;if(n){var o=/^\s*(at|.*@)\s*(.+)?$/.exec(n);s=Array.isArray(o)&&o[2]?o[2]:n}return s}(e.stack,2):"";l||function(e){return v[e]}("src")||E("Unable to determine src line info","src"),a.src=l||""}return a.v=1,a}(n),this._emit(s))}}function f(e){var t=e.stack||e.toString();if(e.cause&&"function"==typeof e.cause){var i=e.cause();i&&(t+="\nCaused by: "+f(i))}return t}C.prototype.trace=b(10),C.prototype.debug=b(20),C.prototype.info=b(30),C.prototype.warn=b(40),C.prototype.error=b(50),C.prototype.fatal=b(60);var T={err:function(e){return e&&e.stack?{message:e.message,name:e.name,stack:f(e),code:e.code,signal:e.signal}:e}};const w={10:"TRACE",20:"DEBUG",30:"INFO",40:"WARN",50:"ERROR",60:"FATAL"};class A{write(e){console.log("%s - [%s] %s: %s",e.time.toISOString(),e.name,w[e.level]||"UNKNOWN",e.msg)}}let y,N;const L=e=>(t,i)=>{var n;y&&"function"==typeof y[e]&&y[e]((n=t,e=>`(${n}) ${e}`)(i))},P={TRACE:"trace",INFO:"info",DEBUG:"debug",WARN:"warn",ERROR:"error",FATAL:"fatal"},R=(e,t=!1,i)=>{const n=[{level:e,stream:new A,type:"raw"}];if(i){const t=i.map((t=>({...t,level:e})));n.push(...t)}t&&(N=[],n.push({level:e,stream:{write:t=>{const i=`[${t.time.toISOString()}] ${e.toUpperCase()}: ${t.msg}`;null==N||N.push(i)}},type:"raw"}));y=function(){return _(C,[].slice.call(arguments))}({level:e,name:"red5pro-sdk",streams:n})},I=()=>(y||R(P.INFO),y),D=()=>N||[];L(P.TRACE),L(P.INFO);const O=L(P.DEBUG),H=L(P.WARN),k=L(P.ERROR);L(P.FATAL);const U="RED5PRO";class M{constructor(){this._callbacks={},this._callbacks[U]=[]}_notify(e,t){let i;const n=e.length;for(i=0;i1&&(s=V.exec(e),n[1]===t&&s&&s.length>1)?s[1]:void 0}}function x(e){const t=G(e,"orientation");if(t)return{orientation:parseInt(t)}}function W(e){const t=G(e,"streamingMode");if(t)return{streamingMode:t}}const K=e=>F.get(e),j=e=>{const t=e.textTracks;t&&(e.addTextTrack("metadata"),t.addEventListener("addtrack",(t=>{const i=t.track;i.mode="hidden",i.addEventListener("cuechange",(t=>{let n,s;for(t&&t.currentTarget?n=t.currentTarget.cues:(n=i.cues,n=n&&n.length>0?n:i.activeCues),n=n||[],s=0;s{e(n)})),s&&o&&o.streamingMode&&o.streamingMode.forEach((e=>{e(s)}))}}}))})))},z="BrowserEnvironment",J=e=>O(z,e),Y=e=>H(z,e);let q=[];const X=()=>{const e=screen.orientation?screen.orientation.angle:void 0,t=void 0===e?window.matchMedia("(orientation: portrait)").matches?0:90:e,i=q.length;J(`[window:onorientationchange]: orientation(${t}).`);for(let e=0;e{const e=document.createElement("video");return e.canPlayType("application/vnd.apple.mpegURL").length>0||e.canPlayType("application/x-mpegURL").length>0||e.canPlayType("audio/mpegurl").length>0||e.canPlayType("audio/x-mpegurl").length>0},te="undefined"!=typeof window&&window.adapter;var ie={gUM:async e=>navigator.mediaDevices.getUserMedia(e),createElement:e=>document.createElement(e),resolveElement:e=>document.getElementById(e),getElementId:e=>e.id,setVideoSource:(e,t,i)=>{if(e.srcObject=t,i)try{const t=e.play();t&&t.then((()=>J("[setVideoSource:action]: play (START)"))).catch((t=>{Y(`[setVideoSource:action]: play (CATCH::FAULT) ${t.message}`);try{e.setAttribute("autoplay","false"),e.pause()}catch(e){Y(`[setVideoSource:action]: pause (CATCH::FAULT) ${e.message}`)}}))}catch(e){Y(`[setVideoSource:action]: play (CATCH::FAULT) ${e.message}`)}},hasAttributeDefined:(e,t)=>e.hasAttribute(t),addOrientationChangeHandler:(e,t=!0)=>{"onorientationchange"in window&&(J("[window:orientation:addOrientationChangeHandler]: add"),q.push(e),t&&X()),1===q.length&&(J("[window:orientation:addOrientationChangeHandler]: add"),window.addEventListener("orientationchange",X))},removeOrientationChangeHandler:e=>{q=q.filter((t=>t!==e)),0===q.length&&window.removeEventListener("orientationchange",X)},toggleFullScreen:e=>{window.screenfull&&window.screenfull.enabled?window.screenfull.toggle(e):document.fullscreenEnabled&&(document.fullscreenElement&&document.fullscreenElement===e?document.exitFullscreen():e.requestFullscreen())},onFullScreenStateChange:e=>{var t;Z.push(e),t=window.screenfull,Q||(Q=!0,window.screenfull?window.screenfull.on("change",(()=>{Z.forEach((e=>e(t.isFullscreen)))})):document.fullscreenEnabled&&document.addEventListener("fullscreenchange",(()=>{Z.forEach((e=>e(null!==document.fullscreenElement)))})))},getOrGenerateFingerprint:()=>{const e=window.localStorage;if(e&&e.getItem("red5_fingerprint"))return e.getItem("red5_fingerprint");let t;try{t=window.crypto.randomUUID()}catch(e){t="10000000-1000-4000-8000-100000000000".replace(/[018]/g,(e=>(Number(e)^crypto.getRandomValues(new Uint8Array(1))[0]&15>>Number(e)/4).toString(16)))}return e.setItem("red5_fingerprint",t),t},getBrowserDetails:()=>{const e=void 0!==window.adapter,{navigator:t,adapter:i}=window,{appVersion:n,platform:s,userAgent:o,vendor:a}=t,r={appVersion:n,platform:s,userAgent:o,vendor:a};return e?{...i.browserDetails,...r}:r},supportsHLS:ee,onOrientationMetadata:(e,t)=>{const i=F.get(e);F.has(e)?Object.prototype.hasOwnProperty.call(i,"orientation")||(F.get(e).orientation=[]):(j(e),F.set(e,{orientation:[]})),F.get(e).orientation.push(t)},onStreamingModeMetadata:(e,t)=>{const i=F.get(e);F.has(e)?Object.prototype.hasOwnProperty.call(i,"streamingMode")||(F.get(e).streamingMode=[]):(j(e),F.set(e,{streamingMode:[]})),F.get(e).streamingMode.push(t)},isTouchEnabled:()=>"ontouchstart"in window,isPossiblySafari:()=>te?"safari"===window.adapter.browserDetails.browser.toLowerCase():ee(),findByQuerySelector:e=>document.querySelector(e),addGlobalEventListener:(e,t,i=document)=>{i.addEventListener(e,t)},removeGlobalEventListener:(e,t,i=document)=>{i.removeEventListener(e,t)},supportsNonNativeHLS:e=>{if(e)try{return e.isSupported()}catch(e){return Y("Could not access Hls.js."),!1}return!!window.Hls&&window.Hls.isSupported()},createHLSClient:(e={})=>new window.Hls(e),getHLSClientEventEnum:()=>window.Hls.Events,globalAssign:(e,t)=>{window[e]=t},globalUnassign:e=>{delete window[e]},getAssignedValue:e=>window[e]};const ne=(e,t,i)=>{const{liveSeek:{baseURL:n,fullURL:s}}=e,{host:o,protocol:a,port:r,app:l,streamName:d}=e;if(i||s)return i||s;const h=o,c="ws"===a?"http":"https",u=5080===r?5080:443,_=l,p=t||n;if(p){const e=p.length-1;return`${"/"===p.charAt(e)?p.substring(0,e):p}/${_}/${d}.m3u8`}return`${c}://${h}:${u}/${_}/${d}.m3u8`},se=e=>{const t=new URL(e),i=t.pathname.split("/").filter((e=>e.length>0)),n="https:"===t.protocol?"https":"http",s=t.hostname;return{protocol:n,port:t.port.length>0?t.port:443,app:i[0],host:s,streamName:i[i.length-1]}},oe=(e,t="whip")=>{var i;const{endpoint:n,proxy:s}=e;if(n)return n;{const{protocol:n,host:o,port:a,app:r,streamName:l}=e,d=n.match(/^http/)?n:"ws"===n?"http":"https";return(null==s?void 0:s.enabled)?`${d}://${o}:${a}/as/${null!==(i=s.version)&&void 0!==i?i:"v1"}/proxy/${t}/${r}/${l}`:`${d}://${o}:${a}/${r}/${t}/endpoint/${l}`}},ae=e=>{const t={audio:!1,video:!1},i={audio:!1,video:!1};return e.getTracks().forEach((e=>{"video"===e.kind?(i.video=e.getSettings(),t.video=e.getConstraints()):"audio"===e.kind&&(i.audio=e.getSettings(),t.audio=e.getConstraints())})),{requested:t,accepted:i}},re=e=>{const t=e.length;return function i(...n){return n.length>=t?e(...n):function(...e){return i(...n,...e)}}},le=re(((e,t)=>{let i=0;const n=t.length,s=[];for(;i{this._responder.onDataChannelError(e,t.error.message)},e.onmessage=e=>{this._onDataChannelMessage(e)},e.onopen=()=>{this._responder.onDataChannelOpen(e)},e.onclose=t=>{this._responder.onDataChannelClose(e),this.trigger(new Ce(ye.CLOSE,this._name,{socket:this,event:t}))}}_isErrorMessage(e){return!("error"!==(null==e?void 0:e.type)||!(null==e?void 0:e.message)&&!(null==e?void 0:e.code))}_isStatusMessage(e){return!("status"!==(null==e?void 0:e.type))}_onDataChannelMessage(e){if(this.handleMessageResponse(e))return!0;const t=this.getJsonFromSocketMessage(e);return t?(O(this._name,`[datachannel-response]: ${JSON.stringify(t,null,2)}`),this._handleMessageContent(t)):(H(this._name,"Determined websocket response not in correct format. Aborting message handle."),!0)}_handleMessageContent(e){const{async:t,data:i,method:n,send:s,type:o,id:a}=e;if(this._isErrorMessage(i)){const e=(null==i?void 0:i.message)||(null==i?void 0:i.code);if(e)return this._responder.onDataChannelError(this._dataChannel,e),!0}if(n)return this._responder.onSendReceived(n,i),!0;if(s){const{senderName:t,dcLabel:i}=e,{data:n,method:o}=s,a={...n,senderName:t,dcLabel:i};return this._responder.onSendReceived(o,a),!0}return"metadata"===o&&i?(this._responder.onMetaData(i),!0):this._isStatusMessage(i)&&"NetConnection.Connect.Closed"===(null==i?void 0:i.code)?(this._responder.onConnectionClosed(),!0):!(!t||!a)&&this._handleAsyncResponse(a,e)}_handleAsyncResponse(e,t){const i=this._asyncTickets.find((t=>t.id===e));if(!i)return!1;const{promise:n}=i,{data:s}=t;if("error"===(null==s?void 0:s.type)){const e=s.message||s.code||"Unknown error";n.reject(new Error(e))}else n.resolve(s);return this._asyncTickets=this._asyncTickets.filter((t=>t.id!==e)),!0}async setUpWithPeerConfiguration(e,t){this.tearDown();(null==e?void 0:e.iceServers)&&e.iceServers.length>0||(e.iceServers=Le);try{O(this._name,`[peerconnection:setUpWithPeerConfiguration]: ${JSON.stringify(e,null,2)}`);const i=new RTCPeerConnection(e);return t&&(this._dataChannel=i.createDataChannel(t.name,{ordered:!0}),this._addDataChannelHandlers(this._dataChannel)),this._addConnectionHandlers(i),this._peerConnection=i,i}catch(e){throw H(this._name,`Could not establish a PeerConnection. ${e.message}`),new Error(e.message)}}tearDown(){if(this._dataChannel){O(this._name,"[teardown:datachannel]"),this._removeDataChannelHandlers(this._dataChannel);try{this._dataChannel.close()}catch(e){H(this._name,`[datachannel.close] error: ${e.message}`)}finally{this._dataChannel=void 0}}if(this._peerConnection){O(this._name,"[teardown:peerconnection]"),this._removeConnectionHandlers(this._peerConnection);try{this._peerConnection.close()}catch(e){H(this._name,`[peerconnection.close] error: ${e.message}`)}finally{this._peerConnection=void 0}}}async setLocalDescription(e){var t;return O(this._name,"[setlocaldescription]"),null===(t=this._peerConnection)||void 0===t?void 0:t.setLocalDescription(e)}async setRemoteDescription(e){var t;return O(this._name,"[setremotedescription]"),null===(t=this._peerConnection)||void 0===t?void 0:t.setRemoteDescription(new RTCSessionDescription(e))}async addIceCandidate(e){var t;return O(this._name,"[addcandidate]"),null===(t=this._peerConnection)||void 0===t?void 0:t.addIceCandidate(e)}async waitToGatherIce(e=5e3){const t=this._peerConnection;return O(this._name,"[waittogatherice]"),new Promise((i=>{if("complete"===t.iceGatheringState)O(this._name,"[waittogatherice] ice gathering state complete."),t.addIceCandidate(null).then((()=>{i(t.localDescription)})).catch((e=>{H(this._name,"Error adding null candidate: "+e.message||e),i(t.localDescription)}));else{O(this._name,"[waittogatherice] waiting...");const n=setTimeout((()=>{clearTimeout(n),t.addIceCandidate(null).then((()=>{i(t.localDescription)})).catch((e=>{H(this._name,"Error adding null candidate: "+e.message||e),i(t.localDescription)}))}),e);t.onicegatheringstatechange=()=>{clearTimeout(n),O(this._name,"[waittogatherice] ice gathering state complete."),"complete"===t.iceGatheringState&&t.addIceCandidate(null).then((()=>{i(t.localDescription)})).catch((e=>{H(this._name,"Error adding null candidate: "+e.message||e),i(t.localDescription)}))}}}))}post(e){if(this._dataChannel){const t="string"==typeof e?e:JSON.stringify(e,null,2);O(this._name,`[datachannel.send] message: ${t}`);try{return this._dataChannel.send(t),Promise.resolve(!0)}catch(e){k(this._name,e.message)}}return Promise.resolve(!1)}get connection(){return this._peerConnection}get dataChannel(){return this._dataChannel}}const Re=[{label:"4K(UHD)",width:3840,height:2160},{label:"1080p(FHD)",width:1920,height:1080},{label:"UXGA",width:1600,height:1200},{label:"720p(HD)",width:1280,height:720},{label:"SVGA",width:800,height:600},{label:"VGA",width:640,height:480},{label:"360p(nHD)",width:640,height:360},{label:"CIF",width:352,height:288},{label:"QVGA",width:320,height:240},{label:"QCIF",width:176,height:144},{label:"QQVGA",width:160,height:120}],Ie=e=>"number"==typeof e?e:e.exact||e.ideal||e.max||e.min||e,De=re(((e,t)=>{var i,n;if("boolean"==typeof e.video)return!0;const s=(null===(i=e.video)||void 0===i?void 0:i.width)?Ie(e.video.width):0,o=(null===(n=e.video)||void 0===n?void 0:n.height)?Ie(e.video.height):0,a=s===t.width&&o===t.height;return a&&O("[gum:isExact]",`Found matching resolution for ${t.width}, ${t.height}.`),a})),Oe=re(((e,t)=>{const i=le(De(t))(e);return O("[gum:hasMatchingFormat]","Filtered list: "+JSON.stringify(i,null,2)),i.length>0})),He=re(((e,t)=>{var i,n;if("boolean"==typeof e.video)return!0;const s=((null===(i=e.video)||void 0===i?void 0:i.width)?Ie(e.video.width):0)*((null===(n=e.video)||void 0===n?void 0:n.height)?Ie(e.video.height):0);return t.width*t.height{const i=He(t);return le(i)(e)})),Ue=async e=>{O("[gum:determineSupportedResolution]","Determine next neighbor based on constraints: "+JSON.stringify(e,null,2));const t=ke(Re)(e),i={...e};return await(async(e,t)=>{let i={...e};if(0==t.length)i.video;else{const n=t.shift();i={...e,video:{...e.video,width:{exact:n.width},height:{exact:n.height}}}}return{media:await ie.gUM(i),constraints:i}})(i,t)},Me=async e=>{let t;const i=Oe(Re),n=async t=>{if(t){const e="string"==typeof t?t:[t.name,t.message].join(": ");O("[gum:getUserMedia]",`Failure in getUserMedia: ${e}. Attempting other resolution tests...`)}return await Ue(e)};if((e=>e.video&&"object"==typeof e.video&&(e.video.width||e.video.height))(e)){if(!i(e))return await n(void 0);{O("[gum:getUserMedia]","Found constraints in list. Checking quick support for faster setup with: "+JSON.stringify(e,null,2));const i=(e=>{var t,i;const n={...e};return"boolean"==typeof e.video||(n.video={...n.video},(null===(t=e.video)||void 0===t?void 0:t.width)&&(n.video.width={exact:Ie(e.video.width)}),(null===(i=e.video)||void 0===i?void 0:i.height)&&(n.video.height={exact:Ie(e.video.height)})),n})(e);try{return t=await ie.gUM(i),{media:t,constraints:i}}catch(e){return await n(e)}}}else try{return t=await ie.gUM(e),{media:t,constraints:e}}catch(e){return await n(e)}},Be=(e,t,i)=>{const n="a=end-of-candidates",s=/^a=candidate:/,o=/^a=ice-ufrag:/,a=/^a=ice-pwd:/,r=/^m=(audio|video|application)\ /,l=e.split("\r\n");let d,h="",c="";const u=[];l.forEach((e=>{!d&&r.exec(e)?d=e:o.exec(e)?h=e:a.exec(e)?c=e:s.exec(e)&&(t&&-1!=e.indexOf(t)?u.push(e):t||u.push(e))})),i&&u[u.length-1]!==n&&u.push(n);return[h,c,d,"a=mid:0"].concat(u).join("\r\n")},Ve="RTCPeerConnectionPublisher";class Fe extends Pe{constructor(e){super(e,Ve)}_removeConnectionHandlers(e){e.onconnectionstatechange=null,e.oniceconnectionstatechange=null,e.onsignalingstatechange=null,e.onicecandidate=null,e.ontrack=null}_addConnectionHandlers(e){let t;e.onsignalingstatechange=()=>{const t=e.signalingState;O(Ve,`[peer.onsignalingstatechange] - State: ${t}`)},e.onconnectionstatechange=()=>{const{connectionState:t}=e;"connected"===t?(O(this._name,"[peerconnection:open]"),this._responder.onPeerConnectionOpen()):"failed"!==t&&"disconnected"!==t||(H(this._name,"[peerconnection:error]"),"failed"===t&&this._responder.onPeerConnectionFail())},e.oniceconnectionstatechange=i=>{const{iceConnectionState:n}=e;O(this._name,`[peer.oniceconnectionstatechange] - State: ${n}`),"failed"===n?(t&&clearTimeout(t),this._responder.onPeerConnectionClose(i)):"disconnected"===n?t=setTimeout((()=>{O(this._name,"[peer.oniceconnectionstatechange] - Reconnect timeout reached. Closing PeerConnection."),clearTimeout(t),this._responder.onPeerConnectionClose(i)}),3e3):t&&(O(this._name,"[peer.oniceconnectionstatechange] - Clearing timeout for reconnect."),clearTimeout(t))},e.onicecandidate=e=>{const{candidate:t}=e;O(this._name,`[peer.onicecandidate] - Peer Candidate: ${null==t?void 0:t.candidate}`),t&&this._responder.onIceCandidate(t)},e.ontrack=e=>{O(this._name,"[peer:ontrack]"),this._responder.onPeerConnectionTrackAdd(e.track)}}_onDataChannelMessage(e){const t=e;if(super._onDataChannelMessage(e))return!0;const i=this.getJsonFromSocketMessage(t);if(null===i)return H(this._name,"Determined websocket response not in correct format. Aborting message handle."),!0;O(this._name,"[datachannel-response]: "+JSON.stringify(i,null,2));const{data:n}=i;return n&&"status"===n.type?"NetStream.Play.UnpublishNotify"===n.code?(this._responder.onUnpublish(),!0):"NetConnection.Publish.InsufficientBW"===n.code?(this._responder.onInsufficientBandwidth(n),!0):"NetConnection.Publish.SufficientBW"===n.code?(this._responder.onSufficientBandwidth(n),!0):"NetConnection.Publish.RecoveringBW"===n.code?(this._responder.onRecoveringBandwidth(n),!0):"Application.Statistics.Endpoint"===n.code?(this._responder.onStatisticsEndpointChange(n.statistics),!0):(O(Ve,`[datachannel.message] status :: ${n.code}`),this._responder.onPublisherStatus(n),!0):(this._responder.onDataChannelMessage(this._dataChannel,t),!1)}addTrack(e){this._peerConnection?this._peerConnection.addTrack(e):H(Ve,"PeerConnection not initialized. Cannot add track.")}async postUnpublish(e){const t=this.post({unpublish:e});return O(Ve,`[peerconnection:unpublish] complete: ${t}`),t}async createOfferWithoutSetLocal(e=null){var t;O(Ve,`[createoffer:withoutlocal]:: bandwidth request: ${JSON.stringify(e,null,2)}`);try{const i=await(null===(t=this._peerConnection)||void 0===t?void 0:t.createOffer());if(e){const t=((e,t)=>{const i=t.indexOf("m=audio");let n,s,o,a=t.indexOf("m=video"),r=t.indexOf("m=application");return i>-1&&e.audio&&(n=t.indexOf("\r\n",i),s=t.slice(0,n),o=t.slice(n+2,t.length),a=(t=[s,"b=AS:"+e.audio,o].join("\r\n")).indexOf("m=video"),r=t.indexOf("m=application")),a>-1&&e.video&&(n=t.indexOf("\r\n",a),s=t.slice(0,n),o=t.slice(n+2,t.length),r=(t=[s,"b=AS:"+e.video,o].join("\r\n")).indexOf("m=application")),r>-1&&e.dataChannel&&(n=t.indexOf("\r\n",r),s=t.slice(0,n),o=t.slice(n+2,t.length),t=[s,"b=AS:"+e.dataChannel,o].join("\r\n")),t})(e,i.sdp);i.sdp=t}return this._responder.onSDPSuccess(),i}catch(e){throw O(Ve,"[createoffer:error]"),this._responder.onSDPError(e),e}}async updateBandwidthRequest(e=null){var t;O(Ve,`[updatebandwidthrequest]:: bandwidth request: ${JSON.stringify(e,null,2)}`);try{const i=null===(t=this._peerConnection)||void 0===t?void 0:t.getSenders();if(e&&(null==i?void 0:i.length)&&i.length>0){const t=(e,t,i)=>new Promise(((n,s)=>{try{O(Ve,`[updatebandwidthrequest:${i}]:: bandwidth(${t.encodings[0].maxBitrate})`),e.setParameters(t).then(n).catch(s)}catch(e){s(e)}})),n=[];null==i||i.forEach((async i=>{var s,o;if("video"===(null===(s=i.track)||void 0===s?void 0:s.kind)&&e.video){const e=i.getParameters();e.encodings||(e.encodings=[{}]),e.encodings[0].maxBitrate=75e4,e.encodings[0].maxFramerate=60,e.encodings[0].priority="high",n.push(t(i,e,"video"))}else if("audio"===(null===(o=i.track)||void 0===o?void 0:o.kind)&&e.audio){const e=i.getParameters();e.encodings||(e.encodings=[{}]),e.encodings[0].maxBitrate=128e3,n.push(t(i,e,"audio"))}})),await Promise.all(n).catch((e=>{k(Ve,`[updatebandwidthrequest:error]:: ${e.message}`)}))}return!0}catch(e){k(Ve,`[updatebandwidthrequest:error]:: ${e.message}`)}return!1}}class $e extends Error{constructor(e){super(e),this.name="InvalidNameError"}}const Ge="WhipWhepSignalingHelper",xe=new Map;xe.set(400,"Invalid offer SDP."),xe.set(401,"Not authorized."),xe.set(404,"Scope resolver failed for the publish name and / or scope."),xe.set(405,"Remember to update the URL passed into the WHIP or WHEP client."),xe.set(406,"Scope connection rejected."),xe.set(409,"Session already initialized."),xe.set(412,"Invalid request body."),xe.set(417,"Session lookup or creation failure.");const We=new Map;We.set(400,"Offer already sent, double POST assumed."),We.set(401,"Not authorized."),We.set(404,"Scope resolver failed for the playback name and / or scope."),We.set(406,"Playback failed due to an exception during creation."),We.set(409,"Stream is not available to playback.");const Ke=["transcode"];var je;!function(e){e.ICE_SERVER="ice-server",e.STATISTICS="statistics"}(je||(je={}));const ze=e=>e&&(e=>{const t=/[?&](.*)=([^]*)/.exec(e);return t&&t.length>0})(e)?"&":"?",Je=e=>e.split(";").map((e=>e.trim())).map((e=>"<"===e.charAt(0)?["url",e.substring(1,e.length-1)]:e.split("="))).reduce(((e,t)=>e.set(t[0].replaceAll('"',""),t[1].replaceAll('"',""))),new Map);class Ye{constructor(e,t=!1,i=!0){O(Ge,`[whipwhep] ${e}`),this._url=e,this._origin=void 0,this._forceHost=i,this._resource=void 0,this._enableSignalingChannel=t}async getOptions(e={}){let t=`${this._url}${ze(this._url)}signal=${this._enableSignalingChannel}`;e&&Object.keys(e).forEach((i=>{t+=`&${i}=${e[i]}`})),O(Ge,`[whipwhep-options] ${t}`);try{const e=await fetch(t,{method:"OPTIONS",mode:"cors"}),{status:i,headers:n}=e;if(200===i||204===i){const e=/^(L|l)ink/,t=/^(S|s)ession-(H|h)ost/,i=[];let s;return n.forEach(((n,o)=>{if(t.exec(o)&&(this._origin=n),e.exec(o))if(n.indexOf(`rel="${je.ICE_SERVER}"`)>-1){const e=Je(n),t=e.get("url"),{protocol:s,host:o}=(e=>{const t=e.split(":");return t.length>1?{protocol:t[0],host:t[1]}:{protocol:void 0,host:e}})(t),a=e.get("username"),r=e.get("credential");s&&o&&a&&r?i.push({username:a,credential:r,urls:t}):t&&i.push({urls:t})}else if(n.indexOf(`rel="${je.STATISTICS}"`)>-1){const e=Je(n).get("url");e&&(s=e)}})),O(Ge,`[whipwhep-links]: ${JSON.stringify(i)}`),O(Ge,`[whipwhep-origin]: ${this._origin}`),{links:i.length>0?i:void 0,origin:this._origin,statisticsEndpoint:s}}throw new Error(`Failed to get options: ${i}`)}catch(e){throw k(Ge,e.message),e}}async postSDPOffer(e,t={},i=!0){let n=`${this._url}${ze(this._url)}signal=${this._enableSignalingChannel}`;t&&Object.keys(t).forEach((e=>{-1===Ke.indexOf(e)&&(n+=`&${e}=${t[e]}`)})),this._forceHost&&this._origin&&!(null==t?void 0:t.host)&&(n+=`&host=${this._origin}`),O(Ge,`[whipwhep:post-offer] ${n}: `+JSON.stringify(e,null,2));try{const t={method:"POST",mode:"cors",headers:{"Content-Type":"application/sdp"}};e&&e.length>0&&(t.body=e);const s=await fetch(n,t),{status:o,headers:a}=s;if(a&&a.forEach(((e,t)=>{O(Ge,`[header] ${t}: ${e}`)})),o>=200&&o<300){const e=await s.text(),t=a.get("Location")||a.get("location");if(t){if(t.match(/^(http|https)/))this._resource=t;else{O(Ge,`[whipwhep-response] Location provided as relative path: ${t}`);const e=new URL(this._url);e.pathname=t.split("?")[0],this._resource=e.toString().replace(/\/endpoint\//,"/resource/")}return O(Ge,`[whipwhep-response] ${this._resource}: ${e}`),{sdp:e,location:this._resource}}return H(Ge,"Location not provided in header response to Offer."),this._resource=new URL(this._url).toString().replace(/\/endpoint\//,"/resource/"),{sdp:e,location:this._resource}}if(i&&xe.get(o)){if(O(Ge,xe.get(o)),404===o||409===o)throw new $e(xe.get(o));throw new Error(xe.get(o))}if(!i&&We.get(o)){if(O(Ge,We.get(o)),404===o||409===o)throw new $e(We.get(o));throw new Error(We.get(o))}{const e=await s.text();throw Error(e)}}catch(e){throw k(Ge,e.message),e}}async postSDPAnswer(e,t={}){O(Ge,`[whipwhep:post-answer] ${this._resource}: `+JSON.stringify(e,null,2));let i=this._resource,n=ze(i);t&&Object.keys(t).forEach((e=>{-1===Ke.indexOf(e)&&(n=ze(i),i+=`${n}${e}=${t[e]}`)})),this._forceHost&&this._origin&&!(null==t?void 0:t.host)&&(n=i.indexOf("?")>-1?"&":"?",i+=`${n}host=${this._origin}`);try{const t=await fetch(i,{method:"PATCH",mode:"cors",headers:{"Content-Type":"application/sdp"},body:e}),{status:n}=t;if(n>=200&&n<300)return{success:!0,code:n};if(We.get(n))throw O(Ge,We.get(n)),new Error(We.get(n));{const e=await t.text();throw Error(e)}}catch(e){throw k(Ge,e.message),e}}async trickle(e,t={}){O(Ge,`[whipwhep-trickle] ${this._resource}: `+JSON.stringify(e,null,2));let i=this._resource,n=ze(i);t&&Object.keys(t).forEach((e=>{-1===Ke.indexOf(e)&&(n=ze(i),i+=`${n}${e}=${t[e]}`)})),this._forceHost&&this._origin&&!(null==t?void 0:t.host)&&(n=ze(i),i+=`${n}host=${this._origin}`);try{const t=await fetch(i,{method:"PATCH",mode:"cors",headers:{"Content-Type":"application/trickle-ice-sdpfrag"},body:e}),{status:n}=t;if(n>=200&&n<300){const e=await t.text();return O(Ge,`[whipwhep-response] ${this._resource}: ${e}`),{candidate:e}}if(405===n)throw O(Ge,"Remember to update the URL passed into the WHIP or WHEP client"),new Error("Remember to update the URL passed into the WHIP or WHEP client");{const e=await t.text();throw Error(e)}}catch(e){throw k(Ge,e.message),e}}async tearDown(e={},t=!1){if(!this._resource)return;let i=this._resource,n=ze(i);e&&Object.keys(e).forEach((t=>{-1===Ke.indexOf(t)&&(n=ze(i),i+=`${n}${t}=${e[t]}`)})),this._forceHost&&this._origin&&!(null==e?void 0:e.host)&&(n=ze(i),i+=`${n}host=${this._origin}`),O(Ge,"[whipwhep-teardown]");try{await fetch(i,{method:"DELETE",mode:"cors"})}catch(e){if(k(Ge,e.message),!t)throw e}this._url=void 0,this._origin=void 0,this._resource=void 0,this._forceHost=!1,this._enableSignalingChannel=!1}async post(){return O(Ge,"[whipwhep:post] transport called."),Promise.resolve(!1)}async postAsync(){return O(Ge,"[whipwhep:postAsync] transport called."),Promise.resolve(null)}getUrl(){return this._url}}const qe="R5ProPublishView";class Xe{constructor(e="red5pro-publisher"){try{this._targetElement=ie.resolveElement(e)}catch(e){throw k(qe,`Could not instantiate a new instance of PublishView. Reason: ${e.message}`),e}}preview(e){const t=this.isAutoplay;O(qe,`[preview]: autoplay(${t})`),ie.setVideoSource(this._targetElement,e,t)}unpreview(){ie.setVideoSource(this._targetElement,null,this.isAutoplay)}get isAutoplay(){return ie.hasAttributeDefined(this._targetElement,"autoplay")}get view(){return this._targetElement}}var Qe,Ze;!function(e){e.INBOUND="inbound-rtp",e.OUTBOUND="outbound-rtp",e.CODEC="codec",e.MEDIA_SOURCE="media-source",e.CANDIDATE_PAIR="candidate-pair",e.CERTIFICATE="certificate",e.DATA_CHANNEL="data-channel",e.LOCAL_CANDIDATE="local-candidate",e.REMOTE_CANDIDATE="remote-candidate",e.PEER_CONNECTION="peer-connection",e.REMOTE_INBOUND="remote-inbound-rtp",e.REMOTE_OUTBOUND="remote-outbound-rtp",e.TRANSPORT="transport"}(Qe||(Qe={})),function(e){e.STALE_STATS="STALE_STATS",e.STATE_REGRESSION="STATE_REGRESSION",e.EXCESSIVE_RTT="EXCESSIVE_RTT",e.ICE_TIMEOUT="ICE_TIMEOUT"}(Ze||(Ze={}));class et{constructor(e,t,i,n){this._name="RTCStatsMonitor",this._queue=[],this._startTime=0,this._stopped=!1,this._interval=0,this._candidatePairHealth=new Map,this._name=e,this._renegotiationPolicy=n,this._config={..._e,...t},this._client=i,this._identifier={name:this._name,created:(new Date).getTime(),fingerprint:ie.getOrGenerateFingerprint(),device:ie.getBrowserDetails(),client:t}}_emptyStatsReportQueue(){for(;this._queue.length>0;){const e=this._client.getMessageTransport();if(e){const t=this._queue.shift();e.post(t)}else H(this._name,"Failed to post stats data to message transport. Message transport is not available.")}}_getStats(){const{_connection:e}=this;if(e)try{e.getStats(null).then((e=>{e.forEach((e=>{this._handleStatsReport(e)}))})).catch((e=>{k(this._name,`Failed to get stats report. ${e.message||e}`)}))}catch(e){k(this._name,`Failed to get stats report. ${e.message||e}`)}}_handleStatsReport(e){console.log(`[${this._name}]: ${JSON.stringify(e,null,2)}`)}_appendClientDetails(e){this._identifier.client={...this._identifier.client,...e}}async start(e){this._startTime=(new Date).getTime(),this._stopped=!1,this._connection=e,this.postAction("started"),this._getStats(),this._interval=setInterval((()=>{this._stopped||this._getStats()}),this._config.interval)}stop(){this._stopped=!0,clearInterval(this._interval),this.postAction("ended")}async post(e){const t={...this._identifier,type:"stats-report",timestamp:(new Date).getTime(),data:e},{endpoint:i,additionalHeaders:n}=this._config;if(i===pe.DEV_NULL)return;if(this._client&&this._client.onStatsReport&&(null===i||i===pe.EVENT_TRANSPORT))return void this._client.onStatsReport(this._connection,t);let s={"Content-Type":"application/json"};if(n&&(s={...s,...n}),i&&i.match(/^(http|https):\/\//))try{const e=await fetch(i,{method:"POST",headers:s,body:JSON.stringify(t)});e.status>=200&&e.status<300?O(this._name,`Posted stats data to endpoint: ${i}.`):k(this._name,`Failed to post stats data to endpoint: ${i}. ${e.status}`)}catch(e){k(this._name,`Failed to post stats data to endpoint: ${i}. ${e.message||e}`)}else if(this._client&&this._client.getMessageTransport()&&(void 0===i||i===pe.DATA_CHANNEL))try{let e=!1;const i=this._client.getMessageTransport();i&&(e=await i.post(t)),e||(this._queue.push(t),this._client.on(ye.CHANGE,(()=>{this._client.off(ye.CHANGE),this._emptyStatsReportQueue()})),H(this._name,"Failed to post stats data to message transport. Message transport is not available. Pushed to Queue."))}catch(e){k(this._name,`Failed to post stats data to message transport. ${e.message||e}`)}}async postAction(e,t=void 0){return this.post({action:{type:e,data:t,timestamp:(new Date).getTime()}})}async postEvent(e,t){return this.post({event:{type:e,data:t||void 0,timestamp:(new Date).getTime()}})}updateEndpoint(e,t=!0){const{endpoint:i}=this._config;t?this._config.endpoint=e:t||i||(this._config.endpoint=e)}_checkCandidatePairHealth(e){var t;const{id:i,state:n,currentRoundTripTime:s,totalRoundTripTime:o}=e,a="connected"===this._client.getPeerConnection().iceConnectionState,r=(new Date).getTime();this._candidatePairHealth.has(i)||this._candidatePairHealth.set(i,{id:i,staleSampleCount:0,stateTransitionTime:r,inProgressStartTime:"in-progress"===n?r:void 0});const l=this._candidatePairHealth.get(i);if(void 0!==l.previousRTT&&void 0!==l.previousTotalRTT&&void 0!==s&&void 0!==o&&(s===l.previousRTT&&o===l.previousTotalRTT?(l.staleSampleCount++,l.staleSampleCount>=3&&l.lastIssueReported!==Ze.STALE_STATS&&(this._client.emit(Ne.CONNECTION_HEALTH_STALE_STATS,{candidatePairId:i,frozenRTT:s,frozenTotalRTT:o,staleDurationSeconds:l.staleSampleCount,message:"RTT values frozen - connection may be dead"}),l.lastIssueReported=Ze.STALE_STATS)):(l.staleSampleCount=0,l.lastIssueReported===Ze.STALE_STATS&&(l.lastIssueReported=void 0))),"succeeded"!==l.previousState||"succeeded"===n||a||(this._client.emit(Ne.CONNECTION_HEALTH_STATE_REGRESSION,{candidatePairId:i,previousState:l.previousState,currentState:n,message:`ICE candidate pair regressed from '${l.previousState}' to '${n}' - connection lost`}),l.lastIssueReported=Ze.STATE_REGRESSION,l.stateTransitionTime=r),void 0!==s&&s>1&&l.lastIssueReported!==Ze.EXCESSIVE_RTT?(this._client.emit(Ne.CONNECTION_HEALTH_EXCESSIVE_RTT,{candidatePairId:i,currentRTT:s,message:`Excessive RTT detected: ${(1e3*s).toFixed(0)}ms - possible network issues`}),l.lastIssueReported=Ze.EXCESSIVE_RTT):void 0!==s&&s<=1&&l.lastIssueReported===Ze.EXCESSIVE_RTT&&(l.lastIssueReported=void 0),"in-progress"===n){l.inProgressStartTime||(l.inProgressStartTime=r);const e=r-l.inProgressStartTime;e>((null===(t=this._renegotiationPolicy)||void 0===t?void 0:t.iceTimeoutInterval)||5e3)&&l.lastIssueReported!==Ze.ICE_TIMEOUT&&(this._client.emit(Ne.CONNECTION_HEALTH_ICE_TIMEOUT,{candidatePairId:i,durationSeconds:Math.floor(e/1e3),message:`ICE negotiation timeout - candidate pair stuck in 'in-progress' for ${Math.floor(e/1e3)}s`}),l.lastIssueReported=Ze.ICE_TIMEOUT)}else l.inProgressStartTime=void 0,l.lastIssueReported===Ze.ICE_TIMEOUT&&(l.lastIssueReported=void 0);l.previousState=n,l.previousRTT=s,l.previousTotalRTT=o,n!==l.previousState&&(l.stateTransitionTime=r)}dispose(){this.stop(),this._candidatePairHealth.clear(),this._connection=void 0,this._client=void 0}}const tt=/(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b) \d+ typ srflx/,it=e=>{const t=e.match(tt);return t&&t.length>1?t[1]:null},nt=[fe.PUBLISH_START,fe.PUBLISH_FAIL,fe.PUBLISH_INSUFFICIENT_BANDWIDTH,fe.PUBLISH_SUFFICIENT_BANDWIDTH,fe.PUBLISH_RECOVERING_BANDWIDTH,fe.STATISTICS_ENDPOINT_CHANGE];class st extends et{constructor(e,t){if(super("RTCPublisherStats",e,t),this.estimatedAudioBitrate=0,this.estimatedVideoBitrate=0,this.lastAudioReport=null,this.lastVideoReport=null,this._eventHandler=e=>{const{type:t,data:i}=e;if(nt.indexOf(t)>-1){if(t===fe.STATISTICS_ENDPOINT_CHANGE){const{statisticsEndpoint:e}=i;this.updateEndpoint(e,!1)}this.postEvent(t)}},this._candidateCreateHandler=({data:{candidate:e}})=>{const{candidate:t}=e,i=it(t);i&&(this._identifier.publicIP=i)},this._hostEndpointChangedHandler=({data:{endpoint:e,iceServers:t}})=>{this._appendClientDetails({node:e,iceServers:t})},this._client.on("*",this._eventHandler),this._client.on(Te.CANDIDATE_CREATE,this._candidateCreateHandler),this._client.on(Te.HOST_ENDPOINT_CHANGED,this._hostEndpointChangedHandler),this._client.getPeerConnection())this.start(this._client.getPeerConnection());else{const e=({data:t})=>{this._client.off(Te.PEER_CONNECTION_AVAILABLE,e),this.start(t)};this._client.on(Te.PEER_CONNECTION_AVAILABLE,e)}}_handleStatsReport(e){const{type:t}=e,{include:i}=this._config,n=i&&i.length>0;if(n&&i.indexOf(t)>=-1)this.post(e);else if(!n)if(t===Qe.CODEC){const{id:i,clockRate:n,mimeType:s,payloadType:o}=e;this.post({id:i,type:t,clockRate:n,mimeType:s,payloadType:o})}else if(t===Qe.CANDIDATE_PAIR){const{availableOutgoingBitrate:i,currentRoundTripTime:n,totalRoundTripTime:s,state:o}=e;this._checkCandidatePairHealth(e),this.post({type:t,availableOutgoingBitrate:i,currentRoundTripTime:n,totalRoundTripTime:s,state:o})}else if(t===Qe.MEDIA_SOURCE){const{kind:i}=e;if("audio"===i)this.post({type:t,kind:i});else if("video"===i){const{framesPerSecond:n,height:s,width:o}=e;this.post({type:t,kind:i,framesPerSecond:n,height:s,width:o})}}else if([Qe.OUTBOUND,"outboundrtp"].indexOf(t)>-1){const{timestamp:i,kind:n,codecId:s,mediaType:o,active:a,bytesSent:r,packetsSent:l,totalPacketsSendDelay:d}=e,h={type:t,kind:n,codecId:s,mediaType:o,active:a,bytesSent:r,packetsSent:l,totalPacketsSendDelay:d};if("audio"===n){if(this.lastAudioReport){const{bytesSent:e,timestamp:t}=this.lastAudioReport,n=8*(r-e)/(i-t);this.estimatedAudioBitrate=n}this.post({...h,estimatedBitrate:Math.floor(this.estimatedAudioBitrate)}),this.lastAudioReport=e}else if("video"===n){const{firCount:t,pliCount:n,frameWidth:s,frameHeight:o,framesEncoded:a,framesPerSecond:l,framesSent:d,keyFramesEncoded:c,qualityLimitationReason:u,qualityLimitationDurations:_}=e;let p={...h,firCount:t,pliCount:n,frameWidth:s,frameHeight:o,framesEncoded:a,framesPerSecond:l,framesSent:d,keyFramesEncoded:c,qualityLimitationReason:"none"!==u?u:void 0,qualityLimitationDurations:"none"!==u?_:void 0};if(this.lastVideoReport){const{bytesSent:e,timestamp:t}=this.lastVideoReport,n=8*(r-e)/(i-t);this.estimatedVideoBitrate=n}this.post({...p,estimatedBitrate:Math.floor(this.estimatedVideoBitrate)}),this.lastVideoReport=e}}}dispose(){this._client.off("*",this._eventHandler),this._client.off(Te.CANDIDATE_CREATE,this._candidateCreateHandler),this._client.off(Te.HOST_ENDPOINT_CHANGED,this._hostEndpointChangedHandler),super.dispose()}}const ot={pubnub:window.PubNub,userId:`user-${Math.floor(65536*Math.random()).toString(16)}`,publishKey:void 0,subscribeKey:void 0,authToken:void 0,cloudEndpoint:void 0,backendUrl:void 0,backendURL:void 0,expiryMinutes:120,channelId:"red5",logLevel:"trace"};var at;!function(e){e.CONNECTED="PubNub.Connected",e.DISCONNECTED="PubNub.Disconnected",e.SUBSCRIBE_SUCCESS="PubNub.Subscribe.Success",e.SUBSCRIBE_FAILURE="PubNub.Subscribe.Failure",e.UNSUBSCRIBE_SUCCESS="PubNub.Unsubscribe.Success",e.UNSUBSCRIBE_FAILURE="PubNub.Unsubscribe.Failure",e.MESSAGE_RECEIVED="PubNub.Message.Received",e.MESSAGE_SEND_SUCCESS="PubNub.Message.Send.Success",e.MESSAGE_SEND_FAILURE="PubNub.Message.Send.Failure",e.AUTH_TOKEN_GENERATED="PubNub.AuthToken.Generated",e.AUTH_TOKEN_GENERATION_ERROR="PubNub.AuthToken.Generation.Error",e.STATUS="PubNub.Status",e.ERROR="PubNub.Error"}(at||(at={}));const rt="PubNubService";class lt{constructor(){}_decodeToken(e){const t=e.split(".")[1].replace(/-/g,"+").replace(/_/g,"/"),i=decodeURIComponent(atob(t).split("").map((e=>"%"+("00"+e.charCodeAt(0).toString(16)).slice(-2))).join(""));return JSON.parse(i)}async getAuthTokenFromBackendService(e){var t;const{userId:i,backendUrl:n,backendURL:s,channelId:o="red5",expiryMinutes:a=120}=e;if(!n&&!s)throw new Error("Backend URL is required. Please provide a backend URL in the pubnub configuration.");const r={userId:i,channelId:o,read:!0,write:!0,ttlMinutes:a};try{const e=await fetch(n||s,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)});if(!e.ok)throw new Error("Failed to generate auth token. Please try again later.");const t=await e.json(),{token:i}=t;return i}catch(e){throw new Error(null!==(t=e.message)&&void 0!==t?t:"Failed to generate auth token. Please try again later.")}}async getAuthTokenFromCloud(e){var t;const{userId:i,cloudEndpoint:n,publishKey:s,subscribeKey:o,channelId:a="red5",expiryMinutes:r=120}=e;if(!n)throw new Error("Cloud endpoint is required. Please provide a cloud endpoint in the pubnub configuration.");try{const e=n.match(/^https?:\/\//)?n:`https://${n}`,t=await fetch(`${e}/config-meetings/api/generate-token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({userId:i,channelId:a,expirationMinutes:r})});if(!t.ok)throw new Error("Failed to generate auth token. Please try again later.");const d=await t.json(),{success:h,token:c}=d;if(!h)throw new Error("Failed to generate auth token. Please try again later.");const u=this._decodeToken(c);if(!u)throw new Error("Failed to decode auth token. Please try again later.");l=`[${rt}] :: Decoded auth token: ${JSON.stringify(u)}`,O(rt,l);const{uid:_,roomId:p,pubnubPublishKey:g,pubnubSubscribeKey:m,pubnubToken:v}=u;if(_!==i||p!==a)throw new Error("Invalid auth token. Please try again later.");if(g!==s||m!==o)throw new Error("Invalid auth token. Please try again later.");return v}catch(e){throw new Error(null!==(t=e.message)&&void 0!==t?t:"Failed to generate auth token. Please try again later.")}var l}}const dt="PubNubClient",ht={receivePresenceEvents:!0,withPresence:!1},ct=e=>O(dt,e),ut=e=>H(dt,e),_t=e=>k(dt,e);class pt extends M{constructor(){super(),this._subscriptions={}}async _getAuthFromCloud(e){const t=new lt;return await t.getAuthTokenFromCloud(e)}async _getAuthFromBackend(e){const t=new lt;return await t.getAuthTokenFromBackendService(e)}async init(e){var t,i,n,s,o,a,r;if(this._config={...ot,...e},(null===(t=this._config)||void 0===t?void 0:t.cloudEndpoint)||(null===(i=this._config)||void 0===i?void 0:i.backendUrl)||(null===(n=this._config)||void 0===n?void 0:n.backendURL)){let e;try{if((null===(s=this._config)||void 0===s?void 0:s.cloudEndpoint)?e=await this._getAuthFromCloud(this._config):((null===(o=this._config)||void 0===o?void 0:o.backendUrl)||(null===(a=this._config)||void 0===a?void 0:a.backendURL))&&(e=await this._getAuthFromBackend(this._config)),!e)throw new Error("Failed to get auth token.");this._config.authToken=e,this.trigger(new be(at.AUTH_TOKEN_GENERATED,this,{authToken:e}))}catch(e){return _t(null!==(r=e.message)&&void 0!==r?r:"Failed to get auth token."),this.trigger(new be(at.AUTH_TOKEN_GENERATION_ERROR,this,{error:e.message})),this}}const{pubnub:l,publishKey:d,subscribeKey:h,authToken:c,userId:u,logLevel:_}=this._config;if(!l){const e="PubNub library is not initialized. Please provide a PubNub library reference in the configuration.";throw this.trigger(new be(at.ERROR,this,{error:e})),_t(e),new Error(e)}return ct(`Initializing PubNub client with options: ${JSON.stringify(this._config)}`),this._pubnub=new l({userId:u,publishKey:d,subscribeKey:h,logLevel:_}),this._pubnub.setToken(c),this._pubnub.addListener({message:e=>{var t;ct(`Message received on channel ${e.channel}: ${e.message}`),this.trigger(new be(at.MESSAGE_RECEIVED,this,{...e,userId:null===(t=this._config)||void 0===t?void 0:t.userId}))},presence:e=>{ct(`Presence event on channel ${e.channel}: ${JSON.stringify(e)}`)},status:e=>{const{category:t,operation:i}=e;ct(`Status event ${t}`),this.trigger(new be(at.STATUS,this,e)),"PNConnectedCategory"===t?(this.trigger(new be(at.CONNECTED,this,e)),"PNSubscribeOperation"===i&&this.trigger(new be(at.SUBSCRIBE_SUCCESS,this,e))):"PNDisconnectedCategory"===t?this.trigger(new be(at.DISCONNECTED,this,e)):"PNReconnectedCategory"===t||("PNAcknowledgmentCategory"===t?"PNUnsubscribeOperation"===i&&this.trigger(new be(at.UNSUBSCRIBE_SUCCESS,this,e)):("PNBadRequestCategory"===t||"PNAccessDeniedCategory"===t)&&this.trigger(new be(at.ERROR,this,e)))}}),this}async publishMessage(e,t){var i,n;if(!this._pubnub)return _t("PubNub client not initialized."),!1;try{const n=await this._pubnub.publish({channel:e,message:t});this.trigger(new be(at.MESSAGE_SEND_SUCCESS,this,{...n,channel:e,message:t,userId:null===(i=this._config)||void 0===i?void 0:i.userId}))}catch(i){return _t(null!==(n=i.message)&&void 0!==n?n:`Failed to publish message to channel ${e}.`),this.trigger(new be(at.MESSAGE_SEND_FAILURE,this,{channel:e,message:t})),!1}return!0}async subscribe(e,t){var i;if(!this._pubnub)return _t("PubNub client not initialized."),!1;if(this._subscriptions[e])return!0;try{const i=this._pubnub.channel(e),n=await i.subscription({...ht,...t});if(!n)throw new Error(`Failed to subscribe to channel ${e}.`);n.subscribe(),this._subscriptions[e]=n}catch(t){return _t(null!==(i=t.message)&&void 0!==i?i:`Failed to subscribe to channel ${e}.`),this.trigger(new be(at.SUBSCRIBE_FAILURE,this,{channel:e})),!1}return!0}async unsubscribe(e){var t;if(!this._pubnub)return!0;if(!this._subscriptions[e])return ut(`Subscription ${e} not found.`),!1;try{await this._subscriptions[e].unsubscribe()}catch(i){_t(null!==(t=i.message)&&void 0!==t?t:`Failed to unsubscribe from channel ${e}.`),this.trigger(new be(at.UNSUBSCRIBE_FAILURE,this,{channel:e}))}return delete this._subscriptions[e],!0}async destroy(){var e;if(this._pubnub)try{await this._pubnub.destroy()}catch(t){ut(null!==(e=t.message)&&void 0!==e?e:"Failed to destroy PubNub client.")}return this._subscriptions={},this._pubnub=void 0,this._config=void 0,!0}getOptions(){var e;return null!==(e=this._config)&&void 0!==e?e:{}}get config(){return this._config}get pubnub(){return this._pubnub}}const gt="WHIPClient",mt=ge,vt=e=>O(gt,e),Et=e=>k(gt,e),St=e=>H(gt,e);class Ct extends M{constructor(e,t,i){super();const n=e?se(e):mt,s=i||mt,o={...s,...n,endpoint:e,mediaElementId:t?t.id:s.mediaElementId};e&&this.internalInit(o),this._onOrientationChange=this._onOrientationChange.bind(this)}async internalInit(e){await this.init(e),await this.publish()}async generateMediaStream(e){var t,i;const{onGetUserMedia:n}=e;if(n){vt("Requesting gUM from user-defined configuration:onGetUserMedia.");const e=await n();return this.trigger(new Ee(Te.CONSTRAINTS_ACCEPTED,this,ae(e))),e}{const{mediaConstraints:n}=e;let s;vt(`Requesting gUM using mediaConstraints: ${JSON.stringify(n,null,2)}`);let o=n;const a=await Me(o);return a&&a.media||(s=await ie.gUM(o)),s=null!==(t=null==a?void 0:a.media)&&void 0!==t?t:s,o=null!==(i=null==a?void 0:a.constraints)&&void 0!==i?i:n,vt(`Constraints accepted: ${JSON.stringify(o,null,2)}`),this.trigger(new Ee(Te.CONSTRAINTS_ACCEPTED,this,{constraints:o,...ae(s)})),s}}async getAndPreviewStreamIfAvailable(){var e;let t=this._mediaStream;if(!t){try{t=null!=t?t:await this.generateMediaStream(this._options)}catch(t){const i=null!==(e=t.message)&&void 0!==e?e:"Could not generate media stream.";throw this.trigger(new Ee(Te.CONSTRAINTS_REJECTED,this,{constraints:this._options.mediaConstraints})),new Error(i)}if(!t)throw new Error("Could not generate media stream.")}return this.trigger(new Ee(Te.MEDIA_STREAM_AVAILABLE,this,t)),this.preview(t),t}reorderCodecPreferences(e,t,i){e.getTransceivers().forEach((e=>{if(e.sender&&e.sender.track){const{kind:n}=e.sender.track;if(t&&"video"===n&&e.setCodecPreferences)try{const{codecs:i}=RTCRtpSender.getCapabilities("video"),n=i.findIndex((e=>e.mimeType===`video/${t}`));if(n>-1){const t=i.slice(0),s=i[n];t.splice(n,1),t.unshift(s),e.setCodecPreferences(t)}}catch(e){St(`[videoEncoding] Could not set codec preferences for ${t}. ${e.message||e}`)}else if(i&&"audio"===n&&e.setCodecPreferences)try{const{codecs:t}=RTCRtpSender.getCapabilities("audio"),n=t.findIndex((e=>e.mimeType===`audio/${i}`));if(n>-1){const i=t[n];t.splice(n,1),t.unshift(i),e.setCodecPreferences(t)}}catch(e){St(`[audioEncoding] Could not set codec preferences for ${i}. ${e.message||e}`)}}}))}async postOffer(e){var t;try{const{sdp:i}=e;let{videoEncoding:n}=this._options;const{mungeOffer:s,streamMode:o,keyFramerate:a,iceTransport:r,connectionParams:d,mediaConstraints:h,forceVP8:c,audioEncoding:u,offerSDPResolution:_}=this._options;c&&!n&&(n=l.VP8);let p=i;s&&(vt(`[MUNGE:before] offer: ${p}`),p=s(p),vt(`[MUNGE:after] offer: ${p}`)),_&&(vt(`[MUNGE] Setting resolution on offer: ${p}`),p=((e,t)=>{if(!t)return e;const{width:i,height:n}=t;if(!i||!n)return e;const s=`a=framesize:${i}-${n}`,o=e.split("\r\n");let a=o.length;const r=/^m=video/;for(;--a>-1;)if(r.exec(o[a])){for(;++a-1){o.splice(a+1,0,s);break}break}return o.join("\r\n")})(p,((e,t)=>{let i;if(e)try{const t=e.getVideoTracks()&&e.getVideoTracks()[0];if(t){const e=t.getSettings();i={width:e.width,height:e.height}}}catch(e){H("[determineMediaResolution]",`Could not determine resolution from MediaStream. ${e.message||e}`)}if(!i)try{const e=t.video,{width:n,height:s}=e;if(n&&s)if("number"==typeof n&&"number"==typeof s)i={width:n,height:s};else{i={width:n.exact||n.min||n.max||n.ideal||640,height:s.exact||s.min||s.max||s.ideal||480}}}catch(e){H("[determineMediaResolution]",`Could not determine resolution from MediaConstraints. ${e.message||e}`)}return i&&O("[determineMediaResolution]",`constraints: ${JSON.stringify(i,null,2)}`),i})(this._mediaStream,h)),vt(`[MUNGE:after] offer: ${p}`));const g={...d,mode:o,transport:r,keyFramerate:a};return n&&(g.videoEncoding=n),u&&(g.audioEncoding=u),await(null===(t=this._whipWhepService)||void 0===t?void 0:t.postSDPOffer(p,g))}catch(e){throw Et(e.message||e),e instanceof $e?this.trigger(new Ee(fe.PUBLISH_INVALID_NAME,this)):(this.trigger(new Ee(fe.CONNECT_FAILURE,this,e)),this.unpublish()),e}}async postCandidateFragments(e){var t;const{connectionParams:i}=this._options,n=Be(e,void 0,!0);return await(null===(t=this._whipWhepService)||void 0===t?void 0:t.trickle(n,i))}async initPubNub(e){var t;try{const t=new pt;this._pubnubClient=t,this._pubnubClient.on("*",(e=>{this.trigger(e)})),await t.init(e)}catch(e){return e(null!==(t=e.message)&&void 0!==t?t:"Failed to initialize PubNub."),!1}return!0}async deinitPubNub(){var e,t;try{await(null===(e=this._pubnubClient)||void 0===e?void 0:e.destroy()),this._pubnubClient=void 0}catch(e){return e(null!==(t=e.message)&&void 0!==t?t:"Failed to deinitialize PubNub."),!1}return!0}async init(e){var t,i;this._options={...mt,...e};const n=oe(this._options),{includeDataChannel:s,disableProxy:o}=this._options;return this._whipWhepService=new Ye(n,s,o),this._messageTransport=this._whipWhepService,(null===(t=this._options)||void 0===t?void 0:t.stats)&&this.monitorStats(this._options.stats),this._mediaStream=await this.getAndPreviewStreamIfAvailable(),(null===(i=this._options)||void 0===i?void 0:i.pubnub)&&await this.initPubNub(this._options.pubnub),this}async initWithStream(e,t){return this._mediaStream=t,this.init(e)}async publish(e){var t,i,n,s,o;e&&(this._options.streamName=e);const{forceVP8:a,audioEncoding:r,rtcConfiguration:d,dataChannelConfiguration:h,includeDataChannel:c,signalingSocketOnly:u,enableChannelSignaling:_,connectionParams:p,bandwidth:g,mungeAnswer:m}=this._options;let{videoEncoding:v}=this._options;a&&(v=l.VP8,this._options.videoEncoding=v),this._mediaStream||(this._mediaStream=await this.getAndPreviewStreamIfAvailable());try{const e=null!=p?p:{};if(p){const{transcode:t}=p;t&&(e.transcode=t)}const o=await(null===(t=this._whipWhepService)||void 0===t?void 0:t.getOptions(e)),a=!!(null===(i=this._options)||void 0===i?void 0:i.rtcConfiguration)&&Array.isArray(this._options.rtcConfiguration.iceServers)&&this._options.rtcConfiguration.iceServers.length>0;(null==o?void 0:o.links)&&!a&&(this._options.rtcConfiguration={...d,iceServers:o.links}),(null==o?void 0:o.origin)&&this.trigger(new Ee(Te.HOST_ENDPOINT_CHANGED,this,{endpoint:o.origin})),(null==o?void 0:o.statisticsEndpoint)&&this._onStatisticsEndpointChange(o.statisticsEndpoint);const l=c||_||u?h:void 0;this._peerConnectionHelper=new Fe({onDataChannelError:this._onDataChannelError.bind(this),onSendReceived:this._onSendReceived.bind(this),onMetaData:this._onMetaData.bind(this),onConnectionClosed:this._onConnectionClosed.bind(this),onDataChannelOpen:this._onDataChannelOpen.bind(this),onDataChannelClose:this._onDataChannelClose.bind(this),onDataChannelMessage:this._onDataChannelMessage.bind(this),onPeerConnectionOpen:this._onPeerConnectionOpen.bind(this),onPeerConnectionFail:this._onPeerConnectionFail.bind(this),onPeerConnectionClose:this._onPeerConnectionClose.bind(this),onIceCandidate:this._onIceCandidate.bind(this),onSDPSuccess:this._onSDPSuccess.bind(this),onSDPError:this._onSDPError.bind(this),onStatisticsEndpointChange:this._onStatisticsEndpointChange.bind(this),onPublisherStatus:this._onPublisherStatus.bind(this),onPeerConnectionTrackAdd:this._onPeerConnectionTrackAdd.bind(this),onInsufficientBandwidth:this._onInsufficientBandwidth.bind(this),onSufficientBandwidth:this._onSufficientBandwidth.bind(this),onRecoveringBandwidth:this._onRecoveringBandwidth.bind(this),onUnpublish:this._onUnpublish.bind(this)}),await this._peerConnectionHelper.setUpWithPeerConfiguration(this._options.rtcConfiguration,l),this.trigger(new Ee(Te.PEER_CONNECTION_AVAILABLE,this,this.getPeerConnection())),this._mediaStream.getTracks().forEach((e=>{var t;null===(t=this.getPeerConnection())||void 0===t||t.addTransceiver(e,{direction:"sendonly"})})),this.reorderCodecPreferences(this.getPeerConnection(),v,r);const E=await(null===(n=this._peerConnectionHelper)||void 0===n?void 0:n.createOfferWithoutSetLocal(g));await this._peerConnectionHelper.setLocalDescription(E),this.trigger(new Ee(Te.OFFER_START,this,E));const{sdp:S}=await this.postOffer(E);let C=S;m&&(vt(`[MUNGE:before] answer: ${C}`),C=m(C),vt(`[MUNGE:after] answer: ${C}`)),await this._peerConnectionHelper.setRemoteDescription({type:"answer",sdp:C}),this.trigger(new Ee(Te.OFFER_END,this,C));const b=await this._peerConnectionHelper.waitToGatherIce(),{sdp:f}=b;return await this.postCandidateFragments(f),this.trigger(new Ee(Te.ICE_TRICKLE_COMPLETE,this)),ie.addOrientationChangeHandler(this._onOrientationChange),(null===(s=this._options)||void 0===s?void 0:s.includeDataChannel)||this.trigger(new Ee(fe.PUBLISH_START,this)),this}catch(e){throw Et(null!==(o=e.message)&&void 0!==o?o:"Could not publish."),this.trigger(new Ee(fe.CONNECT_FAILURE,this,e)),this.unpublish(!0),e}}async unpublish(e=!1){var t;vt("[unpublish]"),this._peerConnectionHelper&&await this._peerConnectionHelper.tearDown(),this._whipWhepService&&await this._whipWhepService.tearDown(null,e),(null===(t=this._options)||void 0===t?void 0:t.clearMediaOnUnpublish)&&this.unpreview(),this._pubnubClient&&await this.deinitPubNub(),this._pubnubClient=void 0,this._mediaStream=void 0,this._peerConnectionHelper=void 0,this._whipWhepService=void 0,this._messageTransport=void 0,this._publishView=void 0,this.trigger(new Ee(fe.UNPUBLISH_SUCCESS,this)),ie.removeOrientationChangeHandler(this._onOrientationChange)}preview(e){vt("[preview]");const{mediaElementId:t}=this._options;t&&(this._publishView=new Xe(t),this._publishView.preview(e))}unpreview(){vt("[unpreview]"),this._mediaStream&&this._mediaStream.getTracks().forEach((e=>{e.stop()})),this._publishView&&this._publishView.unpreview(),this._publishView=void 0}monitorStats(e){vt("[monitorStats]");const{host:t,endpoint:i,app:n,streamName:s,connectionParams:o}=this._options,a=null!=e?e:_e;return this._statisticsConfiguration={...a,host:t,hostEndpoint:i,app:n,streamName:s,connectionParams:o},this._statsMonitor?St("Cannot monitor stats without a Peer Connection. Please call `init` before calling `monitorStats`."):this._statsMonitor=new st(this._statisticsConfiguration,{onStatsReport:this._onStatsReport.bind(this),getPeerConnection:this.getPeerConnection.bind(this),getMessageTransport:this.getMessageTransport.bind(this),on:this.on.bind(this),off:this.off.bind(this),trigger:this.trigger.bind(this),emit:this.emit.bind(this)}),this}unmonitorStats(){return this._statsMonitor&&this._statsMonitor.dispose(),this._statsMonitor=void 0,this._statisticsConfiguration=void 0,this}muteAudio(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteAudio:!0}})}unmuteAudio(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteAudio:!1}})}muteVideo(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteVideo:!0}})}unmuteVideo(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteVideo:!1}})}send(e,t){var i;return null===(i=this.getMessageTransport())||void 0===i?void 0:i.post({send:{method:e,data:"string"==typeof t?JSON.parse(t):t}})}async sendPubNub(e,t){return this._pubnubClient?await this._pubnubClient.publishMessage(e,t):(Et("PubNub client not initialized."),!1)}async subscribePubNub(e,t){return this._pubnubClient?await this._pubnubClient.subscribe(e,t):(Et("PubNub client not initialized."),!1)}async unsubscribePubNub(e){return this._pubnubClient?await this._pubnubClient.unsubscribe(e):(Et("PubNub client not initialized."),!1)}async callServer(e,t){var i;try{if(!this.getMessageTransport())throw new Error("Message transport not available");return null===(i=this.getMessageTransport())||void 0===i?void 0:i.postAsync({callAdapter:{method:e,arguments:t}})}catch(e){Et(e.message||e)}}sendLog(e,t){var i;try{const n=Object.keys(P).find((t=>t.toLowerCase()===e.toLowerCase()))?e:P.DEBUG,s="string"==typeof t?t:JSON.stringify(t);null===(i=this.getMessageTransport())||void 0===i||i.post({log:n.toUpperCase(),message:s})}catch(e){const t=e.message||e;Et("Could not send log to server. Message parameter expected to be String or JSON-serializable object."),Et(t)}}get options(){return this._options}getOptions(){return this._options}getPeerConnection(){var e;return null===(e=this._peerConnectionHelper)||void 0===e?void 0:e.connection}getDataChannel(){var e;return null===(e=this._peerConnectionHelper)||void 0===e?void 0:e.dataChannel}getMediaStream(){return this._mediaStream}getMessageTransport(){return this._messageTransport}getPubNubClient(){return this._pubnubClient}_onDataChannelError(e,t){Et(`Data channel error: ${t}`),this.trigger(new Ee(Te.DATA_CHANNEL_ERROR,this,{dataChannel:e,error:t}))}_onSendReceived(e,t){vt(`Send received: ${e} ${JSON.stringify(t)}`),"onMetaData"===e?this._onMetaData(t):this.trigger(new Ee(fe.PUBLISH_SEND_INVOKE,this,{methodName:e,data:t}))}_onMetaData(e){vt(`Metadata received: ${JSON.stringify(e)}`),this.trigger(new Ee(fe.PUBLISH_METADATA,this,e))}_onConnectionClosed(){vt("Connection closed"),this.unpublish(),this.trigger(new Ee(fe.CONNECTION_CLOSED,this))}_onDataChannelOpen(e){vt(`Data channel opened: ${e.label}`),this.trigger(new Ee(Te.DATA_CHANNEL_OPEN,this,{dataChannel:e})),this.trigger(new Ee(Te.DATA_CHANNEL_AVAILABLE,this,{name:e.label,dataChannel:e})),this._messageTransport=this._peerConnectionHelper,this.trigger(new Ce(ye.CHANGE,this,{controller:this,transport:this._messageTransport})),this.trigger(new Ee(fe.PUBLISH_START,this))}_onDataChannelClose(e){vt(`Data channel closed: ${e.label}`),this.trigger(new Ee(Te.DATA_CHANNEL_CLOSE,this,{dataChannel:e}))}_onDataChannelMessage(e,t){vt(`Data channel message: ${t.data}`),this.trigger(new Ee(Te.DATA_CHANNEL_MESSAGE,this,{dataChannel:e,message:t}))}_onPeerConnectionTrackAdd(e){vt(`Peer connection track added: ${e.id}`),this.trigger(new Ee(Te.TRACK_ADDED,this,{track:e}))}_onPeerConnectionOpen(){vt("Peer connection opened"),this.trigger(new Ee(Te.PEER_CONNECTION_OPEN,this,this.getPeerConnection()))}_onPeerConnectionFail(){Et("Peer connection failed"),this.trigger(new Ee(fe.PUBLISH_FAIL,this))}_onPeerConnectionClose(e){vt(`Peer connection closed: ${e.type}`),this._peerConnectionHelper&&this._peerConnectionHelper.tearDown(),this.trigger(new Ee(fe.CONNECTION_CLOSED,this,e))}_onIceCandidate(e){vt(`ICE candidate: ${JSON.stringify(e,null,2)}`),this.trigger(new Ee(Te.CANDIDATE_CREATE,this,{candidate:e}))}_onUnpublish(){vt("Unpublish received")}_onPublisherStatus(e){vt("[publisherstatus] - "+JSON.stringify(e,null,2)),e.code&&"NetStream.Publish.IsAvailable"===e.code?this.trigger(new Ee(fe.PUBLISH_AVAILABLE,this,e)):this.trigger(new Ee(fe.PUBLISH_STATUS,this,e))}_onInsufficientBandwidth(e){this.trigger(new Ee(fe.PUBLISH_INSUFFICIENT_BANDWIDTH,this,e))}_onSufficientBandwidth(e){this.trigger(new Ee(fe.PUBLISH_SUFFICIENT_BANDWIDTH,this,e))}_onRecoveringBandwidth(e){this.trigger(new Ee(fe.PUBLISH_RECOVERING_BANDWIDTH,this,e))}_onSDPSuccess(e=void 0){const t=e?": "+JSON.stringify(e,null,2):"";vt(`[onsdpsuccess]:: ${t}`)}_onSDPError(e=void 0){this.trigger(new Ee(fe.PUBLISH_FAIL,this));const t=e?": "+JSON.stringify(e,null,2):"";Et(`[onsdperror]:: ${t}`)}_onOrientationChange(e){const t=this.getMessageTransport();t&&t.post({send:{method:"onMetaData",data:{deviceOrientation:e}}})}_onStatisticsEndpointChange(e){vt(`Statistics endpoint changed: ${e}`),this._statsMonitor&&this._statsMonitor.updateEndpoint(e),this.trigger(new Ee(fe.STATISTICS_ENDPOINT_CHANGE,this,{statisticsEndpoint:e}))}_onStatsReport(e,t){this.trigger(new Ee(Te.STATS_REPORT,this,{connection:e,report:t}))}on(e,t){super.on(e,t)}off(e,t){super.off(e,t)}trigger(e){super.trigger(e)}emit(e,t){this.trigger(new Ee(e,this,t))}getType(){return"RTC"}}const bt={...{protocol:"https",port:443,app:"live",autoLayoutOrientation:!0,mediaElementId:"red5pro-subscriber",rtcConfiguration:{iceCandidatePoolSize:2,bundlePolicy:"max-bundle"},iceTransport:de.UDP,muteOnAutoplayRestriction:!0,maintainConnectionOnSubscribeErrors:!1,dataChannelConfiguration:{name:"red5pro"},signalingSocketOnly:!1,includeDataChannel:!0,maintainStreamVariant:!1,buffer:0,stats:void 0,pubnub:void 0,renegotiationPolicy:void 0},signalingSocketOnly:!1,enableChannelSignaling:!1,includeDataChannel:!0,disableProxy:!0,trickleIce:!0,postEmptyOffer:!1,mungeOffer:void 0,mungeAnswer:void 0},ft={protocol:"https",port:443,app:"live",mediaElementId:"red5pro-subscriber",muteOnAutoplayRestriction:!0},Tt={endpoint:pe.DEV_NULL,interval:3e3},wt="R5ProPlaybackView";class At{constructor(e="red5pro-subscriber"){try{this._targetElement=ie.resolveElement(e)}catch(e){throw k(wt,`Could not instantiate a new instance of Red5ProSubscriber. Reason: ${e.message||e}`),e}}attachStream(e){const t=this.isAutoplay;O(wt,"[attachstream]"),ie.setVideoSource(this._targetElement,e,t)}detachStream(){O(wt,"[detachstream]"),ie.setVideoSource(this._targetElement,null,this.isAutoplay)}get isAutoplay(){return ie.hasAttributeDefined(this._targetElement,"autoplay")}get view(){return this._targetElement}}const yt="RTCPeerConnectionSubscriber";class Nt extends Pe{constructor(e){super(e,yt)}_removeConnectionHandlers(e){e.onconnectionstatechange=null,e.oniceconnectionstatechange=null,e.onicegatheringstatechange=null,e.onsignalingstatechange=null,e.onicecandidate=null,e.ontrack=null,e.onnegotiationneeded=null}_addConnectionHandlers(e){let t;e.onsignalingstatechange=()=>{const t=e.signalingState;O(yt,`[peer.onsignalingstatechange] - State: ${t}`)},e.onconnectionstatechange=()=>{const{connectionState:t}=e;"connected"===t?(O(this._name,"[peerconnection:open]"),this._responder.onPeerConnectionOpen()):"failed"===t||"disconnected"===t?(H(this._name,`[peerconnection:error]:: ${t}`),"failed"===t&&this._responder.onPeerConnectionFail()):O(this._name,`[peerconnection:state]:: ${t}`)},e.oniceconnectionstatechange=i=>{const{iceConnectionState:n}=e;O(this._name,`[peer.oniceconnectionstatechange] - State: ${n}`),"failed"===n?(t&&clearTimeout(t),this._responder.onPeerConnectionFail(),this._responder.onPeerConnectionClose(i)):"disconnected"===n?t=setTimeout((()=>{O(this._name,"[peer.oniceconnectionstatechange] - Reconnect timeout reached."),clearTimeout(t),this._responder.onPeerConnectionClose(i)}),3e3):t&&(O(this._name,"[peer.oniceconnectionstatechange] - Clearing timeout for reconnect."),clearTimeout(t))},e.onicecandidate=e=>{const{candidate:t}=e;O(this._name,`[peer.onicecandidate] - Peer Candidate: ${null==t?void 0:t.candidate}`),t&&this._responder.onIceCandidate(t)},e.onnegotiationneeded=()=>{O(this._name,"[peer.onnegotiationneeded]")},e.onicegatheringstatechange=()=>{const{iceGatheringState:t}=e;O(this._name,`[peer.onicegatheringstatechange] - State: ${t}`)}}_onDataChannelMessage(e){const t=e;if(super._onDataChannelMessage(e))return!0;const i=this.getJsonFromSocketMessage(t);if(null===i)return H(this._name,"Determined websocket response not in correct format. Aborting message handle."),!0;O(this._name,"[datachannel-response]: "+JSON.stringify(i,null,2));const{data:n}=i;if(n&&"status"===n.type)return"NetStream.Play.UnpublishNotify"===n.code?(this._responder.onUnpublish(),this._responder.onConnectionClosed(),!0):"Application.Statistics.Endpoint"===n.code?(this._responder.onStatisticsEndpointChange(n.statistics),!0):(O(yt,`[datachannel.message] status :: ${n.code}`),this._responder.onSubscriberStatus(n),!0);if(n&&n.status&&"NetStream.Play.UnpublishNotify"===n.status)return this._responder.onUnpublish(),this._responder.onConnectionClosed(),!0;if(n&&"result"===n.type){const{message:e}=n;if("Stream switch: Success"===e)try{return this._responder.onStreamSwitchComplete(),!0}catch(e){}}return this._responder.onDataChannelMessage(this._dataChannel,t),!1}}var Lt;!function(e){e.EMPTY="Empty",e.VIDEO="Video",e.AUDIO="Audio",e.FULL="Video/Audio"}(Lt||(Lt={}));class Pt extends M{trigger(e){super.trigger(e)}on(e,t){super.on(e,t)}off(e,t){super.off(e,t)}}class Rt extends Pt{}const It=[we.SUBSCRIBE_START,we.SUBSCRIBE_STOP,we.SUBSCRIBE_FAIL,we.SUBSCRIBE_PUBLISHER_CONGESTION,we.SUBSCRIBE_PUBLISHER_RECOVERY,we.PLAY_UNPUBLISH,we.STREAMING_MODE_CHANGE,we.PLAYBACK_STATE_CHANGE,we.STATISTICS_ENDPOINT_CHANGE];class Dt extends et{constructor(e,t,n){if(super("RTCSubscriberStats",e,t,n),this.estimatedAudioBitrate=0,this.estimatedVideoBitrate=0,this.lastAudioReport=null,this.lastVideoReport=null,this._eventHandler=e=>{const{type:t,data:n}=e;if(It.indexOf(t)>-1)if(t===we.STREAMING_MODE_CHANGE){const{streamingMode:e,previousStreamingMode:i}=n;this.postEvent(t,{data:{streamingMode:e,previousStreamingMode:i}})}else if(t===we.PLAYBACK_STATE_CHANGE){const{code:e}=n;let t;e===i.AVAILABLE&&(t={timeToFirstFrameMS:(new Date).getTime()-this._startTime}),this.postEvent(s[e],t)}else{if(t===we.STATISTICS_ENDPOINT_CHANGE){const{statisticsEndpoint:e}=n;this.updateEndpoint(e,!1)}this.postEvent(t)}},this._candidateCreateHandler=({data:{candidate:e}})=>{const{candidate:t}=e,i=it(t);i&&(this._identifier.publicIP=i)},this._hostEndpointChangedHandler=({data:{endpoint:e,iceServers:t}})=>{this._appendClientDetails({node:e,iceServers:t})},this._client.on("*",this._eventHandler),this._client.on(Ae.CANDIDATE_CREATE,this._candidateCreateHandler),this._client.on(Ae.HOST_ENDPOINT_CHANGED,this._hostEndpointChangedHandler),this._client.getPeerConnection())this.start(this._client.getPeerConnection());else{const e=({data:t})=>{this._client.off(Ae.PEER_CONNECTION_AVAILABLE,e),this.start(t)};this._client.on(Ae.PEER_CONNECTION_AVAILABLE,e)}}_handleStatsReport(e){const{type:t}=e,{include:i}=this._config,n=i&&i.length>0;if(n&&i.indexOf(t)>=-1)this.post(e);else if(!n)if(t===Qe.CODEC){const{id:i,clockRate:n,mimeType:s,payloadType:o}=e;this.post({id:i,type:t,clockRate:n,mimeType:s,payloadType:o})}else if(t===Qe.CANDIDATE_PAIR){const{availableOutgoingBitrate:i,currentRoundTripTime:n,totalRoundTripTime:s,state:o}=e;this._checkCandidatePairHealth(e),this.post({type:t,availableOutgoingBitrate:i,currentRoundTripTime:n,totalRoundTripTime:s,state:o})}else if([Qe.INBOUND,"inboundrtp"].indexOf(t)>-1){const{timestamp:i,kind:n,codecId:s,jitter:o,packetsLost:a,packetsReceived:r,bytesReceived:l}=e,d={type:t,kind:n,codecId:s,jitter:o,packetsLost:a,packetsReceived:r,bytesReceived:l};if("audio"===n){const{packetsDiscarded:t}=e;if(this.lastAudioReport){const{bytesReceived:e,timestamp:t}=this.lastAudioReport,n=8*(l-e)/(i-t);this.estimatedAudioBitrate=n}this.post({...d,packetsDiscarded:t,estimatedBitrate:Math.floor(this.estimatedAudioBitrate)}),this.lastAudioReport=e}else if("video"===n){const{firCount:t,frameWidth:n,frameHeight:s,framesDecoded:o,framesDropped:a,framesPerSecond:r,framesReceived:h,freezeCount:c,keyFramesDecoded:u,nackCount:_,pauseCount:p,pliCount:g,totalFreezesDuration:m,totalPausesDuration:v}=e,E={...d,firCount:t,frameWidth:n,frameHeight:s,framesDecoded:o,framesDropped:a,framesPerSecond:r,framesReceived:h,freezeCount:c,keyFramesDecoded:u,nackCount:_,pauseCount:p,pliCount:g,totalFreezesDuration:m,totalPausesDuration:v};if(this.lastVideoReport){const{bytesReceived:e,timestamp:t}=this.lastVideoReport,n=8*(l-e)/(i-t);this.estimatedVideoBitrate=n}this.post({...E,estimatedBitrate:Math.floor(this.estimatedVideoBitrate)}),this.lastVideoReport=e}}}dispose(){this._client.off("*",this._eventHandler),this._client.off(Ae.CANDIDATE_CREATE,this._candidateCreateHandler),this._client.off(Ae.HOST_ENDPOINT_CHANGED,this._hostEndpointChangedHandler),super.dispose()}}class Ot extends Rt{constructor(e,t){super(),this._isVOD=!1,this._name=`SourceHandler-${t}`,this._view=e,this._playbackNotificationCenter=this._view,this.onCanPlay=this._onCanPlay.bind(this),this.onDurationChange=this._onDurationChange.bind(this),this.onEnded=this._onEnded.bind(this),this.onTimeUpdate=this._onTimeUpdate.bind(this),this.onPlay=this._onPlay.bind(this),this.onPause=this._onPause.bind(this),this.onVolumeChange=this._onVolumeChange.bind(this),this.onLoadedData=this._onLoadedData.bind(this),this.onLoadedMetadata=this._onLoadedMetadata.bind(this),this.onResize=this._onResize.bind(this),this.onLoadStart=this._onLoadStart.bind(this),this.onSuspend=this._onSuspend.bind(this),this.onStalled=this._onStalled.bind(this),this.onWaiting=this._onWaiting.bind(this),this.onError=this._onError.bind(this),this.onEncrypted=this._onEncrypted.bind(this),this._addPlaybackNotificationCenterHandlers(this._playbackNotificationCenter),ie.onFullScreenStateChange(this._handleFullScreenChange.bind(this))}_addPlaybackNotificationCenterHandlers(e){e.addEventListener("canplay",this.onCanPlay),e.addEventListener("durationchange",this.onDurationChange),e.addEventListener("ended",this.onEnded),e.addEventListener("timeupdate",this.onTimeUpdate),e.addEventListener("play",this.onPlay),e.addEventListener("pause",this.onPause),e.addEventListener("volumechange",this.onVolumeChange),e.addEventListener("loadeddata",this.onLoadedData),e.addEventListener("loadedmetadata",this.onLoadedMetadata),e.addEventListener("resize",this.onResize),e.addEventListener("loadstart",this.onLoadStart),e.addEventListener("suspend",this.onSuspend),e.addEventListener("stalled",this.onStalled),e.addEventListener("waiting",this.onWaiting),e.addEventListener("error",this.onError),e.addEventListener("encrypted",this.onEncrypted)}_removePlaybackNotificationCenterHandlers(e){e.removeEventListener("canplay",this.onCanPlay),e.removeEventListener("durationchange",this.onDurationChange),e.removeEventListener("ended",this.onEnded),e.removeEventListener("timeupdate",this.onTimeUpdate),e.removeEventListener("play",this.onPlay),e.removeEventListener("pause",this.onPause),e.removeEventListener("volumechange",this.onVolumeChange),e.removeEventListener("loadeddata",this.onLoadedData),e.removeEventListener("loadedmetadata",this.onLoadedMetadata),e.removeEventListener("resize",this.onResize),e.removeEventListener("loadstart",this.onLoadStart),e.removeEventListener("suspend",this.onSuspend),e.removeEventListener("stalled",this.onStalled),e.removeEventListener("waiting",this.onWaiting),e.removeEventListener("error",this.onError)}_handleFullScreenChange(e){var t,i;e?null===(t=this._view)||void 0===t||t.classList.add("red5pro-media-container-full-screen"):null===(i=this._view)||void 0===i||i.classList.remove("red5pro-media-container-full-screen"),this.trigger(new Se(we.FULL_SCREEN_STATE_CHANGE,void 0,e))}_cleanup(){this._playbackNotificationCenter&&this._removePlaybackNotificationCenterHandlers(this._playbackNotificationCenter),this._playbackNotificationCenter=void 0,this._view=void 0}_onCanPlay(e){var t;O(this._name,"[videoelement:event] canplay");const s=null!==(t=this._playbackNotificationCenter)&&void 0!==t?t:e.target,o=this.getControls();o&&o.enable(!0),this.trigger(new Se(we.PLAYBACK_STATE_CHANGE,void 0,{code:i.AVAILABLE,state:n.AVAILABLE})),this.trigger(new Se(we.VOLUME_CHANGE,void 0,{volume:s.volume}))}_onDurationChange(e){var t;O(this._name,"[videoelement:event] durationchange");const i=null!==(t=this._playbackNotificationCenter)&&void 0!==t?t:e.target,n=this.getControls();n&&n.setPlaybackDuration(i.duration),!isNaN(i.duration)&&Number.isFinite(i.duration)&&(this._isVOD=!0)}_onEnded(){O(this._name,"[videoelement:event] ended");const e=this.getControls();e&&e.setState(i.IDLE),this.trigger(new Se(we.PLAYBACK_STATE_CHANGE,void 0,{code:i.IDLE,state:n.IDLE}))}_onTimeUpdate(e){var t;const i=null!==(t=this._playbackNotificationCenter)&&void 0!==t?t:e.target,n=this.getControls();n&&n.setSeekTime(i.currentTime,this.isVOD()?i.duration:void 0),this.trigger(new Se(we.PLAYBACK_TIME_UPDATE,void 0,{time:i.currentTime,duration:i.duration}))}_onPlay(){O(this._name,"[videoelement:event] play");const e=this.getControls();e&&e.setState(i.PLAYING),this.trigger(new Se(we.PLAYBACK_STATE_CHANGE,void 0,{code:i.PLAYING,state:n.PLAYING}))}_onPause(){O(this._name,"[videoelement:event] pause");const e=this.getControls();e&&e.setState(i.PAUSED),this.trigger(new Se(we.PLAYBACK_STATE_CHANGE,void 0,{code:i.PAUSED,state:n.PAUSED}))}_onVolumeChange(e){var t;O(this._name,"[videoelement:event] volumechange");const i=null!==(t=this._playbackNotificationCenter)&&void 0!==t?t:e.target,n=this.getControls();n&&n.getVolume()!==i.volume&&n.setVolume(i.volume),this.trigger(new Se(we.VOLUME_CHANGE,void 0,{volume:i.volume}))}_onLoadedData(e){var t,i,n;O(this._name,"[videoelement:event] loadeddata");const s=null!==(t=this._view)&&void 0!==t?t:e.target;this.trigger(new Se(we.VIDEO_DIMENSIONS_CHANGE,void 0,{width:null!==(i=s.videoWidth)&&void 0!==i?i:0,height:null!==(n=s.videoHeight)&&void 0!==n?n:0}))}_onLoadedMetadata(e){var t,i;O(this._name,"[videoelement:event] loadedmetadata");const n=null!==(t=this._view)&&void 0!==t?t:e.target;this.trigger(new Se(we.LOADED_METADATA,void 0,{duration:null!==(i=n.duration)&&void 0!==i?i:0}))}_onResize(e){var t,i,n;O(this._name,"[videoelement:event] resize");const s=null!==(t=this._view)&&void 0!==t?t:e.target;this.trigger(new Se(we.VIDEO_DIMENSIONS_CHANGE,void 0,{width:null!==(i=s.videoWidth)&&void 0!==i?i:0,height:null!==(n=s.videoHeight)&&void 0!==n?n:0}))}_onLoadStart(){O(this._name,"[videoelement:event] loadstart")}_onSuspend(){O(this._name,"[videoelement:event] suspend")}_onStalled(){O(this._name,"[videoelement:event] stalled")}_onWaiting(){O(this._name,"[videoelement:event] waiting")}_onEncrypted(){O(this._name,"[videoelement:event] encrypted")}_onError(e){O(this._name,"[videoelement:event] error"),this.trigger(new Se(we.CONNECT_FAILURE,void 0,{error:e.message}))}async attemptAutoplay(e=!1){try{await this.play(),this.isMuted()&&this.trigger(new Se(we.AUTO_PLAYBACK_MUTED,void 0,{element:this._view}))}catch(t){e?(this.mute(),this.attemptAutoplay(e)):this.trigger(new Se(we.AUTO_PLAYBACK_FAILURE,void 0,{error:t.message?t.message:t,element:this._view}))}}async play(){var e,t;if(O(this._name,"[videoelement:action] play"),!(null===(e=this._view)||void 0===e?void 0:e.paused))return O(this._name,"[videoelement:action] play (ALREADY PLAYING)"),!0;try{return await(null===(t=this._view)||void 0===t?void 0:t.play()),!0}catch(e){throw k(this._name,"[videoelement:action] play (FAULT) - "+e.message),e}}async pause(){var e;O(this._name,"[videoelement:action] pause");try{return await(null===(e=this._view)||void 0===e?void 0:e.pause()),!0}catch(e){H(this._name,"[videoelement:action] pause (CATCH::FAULT) - "+e.message)}return!1}async resume(){var e;O(this._name,"[videoelement:action] resume");try{return await(null===(e=this._view)||void 0===e?void 0:e.play()),!0}catch(e){H(this._name,"[videoelement:action] resume (CATCH::FAULT) - "+e.message)}return!1}async stop(){var e;O(this._name,"[videoelement:action] stop");try{return await(null===(e=this._view)||void 0===e?void 0:e.pause()),!0}catch(e){H(this._name,"[videoelement:action] stop (CATCH::FAULT) - "+e.message)}return!1}mute(){this._view&&(this._view.muted=!0);const e=this.getControls();e&&e.setMutedState(!0)}unmute(){this._view&&(this._view.muted=!1);const e=this.getControls();e&&e.setMutedState(!1)}setVolume(e){this.unmute(),this._view&&(this._view.volume=e)}getVolume(){var e,t;return null!==(t=null===(e=this._view)||void 0===e?void 0:e.volume)&&void 0!==t?t:0}seekTo(e,t=void 0){this._view&&(this._view.currentTime=t?e*t:e)}toggleFullScreen(e){try{(e||this._view)&&ie.toggleFullScreen(null!=e?e:this._view)}catch(e){}}async unpublish(){var e;try{await this.stop(),null===(e=this._view)||void 0===e||e.dispatchEvent(new Event("ended"))}catch(e){}}disconnect(){this._cleanup()}isVOD(){return this._isVOD}isMuted(){var e,t;return null!==(t=null===(e=this._view)||void 0===e?void 0:e.muted)&&void 0!==t&&t}getControls(){}}const Ht="WHEPClient",kt=bt,Ut=e=>O(Ht,e),Mt=e=>k(Ht,e),Bt=e=>H(Ht,e);class Vt extends Pt{constructor(e,t,i){super(),this._videoMuted=!0,this._audioMuted=!0;const n=e?se(e):kt,s=i||kt,o={...s,...n,endpoint:e,mediaElementId:t?t.id:s.mediaElementId};this._videoUnmuteHandler=this._onVideoUnmute.bind(this),this._audioUnmuteHandler=this._onAudioUnmute.bind(this),e&&this.internalInit(o)}async internalInit(e){await this.init(e),await this.subscribe()}async _runMuteCheck(){var e,t,i;if(this.getPeerConnection())try{let n=this._videoMuted,s=this._audioMuted;const o=await(null===(e=this.getPeerConnection())||void 0===e?void 0:e.getStats());if(null==o||o.forEach((e=>{const{type:t,kind:i,bytesReceived:o}=e;"inbound-rtp"!==t&&"inboundrtp"!==t||("video"===i?n=o<=0:"audio"===i&&(s=o<=0))})),n===this._videoMuted&&s===this._audioMuted)return;this._videoMuted=n,this._audioMuted=s;const a={data:{streamingMode:(t=!this._videoMuted,i=!this._audioMuted,t&&i?Lt.FULL:t?Lt.VIDEO:i?Lt.AUDIO:Lt.EMPTY),method:"onMetaData"},type:"metadata",method:"onMetaData",eventTimestamp:(new Date).getTime()};this._onMetaData(a)}catch(e){Mt(e.message||e)}}_onVideoUnmute(e){const t=e.target;null==t||t.removeEventListener("unmute",this._videoUnmuteHandler);const i=setTimeout((async()=>{clearTimeout(i),this._runMuteCheck()}),1e3)}_onAudioUnmute(e){const t=e.target;null==t||t.removeEventListener("unmute",this._audioUnmuteHandler);const i=setTimeout((async()=>{clearTimeout(i),this._runMuteCheck()}),1e3)}_attachSourceHandler(e){this._sourceHandler=new Ot(e,this.getType())}_glomTrigger(e){e.on("*",(e=>{const{type:t,data:i}=e;this.trigger(new Se(t,this,i))}))}_playIfAutoplaySet(e,t){var i;if(e&&t){const{muteOnAutoplayRestriction:n}=e;ie.hasAttributeDefined(t,"autoplay")&&(null===(i=this._sourceHandler)||void 0===i||i.attemptAutoplay(n))}}addMediaStreamToPlayback(e,t){var i;!this._playbackView&&e&&(this._playbackView=new At(e)),null===(i=this._playbackView)||void 0===i||i.attachStream(t)}async requestOffer(i){var n;Ut("[requestoffer]");const{iceTransport:s,maintainStreamVariant:o,videoEncoding:a,audioEncoding:r,connectionParams:l,mungeOffer:d}=this._options;i.addTransceiver("video",{direction:"recvonly"}),i.addTransceiver("audio",{direction:"recvonly"});const h={transport:s,doNotSwitch:o};a&&a!==t.NONE&&(h.videoEncoding=a),r&&r!==e.NONE&&(h.audioEncoding=r);const c=null!=l?l:{},u=await i.createOffer(),_=await(null===(n=this._whipWhepService)||void 0===n?void 0:n.postSDPOffer(u.sdp,{...c,...h},!1));if(!_)throw Mt("Failed to get offer from WHEP"),new Error("Failed to get offer from WHEP");const{sdp:p}=_;let g=p;return d&&(Ut(`[MUNGE:before] offer: ${g}`),g=d(g),Ut(`[MUNGE:after] offer: ${g}`)),g}async requestAnswer(e){const{mungeAnswer:t}=this._options;let i=(await e.createAnswer()).sdp;return t&&(Ut(`[MUNGE:before] answer: ${i}`),i=t(i),Ut(`[MUNGE:after] answer: ${i}`)),i}async sendAnswer(e){var t;const{connectionParams:i}=this._options;return await(null===(t=this._whipWhepService)||void 0===t?void 0:t.postSDPAnswer(e,i))}async postCandidateFragments(e){var t;const{connectionParams:i}=this._options,n=Be(e,void 0,!0);return await(null===(t=this._whipWhepService)||void 0===t?void 0:t.trickle(n,i))}async initPubNub(e){var t;try{const t=new pt;this._pubnubClient=t,this._pubnubClient.on("*",(e=>{this.trigger(e)})),await t.init(e)}catch(e){return e(null!==(t=e.message)&&void 0!==t?t:"Failed to initialize PubNub."),!1}return!0}async deinitPubNub(){var e,t;try{await(null===(e=this._pubnubClient)||void 0===e?void 0:e.destroy()),this._pubnubClient=void 0}catch(e){return e(null!==(t=e.message)&&void 0!==t?t:"Failed to deinitialize PubNub."),!1}return!0}_evaluateRenegotiationPolicy(e){const{renegotiationPolicy:t}=this._options;if(t){const{type:i}=t,n=i.toLowerCase();Ut(`[evaluateRenegotiationPolicy] - Type: ${e}, Renegotiation Policy: ${t.type}`),(e===Ne.CONNECTION_HEALTH_STATE_REGRESSION&&"regression"===n||e===Ne.CONNECTION_HEALTH_ICE_TIMEOUT&&"timeout"===n||e===we.CONNECTION_CLOSED&&"disconnect"===n)&&this._reconnect()}}async _reconnect(){var e,t;Ut("[reconnect]"),this.trigger(new Se(we.RECONNECT_START,this));try{await this.unsubscribe(!0),await this.init(this._options),await this.subscribe()}catch(i){Mt(null!==(e=i.message)&&void 0!==e?e:"Could not reconnect."),this.trigger(new Se(we.RECONNECT_FAILURE,this,{error:null!==(t=i.message)&&void 0!==t?t:"Could not reconnect."}))}}async init(e){var t,i,n;this._options={...kt,...e},this._options.subscriptionId=this._options.subscriptionId||`subscriber-${Math.floor(65536*Math.random()).toString(16)}`;const s=oe(this._options,"whep"),{includeDataChannel:o,disableProxy:a}=this._options;return this._whipWhepService=new Ye(`${s}?requestId=${this._options.subscriptionId}`,o,a),this._messageTransport=this._whipWhepService,((null===(t=this._options)||void 0===t?void 0:t.stats)||(null===(i=this._options)||void 0===i?void 0:i.renegotiationPolicy))&&(!this._options.stats&&this._options.renegotiationPolicy&&(this._options.stats=Tt),this.monitorStats(this._options.stats,this._options.renegotiationPolicy)),(null===(n=this._options)||void 0===n?void 0:n.pubnub)&&await this.initPubNub(this._options.pubnub),this}async subscribe(){var e,t,i,n,s,o,a,r,l;const{connectionParams:d,rtcConfiguration:h,includeDataChannel:c,signalingSocketOnly:u,enableChannelSignaling:_,dataChannelConfiguration:p}=this._options;try{const l=d||{},m=await(null===(e=this._whipWhepService)||void 0===e?void 0:e.getOptions(l));this.trigger(new Se(we.CONNECT_SUCCESS,this,null===(t=this._whipWhepService)||void 0===t?void 0:t.getUrl()));const v=!!(null===(i=this._options)||void 0===i?void 0:i.rtcConfiguration)&&Array.isArray(this._options.rtcConfiguration.iceServers)&&this._options.rtcConfiguration.iceServers.length>0;(null==m?void 0:m.links)&&!v&&(this._options.rtcConfiguration={...h,iceServers:m.links}),(null==m?void 0:m.origin)&&this.trigger(new Se(Ae.HOST_ENDPOINT_CHANGED,this,{endpoint:m.origin})),(null==m?void 0:m.statisticsEndpoint)&&this._onStatisticsEndpointChange(m.statisticsEndpoint);const E=c||_||u?p:void 0;this._peerConnectionHelper=new Nt({onUnpublish:this._onUnpublish.bind(this),onStreamUnavailable:this._onStreamUnavailable.bind(this),onSubscriberStatus:this._onSubscriberStatus.bind(this),onStreamSwitchComplete:this._onStreamSwitchComplete.bind(this),onDataChannelError:this._onDataChannelError.bind(this),onSendReceived:this._onSendReceived.bind(this),onMetaData:this._onMetaData.bind(this),onConnectionClosed:this._onConnectionClosed.bind(this),onDataChannelOpen:this._onDataChannelOpen.bind(this),onDataChannelClose:this._onDataChannelClose.bind(this),onDataChannelMessage:this._onDataChannelMessage.bind(this),onPeerConnectionOpen:this._onPeerConnectionOpen.bind(this),onPeerConnectionFail:this._onPeerConnectionFail.bind(this),onPeerConnectionClose:this._onPeerConnectionClose.bind(this),onIceCandidate:this._onIceCandidate.bind(this),onSDPSuccess:this._onSDPSuccess.bind(this),onSDPError:this._onSDPError.bind(this),onStatisticsEndpointChange:this._onStatisticsEndpointChange.bind(this)}),await this._peerConnectionHelper.setUpWithPeerConfiguration(this._options.rtcConfiguration,E),null===(n=this.getPeerConnection())||void 0===n||n.addEventListener("track",(e=>{const{buffer:t}=this._options;Ut("[peerconnection.ontrack]");const{streams:i,track:n,receiver:s,transceiver:o}=e;s.jitterBufferDelayHint=t,this.trigger(new Se(Ae.TRACK_ADDED,this,{streams:i,track:n,receiver:s,transceiver:o})),this._mediaStream=i&&i.length>0?i[0]:void 0,"video"===n.kind?(this._videoMuted=n.muted,n.muted&&n.addEventListener("unmute",this._videoUnmuteHandler)):"audio"===n.kind&&(this._audioMuted=n.muted,n.muted&&n.addEventListener("unmute",this._audioUnmuteHandler)),this._runMuteCheck()})),this.trigger(new Se(Ae.PEER_CONNECTION_AVAILABLE,this,this.getPeerConnection())),this.trigger(new Se(Ae.OFFER_START,this));const S=await this.requestOffer(this.getPeerConnection()),C=new RTCSessionDescription({type:"offer",sdp:S});await(null===(s=this.getPeerConnection())||void 0===s?void 0:s.setRemoteDescription(C)),this.trigger(new Se(Ae.OFFER_END,this)),this.trigger(new Se(Ae.ANSWER_START,this));const b=await this.requestAnswer(this.getPeerConnection()),f=(g=b).includes("stereo=1")?g:g.replace("useinbandfec=1","useinbandfec=1;stereo=1;sprop-stereo=1"),T=new RTCSessionDescription({type:"answer",sdp:f});await(null===(o=this.getPeerConnection())||void 0===o?void 0:o.setLocalDescription(T)),await this.sendAnswer(f),this.trigger(new Se(Ae.ANSWER_END,this));const w=await this._peerConnectionHelper.waitToGatherIce(),{sdp:A}=w;return await this.postCandidateFragments(A),this.trigger(new Se(Ae.ICE_TRICKLE_COMPLETE,this)),this._mediaStream&&(this.trigger(new Se(Ae.ON_ADD_STREAM,this,this._mediaStream)),this.addMediaStreamToPlayback(this._options.mediaElementId,this._mediaStream)),(null===(a=this._playbackView)||void 0===a?void 0:a.view)&&this._attachSourceHandler(this._playbackView.view),this._sourceHandler&&this._glomTrigger(this._sourceHandler),this._playIfAutoplaySet(this._options,null===(r=this._playbackView)||void 0===r?void 0:r.view),this}catch(e){throw Mt(null!==(l=e.message)&&void 0!==l?l:"Could not subscribe."),e instanceof $e?this._onStreamUnavailable(e):this.trigger(new Se(we.CONNECT_FAILURE,this,e)),this._options.maintainConnectionOnSubscribeErrors||this.unsubscribe(!0),e}var g}async unsubscribe(e=!1){var t;Ut("[unsubscribe]"),this._peerConnectionHelper&&await this._peerConnectionHelper.tearDown(),this._whipWhepService&&await this._whipWhepService.tearDown(null,e),this._sourceHandler&&this._sourceHandler.disconnect(),this._pubnubClient&&await this.deinitPubNub(),this.unmonitorStats(),null===(t=this._playbackView)||void 0===t||t.detachStream(),this._playbackView=void 0,this._pubnubClient=void 0,this._whipWhepService=void 0,this._messageTransport=void 0,this._peerConnectionHelper=void 0,this._sourceHandler=void 0,this._mediaStream=void 0,this.trigger(new Se(we.SUBSCRIBE_STOP,this))}send(e,t){var i;return null===(i=this.getMessageTransport())||void 0===i?void 0:i.post({send:{method:e,data:"string"==typeof t?JSON.parse(t):t}})}async sendPubNub(e,t){return this._pubnubClient?await this._pubnubClient.publishMessage(e,t):(Mt("PubNub client not initialized."),!1)}async subscribePubNub(e,t){return this._pubnubClient?await this._pubnubClient.subscribe(e,t):(Mt("PubNub client not initialized."),!1)}async unsubscribePubNub(e){return this._pubnubClient?await this._pubnubClient.unsubscribe(e):(Mt("PubNub client not initialized."),!1)}async callServer(e,t){var i;const n="switchStreams"===e,{app:s,streamName:o}=this._options;if(n){const{path:i}=t[0];this._requestedStreamSwitch=i,Ut(`[callServer:switch]:: ${e}, ${s}/${o} -> ${i}`)}return null===(i=this.getMessageTransport())||void 0===i?void 0:i.postAsync({callAdapter:{method:e,arguments:t}})}sendLog(e,t){var i;try{const n=Object.keys(P).find((t=>t.toLowerCase()===e.toLowerCase()))?e:P.DEBUG,s="string"==typeof t?t:JSON.stringify(t);null===(i=this.getMessageTransport())||void 0===i||i.post({log:n.toUpperCase(),message:s})}catch(e){const t=e.message||e;Mt("Could not send log to server. Message parameter expected to be String or JSON-serializable object."),Mt(t)}}enableStandby(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteAudio:!0,muteVideo:!0}})}disableStandby(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteAudio:!1,muteVideo:!1}})}muteAudio(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteAudio:!0}})}unmuteAudio(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteAudio:!1}})}muteVideo(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteVideo:!0}})}unmuteVideo(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteVideo:!1}})}get options(){return this._options}getOptions(){return this._options}getPeerConnection(){var e;return null===(e=this._peerConnectionHelper)||void 0===e?void 0:e.connection}getDataChannel(){var e;return null===(e=this._peerConnectionHelper)||void 0===e?void 0:e.dataChannel}getMediaStream(){return this._mediaStream}getMessageTransport(){return this._messageTransport}getPubNubClient(){return this._pubnubClient}getPlayer(){var e;return null===(e=this._playbackView)||void 0===e?void 0:e.view}play(){Ut("[play]"),this._sourceHandler?this._sourceHandler.play():Bt("Cannot play without a Source Handler.")}pause(){Ut("[pause]"),this._sourceHandler?this._sourceHandler.pause():Bt("Cannot pause without a Source Handler.")}resume(){Ut("[resume]"),this._sourceHandler?this._sourceHandler.resume():Bt("Cannot resume without a Source Handler.")}stop(){Ut("[stop]"),this._sourceHandler?this._sourceHandler.stop():Bt("Cannot stop without a Source Handler.")}setVolume(e){Ut("[setVolume]"),this._sourceHandler?this._sourceHandler.setVolume(e):Bt("Cannot set volume without a Source Handler.")}getVolume(){var e,t,i;return Ut("[getVolume]"),this._sourceHandler?this._sourceHandler.getVolume():(Bt("Cannot get volume without a Source Handler."),null!==(i=null===(t=null===(e=this._playbackView)||void 0===e?void 0:e.view)||void 0===t?void 0:t.volume)&&void 0!==i?i:0)}mute(){Ut("[mute]"),this._sourceHandler?this._sourceHandler.mute():Bt("Cannot mute without a Source Handler.")}unmute(){Ut("[unmute]"),this._sourceHandler?this._sourceHandler.unmute():Bt("Cannot unmute without a Source Handler.")}seekTo(e){Ut("[seekTo]"),this._sourceHandler?this._sourceHandler.seekTo(e):Bt("Cannot seek without a Source Handler.")}toggleFullScreen(){Ut("[toggleFullScreen]"),this._sourceHandler?this._sourceHandler.toggleFullScreen():Bt("Cannot toggle full screen without a Source Handler.")}monitorStats(e,t){Ut(`[monitorStats]:: Stats: ${e?JSON.stringify(e):"undefined"}`),Ut(`[monitorStats]:: Renegotiation Policy: ${t?JSON.stringify(t):"undefined"}`);const{host:i,endpoint:n,app:s,streamName:o,subscriptionId:a,connectionParams:r}=this._options,l=null!=e?e:_e;return this._statisticsConfiguration={...l,host:i,app:s,hostEndpoint:n,streamName:o,subscriptionId:a,connectionParams:r},this._statsMonitor?Bt("Cannot monitor stats without a Peer Connection. Please call `init` before calling `monitorStats`."):this._statsMonitor=new Dt(this._statisticsConfiguration,{onStatsReport:this._onStatsReport.bind(this),getPeerConnection:this.getPeerConnection.bind(this),getMessageTransport:this.getMessageTransport.bind(this),on:this.on.bind(this),off:this.off.bind(this),trigger:this.trigger.bind(this),emit:this.emit.bind(this)},t),this}unmonitorStats(){return this._statsMonitor&&this._statsMonitor.dispose(),this._statsMonitor=void 0,this._statisticsConfiguration=void 0,this}_onUnpublish(){Ut("[unpublish]"),this.trigger(new Se(we.PLAY_UNPUBLISH,this)),this._sourceHandler&&this._sourceHandler.unpublish()}_onStreamUnavailable(e){Ut(`Stream ${this._options.streamName} does not exist.`),Ut("[onstreamunavailable]: "+JSON.stringify(e,null,2)),this.trigger(new Se(we.SUBSCRIBE_INVALID_NAME,this))}_onDataChannelError(e,t){Mt(`Data channel error: ${t}`),this.trigger(new Se(Ae.DATA_CHANNEL_ERROR,this,{dataChannel:e,error:t}))}_onSendReceived(e,t){Ut(`Send received: ${e} ${JSON.stringify(t)}`),"onMetaData"===e?this._onMetaData(t):this.trigger(new Se(we.SUBSCRIBE_SEND_INVOKE,this,{methodName:e,data:t}))}_onStreamSwitchComplete(){Ut("[streamswitch::complete]");const e=this._requestedStreamSwitch;this.trigger(new Se(Ae.SUBSCRIBE_STREAM_SWITCH,this,{path:e})),this._requestedStreamSwitch=void 0}_onMetaData(e){const{orientation:t,streamingMode:i}=e,n=this._streamingMode;void 0!==t&&t!==this._orientation&&(this._orientation=t,this.trigger(new Se(we.ORIENTATION_CHANGE,this,{orientation:parseInt(t,10),viewElement:this._playbackView?this._playbackView.view:void 0}))),i&&void 0!==i&&i!==n&&(this._streamingMode=i,this.trigger(new Se(we.STREAMING_MODE_CHANGE,this,{streamingMode:i,previousStreamingMode:n,viewElement:this._playbackView?this._playbackView.view:void 0}))),this.trigger(new Se(we.SUBSCRIBE_METADATA,this,e))}_onConnectionClosed(){Ut("Connection closed"),this.unsubscribe(!0),this.trigger(new Se(we.CONNECTION_CLOSED,this))}_onDataChannelOpen(e){Ut(`Data channel opened: ${e.label}`),this.trigger(new Se(Ae.DATA_CHANNEL_OPEN,this,{dataChannel:e})),this.trigger(new Se(Ae.DATA_CHANNEL_AVAILABLE,this,{name:e.label,dataChannel:e})),this._messageTransport=this._peerConnectionHelper,this.trigger(new Ce(ye.CHANGE,this,{controller:this,transport:this._messageTransport})),this.trigger(new Se(we.SUBSCRIBE_START,this))}_onDataChannelClose(e){Ut(`Data channel closed: ${e.label}`),this.trigger(new Se(Ae.DATA_CHANNEL_CLOSE,this,{dataChannel:e}))}_onDataChannelMessage(e,t){Ut(`Data channel message: ${t.data}`),this.trigger(new Se(Ae.DATA_CHANNEL_MESSAGE,this,{dataChannel:e,message:t}))}_onPeerConnectionOpen(){var e;Ut("Peer connection opened"),this.trigger(new Se(Ae.PEER_CONNECTION_OPEN,this,this.getPeerConnection())),(null===(e=this._options)||void 0===e?void 0:e.includeDataChannel)||this.trigger(new Se(we.SUBSCRIBE_START,this))}_onPeerConnectionFail(){Mt("Peer connection failed"),this.trigger(new Se(we.SUBSCRIBE_FAIL,this))}_onPeerConnectionClose(e){Ut(`Peer connection closed: ${e.type}`),this._evaluateRenegotiationPolicy(we.CONNECTION_CLOSED)}_onIceCandidate(e){Ut(`ICE candidate: ${e.candidate}`),this.trigger(new Se(Ae.CANDIDATE_CREATE,this,{candidate:e}))}_onPeerConnectionTrackAdd(e){Ut(`Peer connection track added: ${e.id}`)}_onSubscriberStatus(e){Ut(`Subscriber status: ${JSON.stringify(e)}`)}_onSDPSuccess(){Ut("SDP success")}_onSDPError(e){Mt(`SDP error: ${e}`)}_onStatisticsEndpointChange(e){Ut(`Statistics endpoint changed: ${e}`),this._statsMonitor&&this._statsMonitor.updateEndpoint(e),this.trigger(new Se(we.STATISTICS_ENDPOINT_CHANGE,this,{statisticsEndpoint:e}))}_onStatsReport(e,t){this.trigger(new Se(Ae.STATS_REPORT,this,{connection:e,report:t}))}on(e,t){super.on(e,t)}off(e,t){super.off(e,t)}trigger(e){super.trigger(e)}emit(e,t){this.trigger(new Se(e,this,t)),this._evaluateRenegotiationPolicy(e)}getType(){return"RTC"}}class Ft extends Ot{constructor(e,t){super(e,t),this._playingStarted=!1,this.onOrientation=this._onOrientationMetadata.bind(this),this.onStreamingMode=this._onStreamingModeMetadata.bind(this),ie.onOrientationMetadata(this._view,this.onOrientation),ie.onStreamingModeMetadata(this._view,this.onStreamingMode),this.onPlaying=this._onPlaying.bind(this),this.onSourceError=this._onSourceError.bind(this),this._view.addEventListener("playing",this.onPlaying)}addSource(e){this._source=ie.createElement("source"),this._source.type="application/x-mpegURL",this._source.src=e,this._view.firstChild?this._view.insertBefore(this._source,this._view.firstChild):this._view.appendChild(this._source),this._source.addEventListener("error",this.onSourceError)}_onPlaying(){this._playingStarted||this.trigger(new Se(we.SUBSCRIBE_START,this._view)),this._playingStarted=!0}_onSourceError(e){O(this._name,"[source:event] error"),this.trigger(new Se(we.CONNECT_FAILURE,void 0,e))}_onOrientationMetadata(e){const{orientation:t}=e,i=parseInt(t,10);t&&this._orientation!==i&&(O(this._name,"Metadata received: "+JSON.stringify(e,null,2)),this._orientation=i,this.trigger(new Se(we.ORIENTATION_CHANGE,{orientation:this._orientation,viewElement:this._view})),this.trigger(new Se(we.SUBSCRIBE_METADATA,void 0,e)))}_onStreamingModeMetadata(e){const{streamingMode:t}=e,i=this._streamingMode;t&&i!==t&&(O(this._name,"Metadata received: "+JSON.stringify(e,null,2)),this._streamingMode=t,this.trigger(new Se(we.STREAMING_MODE_CHANGE,void 0,{streamingMode:this._streamingMode,previousStreamingMode:i,viewElement:this._view})),this.trigger(new Se(we.SUBSCRIBE_METADATA,void 0,e)))}_cleanup(){this._view&&this._view.removeEventListener("playing",this.onPlaying),this._source&&(this._source.removeEventListener("error",this.onSourceError),this._view.removeChild(this._source),this._source=void 0),super._cleanup()}}const $t="HLSSubscriber",Gt=e=>O($t,e),xt=e=>H($t,e);class Wt extends Pt{constructor(){super()}_glomTrigger(e){e.on("*",(e=>{const{type:t,data:i}=e;this.trigger(new Se(t,this,i))}))}_playIfAutoplaySet(e,t){var i;if(e&&t){const{muteOnAutoplayRestriction:n}=e;ie.hasAttributeDefined(t,"autoplay")&&(null===(i=this._sourceHandler)||void 0===i||i.attemptAutoplay(n))}}async init(e){if(!ie.supportsHLS())throw new Error("Native HLS playback is not supported on this browser.");return this._options={...ft,...e},this}async subscribe(){var e;try{const t=/^http(|s).*\.m3u8/g,{endpoint:i,mediaElementId:n}=this._options;return this._fileURL=i&&i.match(t)?i:(e=>{const{host:t,protocol:i,port:n,app:s,streamName:o,connectionParams:a}=e,r="ws"===i||"http"===i?"http":"https",l=`${r}://${t}:${n||("http"===r?5080:443)}/${s}/${o}.m3u8`;if(a)return`${l}?${Object.entries(a).map((([e,t])=>`${e}=${t}`)).join("&")}`;return l})(this._options),!this._playbackView&&n&&(this._playbackView=new At(n),this._sourceHandler=new Ft(this._playbackView.view,this.getType()),this._sourceHandler.addSource(this._fileURL),this._glomTrigger(this._sourceHandler)),this.trigger(new Se(we.CONNECT_SUCCESS,this,this._fileURL)),this._playIfAutoplaySet(this._options,null===(e=this._playbackView)||void 0===e?void 0:e.view),this}catch(e){throw e(e.message),this.trigger(new Se(we.CONNECT_FAILURE,this,e.message)),e}}async unsubscribe(){var e;return this._sourceHandler&&this._sourceHandler.disconnect(),null===(e=this._playbackView)||void 0===e||e.detachStream(),this._playbackView=void 0,this._sourceHandler=void 0,this.trigger(new Se(we.SUBSCRIBE_STOP,this)),this}play(){Gt("[play]"),this._sourceHandler?this._sourceHandler.play():xt("Cannot play without a Source Handler.")}pause(){Gt("[pause]"),this._sourceHandler?this._sourceHandler.pause():xt("Cannot pause without a Source Handler.")}resume(){Gt("[resume]"),this._sourceHandler?this._sourceHandler.resume():xt("Cannot resume without a Source Handler.")}stop(){Gt("[stop]"),this._sourceHandler?this._sourceHandler.stop():xt("Cannot stop without a Source Handler.")}setVolume(e){Gt("[setVolume]"),this._sourceHandler?this._sourceHandler.setVolume(e):xt("Cannot set volume without a Source Handler.")}getVolume(){var e,t,i;return Gt("[getVolume]"),this._sourceHandler?this._sourceHandler.getVolume():(xt("Cannot get volume without a Source Handler."),null!==(i=null===(t=null===(e=this._playbackView)||void 0===e?void 0:e.view)||void 0===t?void 0:t.volume)&&void 0!==i?i:0)}mute(){Gt("[mute]"),this._sourceHandler?this._sourceHandler.mute():xt("Cannot mute without a Source Handler.")}unmute(){Gt("[unmute]"),this._sourceHandler?this._sourceHandler.unmute():xt("Cannot unmute without a Source Handler.")}seekTo(e){Gt("[seekTo]"),this._sourceHandler?this._sourceHandler.seekTo(e):xt("Cannot seek without a Source Handler.")}toggleFullScreen(){Gt("[toggleFullScreen]"),this._sourceHandler?this._sourceHandler.toggleFullScreen():xt("Cannot toggle full screen without a Source Handler.")}getPlayer(){var e;return null===(e=this._playbackView)||void 0===e?void 0:e.view}get options(){return this._options}getOptions(){return this._options}get fileURL(){return this._fileURL}getFileURL(){return this._fileURL}getType(){return"HLS"}}const Kt={baseURL:void 0,fullURL:void 0,hlsjsRef:void 0,hlsElement:void 0,usePlaybackControlsUI:!0,options:{debug:!1,backBufferLength:0}},jt={...bt,liveSeek:Kt};class zt extends M{trigger(e){super.trigger(e)}on(e,t){super.on(e,t)}off(e,t){super.off(e,t)}}var Jt,Yt;!function(e){e.SEEK_START="Seek.Start",e.SEEK_END="Seek.End"}(Jt||(Jt={})),function(e){e.CHANGE="Slider.Change",e.CHANGE_START="Slider.Change.Start",e.CHANGE_COMPLETE="Slider.Change.Complete"}(Yt||(Yt={}));class qt extends ve{constructor(e,t,i){super(e,i),this._slider=t}get slider(){return this._slider}}const{createElement:Xt,addGlobalEventListener:Qt,removeGlobalEventListener:Zt,globalUnassign:ei,getAssignedValue:ti,globalAssign:ii}=ie,ni="ControlSlider",si="r5_liveseek_event_owner";class oi extends M{constructor(e){super(),this._value=0,this._disabled=!1,this._eventStartPosition=0,this.debug=e=>O(ni,e),this.warn=e=>H(ni,e),this.name=[ni,e].join("::"),this.debug("[init]"),this._container=Xt("div"),this._button=this.createButton(),this._track=this.createTrack(),this._progressBar=this.createProgressBar(),this._container.appendChild(this._track),this._container.appendChild(this._progressBar),this._container.appendChild(this._button),this._layout(),this._mouseupHandler=this._mouseup.bind(this),this._mousedownHandler=this._mousedown.bind(this),this._mousemoveHandler=this._mousemove.bind(this),this._touchupHandler=this._touchproxy.bind(this),this._touchdownHandler=this._touchproxy.bind(this),this._touchmoveHandler=this._touchproxy.bind(this),this._updateHandlers(this._disabled)}_touchproxy(e){var t,i,n,s;const o=e;this.debug(`${o.type} touches: ${(null===(t=o.changedTouches)||void 0===t?void 0:t.length)||0}`);try{o.preventDefault()}catch(e){this.warn("Failed to prevent default on touch event.")}if(!o.touches||o.touches.length>1||"touchend"===o.type&&o.touches.length>0)return;let a,r="";const l=o.target||document.body;switch(o.type){case"touchstart":r="mousedown",a=null===(i=o.changedTouches)||void 0===i?void 0:i[0];break;case"touchmove":r="mousemove",a=null===(n=o.changedTouches)||void 0===n?void 0:n[0];break;case"touchend":r="mouseup",a=null===(s=o.changedTouches)||void 0===s?void 0:s[0]}if(a&&r){const e=new MouseEvent(r,{bubbles:!0,cancelable:!0,view:l.ownerDocument.defaultView,screenX:a.screenX,screenY:a.screenY,clientX:a.clientX,clientY:a.clientY,ctrlKey:o.ctrlKey,altKey:o.altKey,shiftKey:o.shiftKey,metaKey:o.metaKey,button:0,relatedTarget:null});l.dispatchEvent(e)}}_mouseup(){this._eventStartPosition=0,ei(si),Zt("mousemove",this._mousemoveHandler),Zt("mouseup",this._mouseupHandler),Zt("touchmove",this._touchmoveHandler),Zt("touchend",this._touchupHandler),this.trigger(new qt(Yt.CHANGE_COMPLETE,this))}_mousemove(e){if(ti(si)!==this.name)return;this.debug(`[mousemove] ${this.name}`);const t=e.clientX-this._eventStartPosition,i=this._button.parentNode.getBoundingClientRect();let n=this._eventStartPosition+t-i.left;n=Math.max(0,n),n=Math.min(n,i.width);const s=n/i.width;this.trigger(new qt(Yt.CHANGE,this,s))}_mousedown(e){this._eventStartPosition=e.clientX,this.trigger(new qt(Yt.CHANGE_START,this)),ii(si,this.name),Qt("mousemove",this._mousemoveHandler),Qt("mouseup",this._mouseupHandler),Qt("touchmove",this._touchmoveHandler),Qt("touchend",this._touchupHandler)}_updateHandlers(e){this._eventStartPosition=0,e?(this._track.removeEventListener("click",this._mousemoveHandler),this._progressBar.removeEventListener("click",this._mousemoveHandler),this._button.removeEventListener("mousedown",this._mousedownHandler),Zt("mousemove",this._mousemoveHandler),Zt("mouseup",this._mouseupHandler),Zt("touchmove",this._touchmoveHandler),Zt("touchend",this._touchupHandler),this._track.classList.add("red5pro-media-slider-disabled"),this._progressBar.classList.add("red5pro-media-slider-disabled"),this._button.classList.add("red5pro-media-slider-disabled")):(this._track.addEventListener("click",this._mousemoveHandler),this._progressBar.addEventListener("click",this._mousemoveHandler),this._button.addEventListener("mousedown",this._mousedownHandler),this._button.addEventListener("touchstart",this._touchdownHandler),this._track.classList.remove("red5pro-media-slider-disabled"),this._progressBar.classList.remove("red5pro-media-slider-disabled"),this._button.classList.remove("red5pro-media-slider-disabled"))}_layout(){const e=this._progressBar.parentNode.clientWidth*this._value;this._progressBar.style.width=e+"px",this._button.style.left=e-.5*this._button.clientWidth+"px"}createButton(){const e=Xt("span");return e.classList.add("red5pro-media-slider-button"),e}createProgressBar(){const e=Xt("span");return e.classList.add("red5pro-media-slider-progress"),e}createTrack(){const e=Xt("span");return e.classList.add("red5pro-media-slider-track"),e}get value(){return this._value}set value(e){this._value=e,this._layout()}get disabled(){return this._disabled}set disabled(e){this._disabled=e,this._updateHandlers(e)}get view(){return this._container}}const{createElement:ai,isTouchEnabled:ri,isPossiblySafari:li}=ie,di=e=>O("PlaybackControls",e);class hi extends zt{constructor(e,t){super(),this._state=i.IDLE,this._mutedState=!1,this._resumeAfterSeek=!1,this._playbackDuration=0,this._volumeValue=1,this._player=e,this._container=t,this._onPlayPauseClickBound=this._onPlayPauseClick.bind(this),this._decorate(this._container)}_decorate(e){if(!e)return;di("[decorate]");const t=ai("div");let n;t.classList.add("red5pro-media-control-bar"),this._playPauseButton=this._createPlayPauseButton(),this._muteButton=this._createMuteButton(),this._volumeField=this._createVolumeControl(),this._seekTimeField=this._createSeekControl(),this._timeField=this._createPlaybackTime(),this._fullScreenButton=this._createFullScreenToggle(),t.appendChild(this._playPauseButton),t.appendChild(this._timeField),t.appendChild(this._seekTimeField.view),t.appendChild(this._muteButton),t.appendChild(this._volumeField.view),t.appendChild(this._fullScreenButton),e.appendChild(t),this._controlbar=t;const s=()=>{clearTimeout(n),n=setTimeout((()=>{t.classList.remove("red5pro-media-control-bar-show")}),6e3)};ri()?(t.classList.add("red5pro-media-control-bar-show"),e.addEventListener("touchend",(()=>{t.classList.toggle("red5pro-media-control-bar-show"),s()})),s()):(e.addEventListener("mouseover",(()=>{t.classList.add("red5pro-media-control-bar-show")})),e.addEventListener("mouseout",(()=>{t.classList.remove("red5pro-media-control-bar-show")}))),this.setState(i.IDLE).onFullScreenChange(!1).setSeekTime(0).enable(!1)}_onPlayPauseClick(){return this.getState()===i.PLAYING?this._player.pause(!0):this.getState()===i.PAUSED?this._player.resume(!0):this._player.play(!0),this}_createPlayPauseButton(){const e=ai("button");return e.setAttribute("aria-label","Toggle Playback"),e.classList.add("red5pro-media-control-element"),e.classList.add("red5pro-media-element-button"),e.classList.add("red5pro-media-playpause-button"),e}_createMuteButton(){const e=ai("button");return e.setAttribute("aria-label","Toggle Mute Audio"),e.classList.add("red5pro-media-control-element"),e.classList.add("red5pro-media-element-button"),e.classList.add("red5pro-media-muteunmute-button"),e.addEventListener("click",(()=>{this.getMutedState()?(this._player.unmute(),this.setMutedState(!1)):(this._player.mute(),this.setMutedState(!0))})),e}_createVolumeControl(){const e=new oi("volume");return e.view.classList.add("red5pro-media-control-element"),e.view.classList.add("red5pro-media-volume-slider"),e.view.classList.add("red5pro-media-slider"),e.on(Yt.CHANGE,(e=>{const t=Number(e.data);this._player.setVolume(t)})),e}_createSeekControl(){const e=new oi("seek");return e.view.classList.add("red5pro-media-control-element"),e.view.classList.add("red5pro-media-seektime-slider"),e.view.classList.add("red5pro-media-slider"),e.on(Yt.CHANGE_START,(()=>{this.getState()===i.PLAYING&&(this._resumeAfterSeek=!0,this._player.pause(!0,!0)),this.trigger(new ve(Jt.SEEK_START))})),e.on(Yt.CHANGE,(e=>{const t=Number(e.data);this._player.seekTo(t,0===this._playbackDuration?void 0:this._playbackDuration),this.setSeekTime(t*this._playbackDuration,this._playbackDuration)})),e.on(Yt.CHANGE_COMPLETE,(()=>{this._resumeAfterSeek&&this.getState()===i.PAUSED&&(this._resumeAfterSeek=!1,this._player.resume(!0)),this.trigger(new ve(Jt.SEEK_END))})),e}_createPlaybackTime(){const e=ai("span"),t=ai("text");return t.textContent="00:00",e.classList.add("red5pro-media-control-element"),e.classList.add("red5pro-media-time-field"),e.appendChild(t),e}_createFullScreenToggle(){const e=ai("button");return e.setAttribute("aria-label","Toggle Fullscreen"),e.classList.add("red5pro-media-control-element"),e.classList.add("red5pro-media-element-button"),e.classList.add("red5pro-media-fullscreen-button"),e.addEventListener("click",(()=>{this._player.toggleFullScreen()})),e}_formatTime(e){const t=new Date(1e3*e);return`${String(t.getUTCHours()).padStart(2,"0")}:${String(t.getUTCMinutes()).padStart(2,"0")}:${String(t.getUTCSeconds()).padStart(2,"0")}`}onStateChange(e){var t,n,s,o;return e===i.PLAYING?(null===(t=this._playPauseButton)||void 0===t||t.classList.remove("red5pro-media-play-button"),null===(n=this._playPauseButton)||void 0===n||n.classList.add("red5pro-media-pause-button")):(null===(s=this._playPauseButton)||void 0===s||s.classList.add("red5pro-media-play-button"),null===(o=this._playPauseButton)||void 0===o||o.classList.remove("red5pro-media-pause-button")),this}onMutedStateChange(e){var t,i,n,s;return e?(null===(t=this._muteButton)||void 0===t||t.classList.add("red5pro-media-mute-button"),null===(i=this._muteButton)||void 0===i||i.classList.remove("red5pro-media-unmute-button"),this._volumeField&&(this._volumeField.value=0)):(null===(n=this._muteButton)||void 0===n||n.classList.remove("red5pro-media-mute-button"),null===(s=this._muteButton)||void 0===s||s.classList.add("red5pro-media-unmute-button"),this._volumeField&&(this._volumeField.value=this._volumeValue)),this}onFullScreenChange(e){var t,i,n,s;return e?(null===(t=this._fullScreenButton)||void 0===t||t.classList.add("red5pro-media-exit-fullscreen-button"),null===(i=this._fullScreenButton)||void 0===i||i.classList.remove("red5pro-media-fullscreen-button")):(null===(n=this._fullScreenButton)||void 0===n||n.classList.remove("red5pro-media-exit-fullscreen-button"),null===(s=this._fullScreenButton)||void 0===s||s.classList.add("red5pro-media-fullscreen-button")),this}enable(e){var t,i,n,s;return e?(null===(t=this._playPauseButton)||void 0===t||t.classList.remove("red5pro-media-element-button-disabled"),null===(i=this._playPauseButton)||void 0===i||i.addEventListener("click",this._onPlayPauseClickBound)):(null===(n=this._playPauseButton)||void 0===n||n.classList.add("red5pro-media-element-button-disabled"),null===(s=this._playPauseButton)||void 0===s||s.removeEventListener("click",this._onPlayPauseClickBound)),this}getVolume(){return this._volumeValue}setVolume(e){return this._volumeField&&(this._volumeField.value=e),this._volumeValue=e,0===e?this.setMutedState(!0):this.getMutedState()&&this.setMutedState(!1),this}setSeekTime(e,t=0){return this._seekTimeField&&(this._seekTimeField.value=0===t?0:e/t,0!==this._playbackDuration&&this._playbackDuration<=e&&(this._seekTimeField.value=1)),this._timeField&&(!isFinite(this._playbackDuration)&&li()?this._timeField.innerText="Live Broadcast":this._timeField.innerText=this._formatTime(Math.floor(e))),this}setPlaybackDuration(e){return this._playbackDuration=e,this}getPlaybackDuration(){return this._playbackDuration}getState(){return this._state}setState(e){return di(`[setState]: ${s[e]}`),this._state=e,this.onStateChange(this._state),this}setMutedState(e){return this._mutedState=e,this.onMutedStateChange(this._mutedState),this}getMutedState(){return"muted"in this._player?this._player.muted:this._mutedState}setAsVOD(e){return di(`[setAsVOD]: ${e}`),this._seekTimeField&&(e?this._seekTimeField.disabled=!1:(this._seekTimeField.value=0,this._seekTimeField.disabled=!0)),this}detach(){this.enable(!1),this._controlbar&&this._controlbar.parentNode&&this._controlbar.parentNode.removeChild(this._controlbar),this._controlbar=void 0,this._container=void 0}}var ci,ui;!function(e){e[e.LIVE=0]="LIVE",e[e.VOD=1]="VOD"}(ci||(ci={})),function(e){e.LIVE="LiveSeek.LIVE",e.VOD="LiveSeek.VOD"}(ui||(ui={}));const _i={[ci.LIVE]:ui.LIVE,[ci.VOD]:ui.VOD};var pi;!function(e){e.LIVE_SEEK_UNSUPPORTED="WebRTC.LiveSeek.Unsupported",e.LIVE_SEEK_ERROR="WebRTC.LiveSeek.Error",e.LIVE_SEEK_ENABLED="WebRTC.LiveSeek.Enabled",e.LIVE_SEEK_DISABLED="WebRTC.LiveSeek.Disabled",e.LIVE_SEEK_LOADING="WebRTC.LiveSeek.FragmentLoading",e.LIVE_SEEK_LOADED="WebRTC.LiveSeek.FragmentLoaded",e.LIVE_SEEK_CHANGE="WebRTC.LiveSeek.Change"}(pi||(pi={}));const{createElement:gi,findByQuerySelector:mi,createHLSClient:vi,getHLSClientEventEnum:Ei}=ie,Si="SourceHandlerSeekable",Ci=e=>O(Si,e),bi=e=>k(Si,e),fi=e=>H(Si,e);class Ti extends Ot{constructor(e,t,i,n,s=!0){super(e,`${t}-Seekable`),this._hlsElementGenerated=!1,this._hlsRecoverFlop=!1,this._hlsRecoverAttempts=0,this._isFragLoading=!1,this._wallOffset=NaN,this._lastDurationUpdate=0,this._averageSegmentDuration=6,this._isSeekable=!1,this._isHLSPlaybackActive=!1,this._container=s?this._determineContainer(e):void 0,this._liveSeekConfig=i,this._hlsOptions=n,this._usePlaybackControls=s,this.onHLSDurationChange=this._onHLSDurationChange.bind(this),this.onHLSTimeUpdate=this._onHLSTimeUpdate.bind(this),this.onHLSPlay=this._onHLSPlay.bind(this),this.onHLSPause=this._onHLSPause.bind(this)}_determineContainer(e){if(e.parentNode&&e.parentNode.classList.contains("red5pro-media-container"))return e.classList.add("red5pro-media"),e.parentNode;{const t=e.parentNode,i=gi("div");return i.classList.add("red5pro-media-container"),e.classList.add("red5pro-media"),t.insertBefore(i,e),t.removeChild(e),i.appendChild(e),i}}_generateHLSLivePlayback(e,t,i){const n=`${i}-hls-vod`;let s=mi(`#${n}`);return s||(s=gi("video"),s.id=n,s.classList.add("red5pro-hls-vod"),s.classList.add("red5pro-media-background"),s.setAttribute("playsinline","playsinline"),s.style.width="100%",s.style.height="100%",s.style.display="none",e.insertBefore(s,t),this._hlsElementGenerated=!0),s}_onDurationChange(e){var t;Ci("[videoelement:event] durationchange");const i=null!==(t=this._playbackNotificationCenter)&&void 0!==t?t:e.target,n=this.getControls();!this.isSeekable&&n&&n.setPlaybackDuration(i.duration)}_onTimeUpdate(e){var t;const i=null!==(t=this._playbackNotificationCenter)&&void 0!==t?t:e.target,n=this.getControls();if(this.isSeekable){if(!this._isHLSPlaybackActive){const e=this._hlsElement.duration,t=i.currentTime-this._lastDurationUpdate,s=isNaN(e)||0===e?i.currentTime:e+this._averageSegmentDuration+t;n&&n.setSeekTime(s,s),this.trigger(new Se(we.PLAYBACK_TIME_UPDATE,void 0,{time:s,duration:s,action:"rtc time update (1)"}))}}else super._onTimeUpdate(e)}_onEnded(){this.isHLSPlaybackActive||super._onEnded()}_onHLSDurationChange(e){const t=e.target,i=e.duration||t.duration;isNaN(this._wallOffset)&&(this._wallOffset=i-this._view.currentTime),this._lastDurationUpdate=this._view.currentTime;const n=i+this._averageSegmentDuration;Ci(`[HLS:videoelement:duration] ${i}, ${this._averageSegmentDuration}`);const s=this.getControls();s&&s.setPlaybackDuration(n),this._isHLSPlaybackActive?this.trigger(new Se(we.PLAYBACK_TIME_UPDATE,void 0,{time:t.currentTime,duration:n,action:"hls time update"})):this.trigger(new Se(we.PLAYBACK_TIME_UPDATE,void 0,{time:n,duration:n,action:"hls time update"}))}_onHLSTimeUpdate(e){const t=e.target,i=this.getControls();i&&i.setSeekTime(t.currentTime,i.getPlaybackDuration()),t.currentTime>=t.duration?this._showHLSLivePlayback(!1,this._hlsElement,this._view,this._container):!isNaN(t.duration)&&this._isHLSPlaybackActive&&this.trigger(new Se(we.PLAYBACK_TIME_UPDATE,void 0,{time:t.currentTime,duration:t.duration+this._averageSegmentDuration,action:"hls time update"}))}_onHLSPlay(){Ci("[HLS:videoelement:event] play");const e=this.getControls();e&&e.setState(i.PLAYING),this.trigger(new Se(we.PLAYBACK_STATE_CHANGE,void 0,{code:i.PLAYING,state:s[i.PLAYING]}))}_onHLSPause(){Ci("[HLS:videoelement:event] pause");const e=this.getControls();e&&e.setState(i.PAUSED),this.trigger(new Se(we.PLAYBACK_STATE_CHANGE,void 0,{code:i.PAUSED,state:s[i.PAUSED]}))}_addSeekableHandlers(e,t,i){if(t){const i=Ei();t.on(i.ERROR,((i,n)=>{const{type:s,details:o,fatal:a,url:r}=n;if("networkerror"===s.toLowerCase()){if("levelemptyerror"===o.toLowerCase()){this.trigger(new Se(pi.LIVE_SEEK_DISABLED,void 0,{hlsElement:e,hlsControl:t})),this.isSeekable=!1,t.destroy();const i=setTimeout((()=>{clearTimeout(i),this.enableLiveSeek(r,this._subscriptionId,this._hlsElement,!1)}),3e3);return}this.trigger(new Se(pi.LIVE_SEEK_ERROR,void 0,{hlsElement:e,hlsControl:t,error:n}))}else this.trigger(new Se(pi.LIVE_SEEK_ERROR,void 0,{hlsElement:e,hlsControl:t,error:n}));"mediaerror"===s.toLowerCase()&&(this._hlsRecoverFlop&&t.swapAudioCodec(),this._hlsRecoverFlop=!this._hlsRecoverFlop,this._hlsRecoverAttempts=this._hlsRecoverAttempts+1,t.recoverMediaError()),a&&"networkerror"===s.toLowerCase()&&t.startLoad()})),t.on(i.MANIFEST_PARSED,(()=>{try{e.pause()}catch(e){Ci(`Could not pause seekable live stream: ${e.message}`)}this.isSeekable=!0,this.trigger(new Se(pi.LIVE_SEEK_ENABLED,void 0,{hlsElement:e,hlsControl:t}))})),t.on(i.FRAG_LOADING,((i,n)=>{const{frag:{stats:{loaded:s,total:o}}}=n;this.trigger(new Se(pi.LIVE_SEEK_LOADING,void 0,{hlsElement:e,hlsControl:t,progress:s/o*100})),(this._isHLSPlaybackActive||this._isFragLoading)&&(this._isFragLoading=s/o>=1)})),t.on(i.FRAG_LOADED,((i,n)=>{this._isFragLoading=!1;const{frag:{endDTS:s,loader:o}}=n;if(!this._isHLSPlaybackActive&&!s)return;let a=6,r=0;if(o&&o.stats&&o.stats.segments){const e=o.stats.segments;for(let t=0;t{this._isFragLoading=!1;const{frag:{endDTS:s,loader:o}}=n;if(!this._isHLSPlaybackActive&&!s)return;let a=6,r=0;if(o&&o.stats&&o.stats.segments){const e=o.stats.segments;for(let t=0;tn.test(e)));if(!a)return void fi(`Could not find last segment in manifest: ${e}`);const r=o.find((e=>i.test(e)));if(!r)return void fi(`Could not find duration line in manifest: ${e}`);const l=r.match(i);if(!l)return void fi(`Could not find duration in manifest: ${e}`);const d=l[1],h=parseFloat(d),c=a.match(n);if(!c)return void fi(`Could not find segment length in manifest: ${e}`);const u=c[1];let _=parseInt(u,10);isNaN(_)&&(_=1),_=_>1?_-1:_,this._averageSegmentDuration=h,this.isSeekable=!0,this.trigger(new Se(pi.LIVE_SEEK_ENABLED,void 0,{hlsElement:this._hlsElement,hlsControl:void 0})),this.onHLSDurationChange({target:t,duration:h*_}),this._manifestLoadTimeout=setTimeout((()=>{clearTimeout(this._manifestLoadTimeout),this._loadManifest(e,t)}),1e3*h)}catch(e){bi(`Could not load manifest: ${e.message}.`),this.trigger(new Se(pi.LIVE_SEEK_DISABLED,void 0,{hlsElement:t,hlsControl:void 0})),this.isSeekable=!1}}_cleanup(){this._removeSeekableHandlers(this._hlsElement,this._hlsjsRef),this._hlsjsRef&&(this._hlsjsRef.detachMedia(),this._hlsjsRef=void 0),this._hlsElement&&(this._hlsElement.parentNode&&this._hlsElementGenerated&&this._hlsElement.parentNode.removeChild(this._hlsElement),this._hlsElement=void 0),this._playbackControls&&(this._playbackControls.detach(),this._playbackControls=void 0),this._isVOD=!1,this._isSeekable=!1,this._isHLSPlaybackActive=!1,this._isFragLoading=!1,this._hlsRecoverFlop=!1,this._hlsRecoverAttempts=0,this._averageSegmentDuration=6,this._hlsElementGenerated=!1,this._wallOffset=NaN,this._lastDurationUpdate=0,this._manifestLoadTimeout&&(clearTimeout(this._manifestLoadTimeout),this._manifestLoadTimeout=void 0),super._cleanup()}addSource(){Ci("[addSource]"),this._view.controls=!0,this._view.classList.add("red5pro-media");this._view.hasAttribute("controls")&&this._view.classList.contains("red5pro-media")&&(this._container=this._determineContainer(this._view));const e=this._view.hasAttribute("muted");this._usePlaybackControls?(this._playbackControls=new hi(this,this._container),this._view.controls=!1,this._playbackControls.setAsVOD(this.isSeekable),this._playbackControls.setMutedState(e)):this._view.controls=!1}enableLiveSeek(e,t,i,n=!1){if(this.getControls()&&this.getControls().setSeekTime(1,1),this._url=e,this._subscriptionId=t,this._hlsElement=i||this._generateHLSLivePlayback(this._container,this._view,t),this._showHLSLivePlayback(this._isHLSPlaybackActive,this._hlsElement,this._view,this._container),n){this._addSeekableHandlers(this._hlsElement,void 0,!1);const t=gi("source");t.src=e,this._hlsElement.appendChild(t),this._loadManifest(e,this._hlsElement)}else{const t=this._hlsOptions,{liveSeek:{hlsjsRef:i}}=this._liveSeekConfig,n=i?new i(t):vi(t);this._addSeekableHandlers(this._hlsElement,n,!0),n.attachMedia(this._hlsElement,e),n.on(Ei().MEDIA_ATTACHED,(()=>{n.loadSource(e)})),this._hlsjsRef=n}}switchLiveSeek(e){this._hlsjsRef&&(this._hlsjsRef.destroy(),this._hlsjsRef=void 0),this.enableLiveSeek(e,this._subscriptionId,this._hlsElement),this.seekTo(1);try{this._view.play()}catch(e){fi("[videoelement:action] play (FAULT) - "+e.message)}this._url=e}async play(e=!1){Ci("[videoelement:action] play");try{return e&&this._hlsElement&&this._hlsElement.paused?(await this._hlsElement.play(),!0):super.play()}catch(e){fi("[videoelement:action] play (CATCH::FAULT) - "+e.message)}return!1}async pause(e=!1,t=!1){Ci("[videoelement:action] pause");try{return e&&t&&this._hlsElement?(this._hlsElement.pause(),super.pause()):e&&this._hlsElement&&!this._hlsElement.paused?(this._hlsElement.pause(),!0):super.pause()}catch(e){fi("[videoelement:action] pause (CATCH::FAULT) - "+e.message)}return!1}async resume(e=!1){var t,i;Ci("[videoelement:action] resume");try{const n=this._isHLSPlaybackActive&&this._hlsElement?this._hlsElement.play():null===(t=this._view)||void 0===t?void 0:t.play();if(e&&this._isHLSPlaybackActive)return await(null===(i=this._view)||void 0===i?void 0:i.play()),!0;n&&n.then((()=>Ci("[videoelement:action] play (START)"))).catch((e=>fi("[videoelement:action] play (CATCH::FAULT) "+(e.message?e.message:e))))}catch(e){fi("[videoelement:action] resume (CATCH::FAULT) - "+e.message)}return!1}async stop(){Ci("[videoelement:action] stop");try{return this._hlsElement&&this._hlsElement.pause(),super.stop()}catch(e){fi("[videoelement:action] stop (CATCH::FAULT) - "+e.message)}return!1}mute(){this._hlsElement&&(this._hlsElement.muted=this._isHLSPlaybackActive),this._view&&(this._view.muted=!0);const e=this.getControls();e&&e.setMutedState(!0)}unmute(){this._hlsElement&&(this._hlsElement.muted=!this._isHLSPlaybackActive,this._view&&(this._view.muted=this._isHLSPlaybackActive)),this._view&&(this._view.muted=!1);const e=this.getControls();e&&e.setMutedState(!1)}setVolume(e){this.unmute(),this._hlsElement&&this._isHLSPlaybackActive?this._hlsElement.volume=e:this._view?this._view.volume=e:bi("[videoelement:action] setVolume (CATCH::FAULT) - "+e)}seekTo(e,t=void 0){if(this.isSeekable)if(this.getControls()&&this.getControls().setSeekTime(e,t),this.trigger(new Se(pi.LIVE_SEEK_CHANGE,void 0,{seek:e,duration:t})),this._hlsElement&&e<1)try{this._hlsElement.classList.remove("hidden"),this._hlsElement.currentTime=this._hlsElement.duration*e,this._isFragLoading=!0,this._showHLSLivePlayback(!0,this._hlsElement,this._view,this._container),this._view.paused||(Ci("[hlsvod:action] play (START) - (seekTo)"),this.play(!0))}catch(e){fi("[hlsvod:action] play (CATCH::FAULT) - "+e.message)}else this._hlsElement&&e>=1&&(this._isFragLoading=!1,this._showHLSLivePlayback(!1,this._hlsElement,this._view,this._container));else this._view.currentTime=t?e*t:e}toggleFullScreen(e){var t;this._container&&super.toggleFullScreen(null!==(t=this._container)&&void 0!==t?t:e)}getControls(){return this._playbackControls}get isSeekable(){return this._isSeekable}set isSeekable(e){this._isSeekable=e,this.getControls()&&this.getControls().setAsVOD(e)}get isHLSPlaybackActive(){return this._isHLSPlaybackActive}get url(){return this._url}}const{supportsHLS:wi,supportsNonNativeHLS:Ai}=ie,yi="WHEPLiveSeekClient",Ni=e=>k(yi,e);class Li extends Vt{constructor(e,t,i){super(e,t,i)}async init(e){const{liveSeek:t}=e;return t||(e.liveSeek=Kt),super.init(e)}_attachSourceHandler(e){var t;if((null===(t=this._playbackView)||void 0===t?void 0:t.view)&&!this._enableLiveSeek(this._playbackView.view))return H(yi,"LiveSeek is not enabled, using default source handler"),void super._attachSourceHandler(e);this._startSeekableIfSeekableEnabled(this._options)}_enableLiveSeek(e){const{liveSeek:t}=this._options;if(t){const{hlsjsRef:i,usePlaybackControlsUI:n,options:s}=t;if(wi()||Ai(i))return this._sourceHandler=new Ti(e,this.getType(),this._options,s,n),this._sourceHandler.addSource(),!0;Ni("Could not utilize the 'LiveSeek' request. This feature requires either native HLS playback or hls.js as a depenency."),this.trigger(new Se(pi.LIVE_SEEK_UNSUPPORTED,this,{feature:"Live Seek",message:"Live Seek requires integration with the HLS.JS plugin in order work properly. Most likely you are viewing this on a browser that does not support the use of HLS.JS."}))}return!1}_startSeekableIfSeekableEnabled(e){const{liveSeek:t,subscriptionId:i}=e;if(!t)return;const{hlsjsRef:n,hlsElement:s}=t;if(this._sourceHandler)try{if(!wi()&&!Ai(n))throw new Error;{const t=ne(e);this._sourceHandler.enableLiveSeek(t,i,s,!Ai(n))}}catch(e){Ni("Could not utilize the 'LiveSeek' request. This feature requires either native HLS playback or hls.js as a depenency.")}}_onUnpublish(){super._onUnpublish();const{liveSeek:e}=this._options;e||this.unsubscribe(!0)}_onStreamSwitchComplete(){const e=this._requestedStreamSwitch,{liveSeek:t}=this._options;if(t&&e){const{baseURL:i,fullURL:n}=t,s=e.split("/"),o=s.pop(),a=s.join("/"),r={...this._options,app:a,streamName:o};let l=n;if(n){const e=/.*\/(.*)\.m3u8/.exec(n);if(e&&e.length>1){const t=`${e[1]}.m3u8`;l=n.replace(t,`${o}.m3u8`)}}const d=ne(r,i,l);this._sourceHandler&&this._sourceHandler.switchLiveSeek(d)}super._onStreamSwitchComplete()}}const Pi="15.2.0";R(P.ERROR);const Ri=(e,t=!1)=>{Object.prototype.hasOwnProperty.call(P,e.toUpperCase())&&(R(e,t),console&&console.log(`Red5 Pro SDK Version ${Ii()}`))},Ii=()=>Pi;O("RED5",`Red5 Pro HTML SDK Version: ${Pi}`);var Di={version:Pi,LOG_LEVELS:P,getLogger:I,getRecordedLogs:D,setLogLevel:Ri,getVersion:Ii,PlaybackVideoEncoder:t,PlaybackAudioEncoder:e,PlaybackState:i,PlaybackStateReadableMap:s,PublishVideoEncoder:l,PublishAudioEncoder:r,SubscriberEvent:Se,PublisherEvent:Ee,MessageTransportStateEvent:Ce,PubNubEvent:be,PublisherEventTypes:fe,SubscriberEventTypes:we,RTCPublisherEventTypes:Te,RTCSubscriberEventTypes:Ae,MessageTransportStateEventTypes:ye,PubNubEventTypes:at,WHIPClient:Ct,WHEPClient:Vt,HLSSubscriber:Wt,LiveSeekClient:Li,PubNubClient:pt,defaultWhepSubscriberConfig:bt,defaultWhipPublisherConfig:ge,defaultStatsConfig:_e,StatsEndpointType:pe};export{ve as Event,M as EventEmitter,Wt as HLSSubscriber,P as LOG_LEVELS,Li as LiveSeekClient,Ce as MessageTransportStateEvent,ye as MessageTransportStateEventTypes,e as PlaybackAudioEncoder,Pt as PlaybackController,zt as PlaybackControls,i as PlaybackState,s as PlaybackStateReadableMap,t as PlaybackVideoEncoder,pt as PubNubClient,r as PublishAudioEncoder,l as PublishVideoEncoder,Ee as PublisherEvent,fe as PublisherEventTypes,Te as RTCPublisherEventTypes,Ae as RTCSubscriberEventTypes,Rt as SourceHandler,Ot as SourceHandlerImpl,pe as StatsEndpointType,Se as SubscriberEvent,we as SubscriberEventTypes,Vt as WHEPClient,Ct as WHIPClient,Di as default,ft as defaultHLSSubscriberConfig,jt as defaultLiveSeekConfig,_e as defaultStatsConfig,bt as defaultWhepSubscriberConfig,ge as defaultWhipPublisherConfig,I as getLogger,D as getRecordedLogs,Ii as getVersion,Ri as setLogLevel};
+var e,t,i,n;!function(e){e.OPUS="OPUS",e.NONE="NONE"}(e||(e={})),function(e){e.VP8="VP8",e.H264="H264",e.H265="H265",e.NONE="NONE"}(t||(t={})),function(e){e[e.UNAVAILABLE=1e3]="UNAVAILABLE",e[e.AVAILABLE=0]="AVAILABLE",e[e.IDLE=1]="IDLE",e[e.PLAYING=2]="PLAYING",e[e.PAUSED=3]="PAUSED"}(i||(i={})),function(e){e.UNAVAILABLE="Playback.UNAVAILABLE",e.AVAILABLE="Playback.AVAILABLE",e.IDLE="Playback.IDLE",e.PLAYING="Playback.PLAYING",e.PAUSED="Playback.PAUSED"}(n||(n={}));const s={[i.UNAVAILABLE]:n.UNAVAILABLE,[i.AVAILABLE]:n.AVAILABLE,[i.IDLE]:n.IDLE,[i.PLAYING]:n.PLAYING,[i.PAUSED]:n.PAUSED};var o,a,r,l;!function(e){e.RTMP="rtmp",e.RTC="rtc"}(o||(o={})),function(e){e.LIVE="live",e.RECORD="record",e.APPEND="append"}(a||(a={})),function(e){e.OPUS="OPUS"}(r||(r={})),function(e){e.VP8="VP8",e.H264="H264",e.H265="H265"}(l||(l={}));var d={trace:10,debug:20,info:30,warn:40,error:50,fatal:60},h={};function c(e){return"string"==typeof e?d[e.toLowerCase()]:e}function u(e,t){return u=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e},u(e,t)}function p(e,t,i){return p=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){}))),!0}catch(e){return!1}}()?Reflect.construct:function(e,t,i){var n=[null];n.push.apply(n,t);var s=new(Function.bind.apply(e,n));return i&&u(s,i.prototype),s},p.apply(null,arguments)}function _(e){if(null==e)return e;if(Array.isArray(e))return e.slice();if("object"==typeof e){var t={};return Object.keys(e).forEach((function(i){t[i]=e[i]})),t}return e}function g(e){return void 0===e?"undefined":null===e?"null":Array.isArray(e)?"[ "+e.map((function(e){return g(e)})).join(", ")+" ]":"object"==typeof e?JSON.stringify(e):"function"==typeof e?"[Function: "+e.name+"]":"boolean"==typeof e||"number"==typeof e?e:"'"+e.toString()+"'"}function m(e){if("string"!=typeof e){for(var t=new Array(arguments.length),i=0;i=o)return e;switch(e){case"%s":return String(s[n++]);case"%d":return Number(s[n++]);case"%j":try{return JSON.stringify(s[n++])}catch(e){return"[Circular]"}default:return e}})),r=s[n];ne||(s=function(s){var o;s[0]instanceof Error?(i={err:t.serializers&&t.serializers.err?t.serializers.err(s[0]):T.err(s[0])},o={err:!0},n=1===s.length?[i.err.message]:Array.prototype.slice.call(s,1)):"object"!=typeof s[0]&&null!==s[0]||Array.isArray(s[0])?(i=null,n=Array.prototype.slice.call(s)):(i=s[0],n=1===s.length&&i.err&&i.err instanceof Error?[i.err.message]:Array.prototype.slice.call(s,1));var a=_(t.fields);a.level=e;var r=i?_(i):null;if(r&&(t.serializers&&t._applySerializers(r,o),Object.keys(r).forEach((function(e){a[e]=r[e]}))),a.levelName=h[e],a.msg=n.length?m.apply(t,n):"",a.time||(a.time=new Date),t.src&&!a.src)try{throw new Error("call-stack-error")}catch(e){var l=e.stack?function(e,t){var i=e.split("\n");i[0]&&i[0].indexOf("call-stack-error")>=0&&i.shift();var n=i[t],s=null;if(n){var o=/^\s*(at|.*@)\s*(.+)?$/.exec(n);s=Array.isArray(o)&&o[2]?o[2]:n}return s}(e.stack,2):"";l||function(e){return v[e]}("src")||E("Unable to determine src line info","src"),a.src=l||""}return a.v=1,a}(n),this._emit(s))}}function f(e){var t=e.stack||e.toString();if(e.cause&&"function"==typeof e.cause){var i=e.cause();i&&(t+="\nCaused by: "+f(i))}return t}C.prototype.trace=b(10),C.prototype.debug=b(20),C.prototype.info=b(30),C.prototype.warn=b(40),C.prototype.error=b(50),C.prototype.fatal=b(60);var T={err:function(e){return e&&e.stack?{message:e.message,name:e.name,stack:f(e),code:e.code,signal:e.signal}:e}};const y={10:"TRACE",20:"DEBUG",30:"INFO",40:"WARN",50:"ERROR",60:"FATAL"};class w{write(e){console.log("%s - [%s] %s: %s",e.time.toISOString(),e.name,y[e.level]||"UNKNOWN",e.msg)}}let A,N;const P=e=>(t,i)=>{var n;A&&"function"==typeof A[e]&&A[e]((n=t,e=>`(${n}) ${e}`)(i))},L={TRACE:"trace",INFO:"info",DEBUG:"debug",WARN:"warn",ERROR:"error",FATAL:"fatal"},R=(e,t=!1,i)=>{const n=[{level:e,stream:new w,type:"raw"}];if(i){const t=i.map((t=>({...t,level:e})));n.push(...t)}t&&(N=[],n.push({level:e,stream:{write:t=>{const i=`[${t.time.toISOString()}] ${e.toUpperCase()}: ${t.msg}`;null==N||N.push(i)}},type:"raw"}));A=function(){return p(C,[].slice.call(arguments))}({level:e,name:"red5pro-sdk",streams:n})},I=()=>(A||R(L.INFO),A),D=()=>N||[];P(L.TRACE),P(L.INFO);const O=P(L.DEBUG),H=P(L.WARN),k=P(L.ERROR);P(L.FATAL);const M="RED5PRO";class U{constructor(){this._callbacks={},this._callbacks[M]=[]}_notify(e,t){let i;const n=e.length;for(i=0;i1&&(s=V.exec(e),n[1]===t&&s&&s.length>1)?s[1]:void 0}}function x(e){const t=G(e,"orientation");if(t)return{orientation:parseInt(t)}}function W(e){const t=G(e,"streamingMode");if(t)return{streamingMode:t}}const K=e=>F.get(e),j=e=>{const t=e.textTracks;t&&(e.addTextTrack("metadata"),t.addEventListener("addtrack",(t=>{const i=t.track;i.mode="hidden",i.addEventListener("cuechange",(t=>{let n,s;for(t&&t.currentTarget?n=t.currentTarget.cues:(n=i.cues,n=n&&n.length>0?n:i.activeCues),n=n||[],s=0;s{e(n)})),s&&o&&o.streamingMode&&o.streamingMode.forEach((e=>{e(s)}))}}}))})))},z="BrowserEnvironment",J=e=>O(z,e),Y=e=>H(z,e);let q=[];const X=()=>{const e=screen.orientation?screen.orientation.angle:void 0,t=void 0===e?window.matchMedia("(orientation: portrait)").matches?0:90:e,i=q.length;J(`[window:onorientationchange]: orientation(${t}).`);for(let e=0;e{const e=document.createElement("video");return e.canPlayType("application/vnd.apple.mpegURL").length>0||e.canPlayType("application/x-mpegURL").length>0||e.canPlayType("audio/mpegurl").length>0||e.canPlayType("audio/x-mpegurl").length>0},te="undefined"!=typeof window&&window.adapter;var ie={gUM:async e=>navigator.mediaDevices.getUserMedia(e),createElement:e=>document.createElement(e),resolveElement:e=>document.getElementById(e),getElementId:e=>e.id,setVideoSource:(e,t,i)=>{if(e.srcObject=t,i)try{const t=e.play();t&&t.then((()=>J("[setVideoSource:action]: play (START)"))).catch((t=>{Y(`[setVideoSource:action]: play (CATCH::FAULT) ${t.message}`);try{e.setAttribute("autoplay","false"),e.pause()}catch(e){Y(`[setVideoSource:action]: pause (CATCH::FAULT) ${e.message}`)}}))}catch(e){Y(`[setVideoSource:action]: play (CATCH::FAULT) ${e.message}`)}},hasAttributeDefined:(e,t)=>e.hasAttribute(t),addOrientationChangeHandler:(e,t=!0)=>{"onorientationchange"in window&&(J("[window:orientation:addOrientationChangeHandler]: add"),q.push(e),t&&X()),1===q.length&&(J("[window:orientation:addOrientationChangeHandler]: add"),window.addEventListener("orientationchange",X))},removeOrientationChangeHandler:e=>{q=q.filter((t=>t!==e)),0===q.length&&window.removeEventListener("orientationchange",X)},toggleFullScreen:e=>{window.screenfull&&window.screenfull.enabled?window.screenfull.toggle(e):document.fullscreenEnabled&&(document.fullscreenElement&&document.fullscreenElement===e?document.exitFullscreen():e.requestFullscreen())},onFullScreenStateChange:e=>{var t;Z.push(e),t=window.screenfull,Q||(Q=!0,window.screenfull?window.screenfull.on("change",(()=>{Z.forEach((e=>e(t.isFullscreen)))})):document.fullscreenEnabled&&document.addEventListener("fullscreenchange",(()=>{Z.forEach((e=>e(null!==document.fullscreenElement)))})))},getOrGenerateFingerprint:()=>{const e=window.localStorage;if(e&&e.getItem("red5_fingerprint"))return e.getItem("red5_fingerprint");let t;try{t=window.crypto.randomUUID()}catch(e){t="10000000-1000-4000-8000-100000000000".replace(/[018]/g,(e=>(Number(e)^crypto.getRandomValues(new Uint8Array(1))[0]&15>>Number(e)/4).toString(16)))}return e.setItem("red5_fingerprint",t),t},getBrowserDetails:()=>{const e=void 0!==window.adapter,{navigator:t,adapter:i}=window,{appVersion:n,platform:s,userAgent:o,vendor:a}=t,r={appVersion:n,platform:s,userAgent:o,vendor:a};return e?{...i.browserDetails,...r}:r},supportsHLS:ee,onOrientationMetadata:(e,t)=>{const i=F.get(e);F.has(e)?Object.prototype.hasOwnProperty.call(i,"orientation")||(F.get(e).orientation=[]):(j(e),F.set(e,{orientation:[]})),F.get(e).orientation.push(t)},onStreamingModeMetadata:(e,t)=>{const i=F.get(e);F.has(e)?Object.prototype.hasOwnProperty.call(i,"streamingMode")||(F.get(e).streamingMode=[]):(j(e),F.set(e,{streamingMode:[]})),F.get(e).streamingMode.push(t)},isTouchEnabled:()=>"ontouchstart"in window,isPossiblySafari:()=>te?"safari"===window.adapter.browserDetails.browser.toLowerCase():ee(),findByQuerySelector:e=>document.querySelector(e),addGlobalEventListener:(e,t,i=document)=>{i.addEventListener(e,t)},removeGlobalEventListener:(e,t,i=document)=>{i.removeEventListener(e,t)},supportsNonNativeHLS:e=>{if(e)try{return e.isSupported()}catch(e){return Y("Could not access Hls.js."),!1}return!!window.Hls&&window.Hls.isSupported()},createHLSClient:(e={})=>new window.Hls(e),getHLSClientEventEnum:()=>window.Hls.Events,globalAssign:(e,t)=>{window[e]=t},globalUnassign:e=>{delete window[e]},getAssignedValue:e=>window[e]};const ne=(e,t,i)=>{const{liveSeek:{baseURL:n,fullURL:s}}=e,{host:o,protocol:a,port:r,app:l,streamName:d}=e;if(i||s)return i||s;const h=o,c="ws"===a?"http":"https",u=5080===r?5080:443,p=l,_=t||n;if(_){const e=_.length-1;return`${"/"===_.charAt(e)?_.substring(0,e):_}/${p}/${d}.m3u8`}return`${c}://${h}:${u}/${p}/${d}.m3u8`},se=e=>{const t=new URL(e),i=t.pathname.split("/").filter((e=>e.length>0)),n="https:"===t.protocol?"https":"http",s=t.hostname;return{protocol:n,port:t.port.length>0?t.port:443,app:i[0],host:s,streamName:i[i.length-1]}},oe=(e,t="whip")=>{var i;const{endpoint:n,proxy:s}=e;if(n)return n;{const{protocol:n,host:o,port:a,app:r,streamName:l}=e,d=n.match(/^http/)?n:"ws"===n?"http":"https";return(null==s?void 0:s.enabled)?`${d}://${o}:${a}/as/${null!==(i=s.version)&&void 0!==i?i:"v1"}/proxy/${t}/${r}/${l}`:`${d}://${o}:${a}/${r}/${t}/endpoint/${l}`}},ae=e=>{const t={audio:!1,video:!1},i={audio:!1,video:!1};return e.getTracks().forEach((e=>{"video"===e.kind?(i.video=e.getSettings(),t.video=e.getConstraints()):"audio"===e.kind&&(i.audio=e.getSettings(),t.audio=e.getConstraints())})),{requested:t,accepted:i}},re=e=>{const t=e.length;return function i(...n){return n.length>=t?e(...n):function(...e){return i(...n,...e)}}},le=re(((e,t)=>{let i=0;const n=t.length,s=[];for(;i{this._responder.onDataChannelError(e,t.error.message)},e.onmessage=e=>{this._onDataChannelMessage(e)},e.onopen=()=>{this._responder.onDataChannelOpen(e)},e.onclose=t=>{this._responder.onDataChannelClose(e),this.trigger(new Ce(Ne.CLOSE,this._name,{socket:this,event:t}))}}_isErrorMessage(e){return!("error"!==(null==e?void 0:e.type)||!(null==e?void 0:e.message)&&!(null==e?void 0:e.code))}_isStatusMessage(e){return!("status"!==(null==e?void 0:e.type))}_onDataChannelMessage(e){if(this.handleMessageResponse(e))return!0;const t=this.getJsonFromSocketMessage(e);return t?(O(this._name,`[datachannel-response]: ${JSON.stringify(t,null,2)}`),this._handleMessageContent(t)):(H(this._name,"Determined websocket response not in correct format. Aborting message handle."),!0)}_handleMessageContent(e){const{async:t,data:i,method:n,send:s,type:o,id:a}=e;if(this._isErrorMessage(i)){const e=(null==i?void 0:i.message)||(null==i?void 0:i.code);if(e)return this._responder.onDataChannelError(this._dataChannel,e),!0}if(n)return this._responder.onSendReceived(n,i),!0;if(s){const{senderName:t,dcLabel:i}=e,{data:n,method:o}=s,a={...n,senderName:t,dcLabel:i};return this._responder.onSendReceived(o,a),!0}return"metadata"===o&&i?(this._responder.onMetaData(i),!0):this._isStatusMessage(i)&&"NetConnection.Connect.Closed"===(null==i?void 0:i.code)?(this._responder.onConnectionClosed(),!0):!(!t||!a)&&this._handleAsyncResponse(a,e)}_handleAsyncResponse(e,t){const i=this._asyncTickets.find((t=>t.id===e));if(!i)return!1;const{promise:n}=i,{data:s}=t;if("error"===(null==s?void 0:s.type)){const e=s.message||s.code||"Unknown error";n.reject(new Error(e))}else n.resolve(s);return this._asyncTickets=this._asyncTickets.filter((t=>t.id!==e)),!0}async setUpWithPeerConfiguration(e,t){this.tearDown();(null==e?void 0:e.iceServers)&&e.iceServers.length>0||(e.iceServers=Re);try{O(this._name,`[peerconnection:setUpWithPeerConfiguration]: ${JSON.stringify(e,null,2)}`);const i=new RTCPeerConnection(e);return t&&(this._dataChannel=i.createDataChannel(t.name,{ordered:!0}),this._addDataChannelHandlers(this._dataChannel)),this._addConnectionHandlers(i),this._peerConnection=i,i}catch(e){throw H(this._name,`Could not establish a PeerConnection. ${e.message}`),new Error(e.message)}}tearDown(){if(this._dataChannel){O(this._name,"[teardown:datachannel]"),this._removeDataChannelHandlers(this._dataChannel);try{this._dataChannel.close()}catch(e){H(this._name,`[datachannel.close] error: ${e.message}`)}finally{this._dataChannel=void 0}}if(this._peerConnection){O(this._name,"[teardown:peerconnection]"),this._removeConnectionHandlers(this._peerConnection);try{this._peerConnection.close()}catch(e){H(this._name,`[peerconnection.close] error: ${e.message}`)}finally{this._peerConnection=void 0}}}async setLocalDescription(e){var t;return O(this._name,"[setlocaldescription]"),null===(t=this._peerConnection)||void 0===t?void 0:t.setLocalDescription(e)}async setRemoteDescription(e){var t;return O(this._name,"[setremotedescription]"),null===(t=this._peerConnection)||void 0===t?void 0:t.setRemoteDescription(new RTCSessionDescription(e))}async addIceCandidate(e){var t;return O(this._name,"[addcandidate]"),null===(t=this._peerConnection)||void 0===t?void 0:t.addIceCandidate(e)}async waitToGatherIce(e=5e3){const t=this._peerConnection;return O(this._name,"[waittogatherice]"),new Promise((i=>{if("complete"===t.iceGatheringState)O(this._name,"[waittogatherice] ice gathering state complete."),t.addIceCandidate(null).then((()=>{i(t.localDescription)})).catch((e=>{H(this._name,"Error adding null candidate: "+e.message||e),i(t.localDescription)}));else{O(this._name,"[waittogatherice] waiting...");const n=setTimeout((()=>{clearTimeout(n),t.addIceCandidate(null).then((()=>{i(t.localDescription)})).catch((e=>{H(this._name,"Error adding null candidate: "+e.message||e),i(t.localDescription)}))}),e);t.onicegatheringstatechange=()=>{clearTimeout(n),O(this._name,"[waittogatherice] ice gathering state complete."),"complete"===t.iceGatheringState&&t.addIceCandidate(null).then((()=>{i(t.localDescription)})).catch((e=>{H(this._name,"Error adding null candidate: "+e.message||e),i(t.localDescription)}))}}}))}post(e){if(this._dataChannel){const t="string"==typeof e?e:JSON.stringify(e,null,2);O(this._name,`[datachannel.send] message: ${t}`);try{return this._dataChannel.send(t),Promise.resolve(!0)}catch(e){k(this._name,e.message)}}return Promise.resolve(!1)}get connection(){return this._peerConnection}get dataChannel(){return this._dataChannel}}const De=[{label:"4K(UHD)",width:3840,height:2160},{label:"1080p(FHD)",width:1920,height:1080},{label:"UXGA",width:1600,height:1200},{label:"720p(HD)",width:1280,height:720},{label:"SVGA",width:800,height:600},{label:"VGA",width:640,height:480},{label:"360p(nHD)",width:640,height:360},{label:"CIF",width:352,height:288},{label:"QVGA",width:320,height:240},{label:"QCIF",width:176,height:144},{label:"QQVGA",width:160,height:120}],Oe=e=>"number"==typeof e?e:e.exact||e.ideal||e.max||e.min||e,He=re(((e,t)=>{var i,n;if("boolean"==typeof e.video)return!0;const s=(null===(i=e.video)||void 0===i?void 0:i.width)?Oe(e.video.width):0,o=(null===(n=e.video)||void 0===n?void 0:n.height)?Oe(e.video.height):0,a=s===t.width&&o===t.height;return a&&O("[gum:isExact]",`Found matching resolution for ${t.width}, ${t.height}.`),a})),ke=re(((e,t)=>{const i=le(He(t))(e);return O("[gum:hasMatchingFormat]","Filtered list: "+JSON.stringify(i,null,2)),i.length>0})),Me=re(((e,t)=>{var i,n;if("boolean"==typeof e.video)return!0;const s=((null===(i=e.video)||void 0===i?void 0:i.width)?Oe(e.video.width):0)*((null===(n=e.video)||void 0===n?void 0:n.height)?Oe(e.video.height):0);return t.width*t.height{const i=Me(t);return le(i)(e)})),Be=async e=>{O("[gum:determineSupportedResolution]","Determine next neighbor based on constraints: "+JSON.stringify(e,null,2));const t=Ue(De)(e),i={...e};return await(async(e,t)=>{let i={...e};if(0==t.length)i.video;else{const n=t.shift();i={...e,video:{...e.video,width:{exact:n.width},height:{exact:n.height}}}}return{media:await ie.gUM(i),constraints:i}})(i,t)},Ve=async e=>{let t;const i=ke(De),n=async t=>{if(t){const e="string"==typeof t?t:[t.name,t.message].join(": ");O("[gum:getUserMedia]",`Failure in getUserMedia: ${e}. Attempting other resolution tests...`)}return await Be(e)};if((e=>e.video&&"object"==typeof e.video&&(e.video.width||e.video.height))(e)){if(!i(e))return await n(void 0);{O("[gum:getUserMedia]","Found constraints in list. Checking quick support for faster setup with: "+JSON.stringify(e,null,2));const i=(e=>{var t,i;const n={...e};return"boolean"==typeof e.video||(n.video={...n.video},(null===(t=e.video)||void 0===t?void 0:t.width)&&(n.video.width={exact:Oe(e.video.width)}),(null===(i=e.video)||void 0===i?void 0:i.height)&&(n.video.height={exact:Oe(e.video.height)})),n})(e);try{return t=await ie.gUM(i),{media:t,constraints:i}}catch(e){return await n(e)}}}else try{return t=await ie.gUM(e),{media:t,constraints:e}}catch(e){return await n(e)}},Fe=(e,t,i)=>{const n="a=end-of-candidates",s=/^a=candidate:/,o=/^a=ice-ufrag:/,a=/^a=ice-pwd:/,r=/^m=(audio|video|application)\ /,l=e.split("\r\n");let d,h="",c="";const u=[];l.forEach((e=>{!d&&r.exec(e)?d=e:o.exec(e)?h=e:a.exec(e)?c=e:s.exec(e)&&(t&&-1!=e.indexOf(t)?u.push(e):t||u.push(e))})),i&&u[u.length-1]!==n&&u.push(n);return[h,c,d,"a=mid:0"].concat(u).join("\r\n")},$e="RTCPeerConnectionPublisher";class Ge extends Ie{constructor(e){super(e,$e)}_removeConnectionHandlers(e){e.onconnectionstatechange=null,e.oniceconnectionstatechange=null,e.onsignalingstatechange=null,e.onicecandidate=null,e.ontrack=null}_addConnectionHandlers(e){let t;e.onsignalingstatechange=()=>{const t=e.signalingState;O($e,`[peer.onsignalingstatechange] - State: ${t}`)},e.onconnectionstatechange=()=>{const{connectionState:t}=e;"connected"===t?(O(this._name,"[peerconnection:open]"),this._responder.onPeerConnectionOpen()):"failed"!==t&&"disconnected"!==t||(H(this._name,"[peerconnection:error]"),"failed"===t&&this._responder.onPeerConnectionFail())},e.oniceconnectionstatechange=i=>{const{iceConnectionState:n}=e;O(this._name,`[peer.oniceconnectionstatechange] - State: ${n}`),"failed"===n?(t&&clearTimeout(t),this._responder.onPeerConnectionClose(i)):"disconnected"===n?t=setTimeout((()=>{O(this._name,"[peer.oniceconnectionstatechange] - Reconnect timeout reached. Closing PeerConnection."),clearTimeout(t),this._responder.onPeerConnectionClose(i)}),3e3):t&&(O(this._name,"[peer.oniceconnectionstatechange] - Clearing timeout for reconnect."),clearTimeout(t))},e.onicecandidate=e=>{const{candidate:t}=e;O(this._name,`[peer.onicecandidate] - Peer Candidate: ${null==t?void 0:t.candidate}`),t&&this._responder.onIceCandidate(t)},e.ontrack=e=>{O(this._name,"[peer:ontrack]"),this._responder.onPeerConnectionTrackAdd(e.track)}}_onDataChannelMessage(e){const t=e;if(super._onDataChannelMessage(e))return!0;const i=this.getJsonFromSocketMessage(t);if(null===i)return H(this._name,"Determined websocket response not in correct format. Aborting message handle."),!0;O(this._name,"[datachannel-response]: "+JSON.stringify(i,null,2));const{data:n}=i;return n&&"status"===n.type?"NetStream.Play.UnpublishNotify"===n.code?(this._responder.onUnpublish(),!0):"NetConnection.Publish.InsufficientBW"===n.code?(this._responder.onInsufficientBandwidth(n),!0):"NetConnection.Publish.SufficientBW"===n.code?(this._responder.onSufficientBandwidth(n),!0):"NetConnection.Publish.RecoveringBW"===n.code?(this._responder.onRecoveringBandwidth(n),!0):"Application.Statistics.Endpoint"===n.code?(this._responder.onStatisticsEndpointChange(n.statistics),!0):(O($e,`[datachannel.message] status :: ${n.code}`),this._responder.onPublisherStatus(n),!0):(this._responder.onDataChannelMessage(this._dataChannel,t),!1)}addTrack(e){this._peerConnection?this._peerConnection.addTrack(e):H($e,"PeerConnection not initialized. Cannot add track.")}async postUnpublish(e){const t=this.post({unpublish:e});return O($e,`[peerconnection:unpublish] complete: ${t}`),t}async createOfferWithoutSetLocal(e=null){var t;O($e,`[createoffer:withoutlocal]:: bandwidth request: ${JSON.stringify(e,null,2)}`);try{const i=await(null===(t=this._peerConnection)||void 0===t?void 0:t.createOffer());if(e){const t=((e,t)=>{const i=t.indexOf("m=audio");let n,s,o,a=t.indexOf("m=video"),r=t.indexOf("m=application");return i>-1&&e.audio&&(n=t.indexOf("\r\n",i),s=t.slice(0,n),o=t.slice(n+2,t.length),a=(t=[s,"b=AS:"+e.audio,o].join("\r\n")).indexOf("m=video"),r=t.indexOf("m=application")),a>-1&&e.video&&(n=t.indexOf("\r\n",a),s=t.slice(0,n),o=t.slice(n+2,t.length),r=(t=[s,"b=AS:"+e.video,o].join("\r\n")).indexOf("m=application")),r>-1&&e.dataChannel&&(n=t.indexOf("\r\n",r),s=t.slice(0,n),o=t.slice(n+2,t.length),t=[s,"b=AS:"+e.dataChannel,o].join("\r\n")),t})(e,i.sdp);i.sdp=t}return this._responder.onSDPSuccess(),i}catch(e){throw O($e,"[createoffer:error]"),this._responder.onSDPError(e),e}}async updateBandwidthRequest(e=null){var t;O($e,`[updatebandwidthrequest]:: bandwidth request: ${JSON.stringify(e,null,2)}`);try{const i=null===(t=this._peerConnection)||void 0===t?void 0:t.getSenders();if(e&&(null==i?void 0:i.length)&&i.length>0){const t=(e,t,i)=>new Promise(((n,s)=>{try{O($e,`[updatebandwidthrequest:${i}]:: bandwidth(${t.encodings[0].maxBitrate})`),e.setParameters(t).then(n).catch(s)}catch(e){s(e)}})),n=[];null==i||i.forEach((async i=>{var s,o;if("video"===(null===(s=i.track)||void 0===s?void 0:s.kind)&&e.video){const e=i.getParameters();e.encodings||(e.encodings=[{}]),e.encodings[0].maxBitrate=75e4,e.encodings[0].maxFramerate=60,e.encodings[0].priority="high",n.push(t(i,e,"video"))}else if("audio"===(null===(o=i.track)||void 0===o?void 0:o.kind)&&e.audio){const e=i.getParameters();e.encodings||(e.encodings=[{}]),e.encodings[0].maxBitrate=128e3,n.push(t(i,e,"audio"))}})),await Promise.all(n).catch((e=>{k($e,`[updatebandwidthrequest:error]:: ${e.message}`)}))}return!0}catch(e){k($e,`[updatebandwidthrequest:error]:: ${e.message}`)}return!1}}class xe extends Error{constructor(e){super(e),this.name="InvalidNameError"}}const We="WhipWhepSignalingHelper",Ke=new Map;Ke.set(400,"Invalid offer SDP."),Ke.set(401,"Not authorized."),Ke.set(404,"Scope resolver failed for the publish name and / or scope."),Ke.set(405,"Remember to update the URL passed into the WHIP or WHEP client."),Ke.set(406,"Scope connection rejected."),Ke.set(409,"Session already initialized."),Ke.set(412,"Invalid request body."),Ke.set(417,"Session lookup or creation failure.");const je=new Map;je.set(400,"Offer already sent, double POST assumed."),je.set(401,"Not authorized."),je.set(404,"Scope resolver failed for the playback name and / or scope."),je.set(406,"Playback failed due to an exception during creation."),je.set(409,"Stream is not available to playback.");const ze=["transcode"];var Je;!function(e){e.ICE_SERVER="ice-server",e.STATISTICS="statistics"}(Je||(Je={}));const Ye=e=>e&&(e=>{const t=/[?&](.*)=([^]*)/.exec(e);return t&&t.length>0})(e)?"&":"?",qe=e=>e.split(";").map((e=>e.trim())).map((e=>"<"===e.charAt(0)?["url",e.substring(1,e.length-1)]:e.split("="))).reduce(((e,t)=>e.set(t[0].replaceAll('"',""),t[1].replaceAll('"',""))),new Map);class Xe{constructor(e,t=!1,i=!0){O(We,`[whipwhep] ${e}`),this._url=e,this._origin=void 0,this._forceHost=i,this._resource=void 0,this._enableSignalingChannel=t}async getOptions(e={}){let t=`${this._url}${Ye(this._url)}signal=${this._enableSignalingChannel}`;e&&Object.keys(e).forEach((i=>{t+=`&${i}=${e[i]}`})),O(We,`[whipwhep-options] ${t}`);try{const e=await fetch(t,{method:"OPTIONS",mode:"cors"}),{status:i,headers:n}=e;if(200===i||204===i){const e=/^(L|l)ink/,t=/^(S|s)ession-(H|h)ost/,i=[];let s;return n.forEach(((n,o)=>{if(t.exec(o)&&(this._origin=n),e.exec(o))if(n.indexOf(`rel="${Je.ICE_SERVER}"`)>-1){const e=qe(n),t=e.get("url"),{protocol:s,host:o}=(e=>{const t=e.split(":");return t.length>1?{protocol:t[0],host:t[1]}:{protocol:void 0,host:e}})(t),a=e.get("username"),r=e.get("credential");s&&o&&a&&r?i.push({username:a,credential:r,urls:t}):t&&i.push({urls:t})}else if(n.indexOf(`rel="${Je.STATISTICS}"`)>-1){const e=qe(n).get("url");e&&(s=e)}})),O(We,`[whipwhep-links]: ${JSON.stringify(i)}`),O(We,`[whipwhep-origin]: ${this._origin}`),{links:i.length>0?i:void 0,origin:this._origin,statisticsEndpoint:s}}throw new Error(`Failed to get options: ${i}`)}catch(e){throw k(We,e.message),e}}async postSDPOffer(e,t={},i=!0){let n=`${this._url}${Ye(this._url)}signal=${this._enableSignalingChannel}`;t&&Object.keys(t).forEach((e=>{-1===ze.indexOf(e)&&(n+=`&${e}=${t[e]}`)})),this._forceHost&&this._origin&&!(null==t?void 0:t.host)&&(n+=`&host=${this._origin}`),O(We,`[whipwhep:post-offer] ${n}: `+JSON.stringify(e,null,2));try{const t={method:"POST",mode:"cors",headers:{"Content-Type":"application/sdp"}};e&&e.length>0&&(t.body=e);const s=await fetch(n,t),{status:o,headers:a}=s;if(a&&a.forEach(((e,t)=>{O(We,`[header] ${t}: ${e}`)})),o>=200&&o<300){const e=await s.text(),t=a.get("Location")||a.get("location");if(t){if(t.match(/^(http|https)/))this._resource=t;else{O(We,`[whipwhep-response] Location provided as relative path: ${t}`);const e=new URL(this._url);e.pathname=t.split("?")[0],this._resource=e.toString().replace(/\/endpoint\//,"/resource/")}return O(We,`[whipwhep-response] ${this._resource}: ${e}`),{sdp:e,location:this._resource}}return H(We,"Location not provided in header response to Offer."),this._resource=new URL(this._url).toString().replace(/\/endpoint\//,"/resource/"),{sdp:e,location:this._resource}}if(i&&Ke.get(o)){if(O(We,Ke.get(o)),404===o||409===o)throw new xe(Ke.get(o));throw new Error(Ke.get(o))}if(!i&&je.get(o)){if(O(We,je.get(o)),404===o||409===o)throw new xe(je.get(o));throw new Error(je.get(o))}{const e=await s.text();throw Error(e)}}catch(e){throw k(We,e.message),e}}async postSDPAnswer(e,t={}){O(We,`[whipwhep:post-answer] ${this._resource}: `+JSON.stringify(e,null,2));let i=this._resource,n=Ye(i);t&&Object.keys(t).forEach((e=>{-1===ze.indexOf(e)&&(n=Ye(i),i+=`${n}${e}=${t[e]}`)})),this._forceHost&&this._origin&&!(null==t?void 0:t.host)&&(n=i.indexOf("?")>-1?"&":"?",i+=`${n}host=${this._origin}`);try{const t=await fetch(i,{method:"PATCH",mode:"cors",headers:{"Content-Type":"application/sdp"},body:e}),{status:n}=t;if(n>=200&&n<300)return{success:!0,code:n};if(je.get(n))throw O(We,je.get(n)),new Error(je.get(n));{const e=await t.text();throw Error(e)}}catch(e){throw k(We,e.message),e}}async trickle(e,t={}){O(We,`[whipwhep-trickle] ${this._resource}: `+JSON.stringify(e,null,2));let i=this._resource,n=Ye(i);t&&Object.keys(t).forEach((e=>{-1===ze.indexOf(e)&&(n=Ye(i),i+=`${n}${e}=${t[e]}`)})),this._forceHost&&this._origin&&!(null==t?void 0:t.host)&&(n=Ye(i),i+=`${n}host=${this._origin}`);try{const t=await fetch(i,{method:"PATCH",mode:"cors",headers:{"Content-Type":"application/trickle-ice-sdpfrag"},body:e}),{status:n}=t;if(n>=200&&n<300){const e=await t.text();return O(We,`[whipwhep-response] ${this._resource}: ${e}`),{candidate:e}}if(405===n)throw O(We,"Remember to update the URL passed into the WHIP or WHEP client"),new Error("Remember to update the URL passed into the WHIP or WHEP client");{const e=await t.text();throw Error(e)}}catch(e){throw k(We,e.message),e}}async tearDown(e={},t=!1){if(!this._resource)return;let i=this._resource,n=Ye(i);e&&Object.keys(e).forEach((t=>{-1===ze.indexOf(t)&&(n=Ye(i),i+=`${n}${t}=${e[t]}`)})),this._forceHost&&this._origin&&!(null==e?void 0:e.host)&&(n=Ye(i),i+=`${n}host=${this._origin}`),O(We,"[whipwhep-teardown]");try{await fetch(i,{method:"DELETE",mode:"cors"})}catch(e){if(k(We,e.message),!t)throw e}this._url=void 0,this._origin=void 0,this._resource=void 0,this._forceHost=!1,this._enableSignalingChannel=!1}async post(){return O(We,"[whipwhep:post] transport called."),Promise.resolve(!1)}async postAsync(){return O(We,"[whipwhep:postAsync] transport called."),Promise.resolve(null)}getUrl(){return this._url}}const Qe="R5ProPublishView";class Ze{constructor(e="red5pro-publisher"){try{this._targetElement=ie.resolveElement(e)}catch(e){throw k(Qe,`Could not instantiate a new instance of PublishView. Reason: ${e.message}`),e}}preview(e){const t=this.isAutoplay;O(Qe,`[preview]: autoplay(${t})`),ie.setVideoSource(this._targetElement,e,t)}unpreview(){ie.setVideoSource(this._targetElement,null,this.isAutoplay)}get isAutoplay(){return ie.hasAttributeDefined(this._targetElement,"autoplay")}get view(){return this._targetElement}}var et,tt;!function(e){e.INBOUND="inbound-rtp",e.OUTBOUND="outbound-rtp",e.CODEC="codec",e.MEDIA_SOURCE="media-source",e.CANDIDATE_PAIR="candidate-pair",e.CERTIFICATE="certificate",e.DATA_CHANNEL="data-channel",e.LOCAL_CANDIDATE="local-candidate",e.REMOTE_CANDIDATE="remote-candidate",e.PEER_CONNECTION="peer-connection",e.REMOTE_INBOUND="remote-inbound-rtp",e.REMOTE_OUTBOUND="remote-outbound-rtp",e.TRANSPORT="transport"}(et||(et={})),function(e){e.STALE_STATS="STALE_STATS",e.STATE_REGRESSION="STATE_REGRESSION",e.EXCESSIVE_RTT="EXCESSIVE_RTT",e.ICE_TIMEOUT="ICE_TIMEOUT"}(tt||(tt={}));class it{constructor(e,t,i,n){this._name="RTCStatsMonitor",this._queue=[],this._startTime=0,this._stopped=!1,this._interval=0,this._candidatePairHealth=new Map,this._name=e,this._renegotiationPolicy=n,this._config={...pe,...t},this._client=i,this._identifier={name:this._name,created:(new Date).getTime(),fingerprint:ie.getOrGenerateFingerprint(),device:ie.getBrowserDetails(),client:t}}_emptyStatsReportQueue(){for(var e;this._queue.length>0;){const t=this._queue.shift(),i=null===(e=this._client)||void 0===e?void 0:e.getMessageTransport();i?i.post(t):H(this._name,"Failed to post stats data to message transport. Message transport is not available.")}}_getStats(){const{_connection:e}=this;if(e)try{e.getStats(null).then((e=>{e.forEach((e=>{this._handleStatsReport(e)}))})).catch((e=>{k(this._name,`Failed to get stats report. ${e.message||e}`)}))}catch(e){k(this._name,`Failed to get stats report. ${e.message||e}`)}}_handleStatsReport(e){console.log(`[${this._name}]: ${JSON.stringify(e,null,2)}`)}_appendClientDetails(e){this._identifier.client={...this._identifier.client,...e}}async start(e){this._startTime=(new Date).getTime(),this._stopped=!1,this._connection=e,this.postAction("started"),this._getStats(),this._interval=setInterval((()=>{this._stopped||this._getStats()}),this._config.interval)}stop(){this._stopped=!0,clearInterval(this._interval),this.postAction("ended")}async post(e){const t={...this._identifier,type:"stats-report",timestamp:(new Date).getTime(),data:e},{endpoint:i,additionalHeaders:n}=this._config;if(i===_e.DEV_NULL)return;if(this._client&&this._client.onStatsReport&&(null===i||i===_e.EVENT_TRANSPORT))return void this._client.onStatsReport(this._connection,t);let s={"Content-Type":"application/json"};if(n&&(s={...s,...n}),i&&i.match(/^(http|https):\/\//))try{const e=await fetch(i,{method:"POST",headers:s,body:JSON.stringify(t)});e.status>=200&&e.status<300?O(this._name,`Posted stats data to endpoint: ${i}.`):k(this._name,`Failed to post stats data to endpoint: ${i}. ${e.status}`)}catch(e){k(this._name,`Failed to post stats data to endpoint: ${i}. ${e.message||e}`)}else if(this._client&&this._client.getMessageTransport()&&(void 0===i||i===_e.DATA_CHANNEL))try{let e=!1;const i=this._client.getMessageTransport();i&&(e=await i.post(t)),!e&&this._client&&(this._queue.push(t),this._client.on(Ne.CHANGE,(()=>{this._client&&this._client.off(Ne.CHANGE),this._emptyStatsReportQueue()})),H(this._name,"Failed to post stats data to message transport. Message transport is not available. Pushed to Queue."))}catch(e){k(this._name,`Failed to post stats data to message transport. ${e.message||e}`)}}async postAction(e,t=void 0){return this.post({action:{type:e,data:t,timestamp:(new Date).getTime()}})}async postEvent(e,t){return this.post({event:{type:e,data:t||void 0,timestamp:(new Date).getTime()}})}updateEndpoint(e,t=!0){const{endpoint:i}=this._config;t?this._config.endpoint=e:t||i||(this._config.endpoint=e)}_checkCandidatePairHealth(e){var t;const{id:i,state:n,currentRoundTripTime:s,totalRoundTripTime:o}=e,a="connected"===this._client.getPeerConnection().iceConnectionState,r=(new Date).getTime();this._candidatePairHealth.has(i)||this._candidatePairHealth.set(i,{id:i,staleSampleCount:0,stateTransitionTime:r,inProgressStartTime:"in-progress"===n?r:void 0});const l=this._candidatePairHealth.get(i);if(void 0!==l.previousRTT&&void 0!==l.previousTotalRTT&&void 0!==s&&void 0!==o&&(s===l.previousRTT&&o===l.previousTotalRTT?(l.staleSampleCount++,l.staleSampleCount>=3&&l.lastIssueReported!==tt.STALE_STATS&&(this._client.emit(Pe.CONNECTION_HEALTH_STALE_STATS,{candidatePairId:i,frozenRTT:s,frozenTotalRTT:o,staleDurationSeconds:l.staleSampleCount,message:"RTT values frozen - connection may be dead"}),l.lastIssueReported=tt.STALE_STATS)):(l.staleSampleCount=0,l.lastIssueReported===tt.STALE_STATS&&(l.lastIssueReported=void 0))),"succeeded"!==l.previousState||"succeeded"===n||a||(this._client.emit(Pe.CONNECTION_HEALTH_STATE_REGRESSION,{candidatePairId:i,previousState:l.previousState,currentState:n,message:`ICE candidate pair regressed from '${l.previousState}' to '${n}' - connection lost`}),l.lastIssueReported=tt.STATE_REGRESSION,l.stateTransitionTime=r),void 0!==s&&s>1&&l.lastIssueReported!==tt.EXCESSIVE_RTT?(this._client.emit(Pe.CONNECTION_HEALTH_EXCESSIVE_RTT,{candidatePairId:i,currentRTT:s,message:`Excessive RTT detected: ${(1e3*s).toFixed(0)}ms - possible network issues`}),l.lastIssueReported=tt.EXCESSIVE_RTT):void 0!==s&&s<=1&&l.lastIssueReported===tt.EXCESSIVE_RTT&&(l.lastIssueReported=void 0),"in-progress"===n){l.inProgressStartTime||(l.inProgressStartTime=r);const e=r-l.inProgressStartTime;e>((null===(t=this._renegotiationPolicy)||void 0===t?void 0:t.iceTimeoutInterval)||5e3)&&l.lastIssueReported!==tt.ICE_TIMEOUT&&(this._client.emit(Pe.CONNECTION_HEALTH_ICE_TIMEOUT,{candidatePairId:i,durationSeconds:Math.floor(e/1e3),message:`ICE negotiation timeout - candidate pair stuck in 'in-progress' for ${Math.floor(e/1e3)}s`}),l.lastIssueReported=tt.ICE_TIMEOUT)}else l.inProgressStartTime=void 0,l.lastIssueReported===tt.ICE_TIMEOUT&&(l.lastIssueReported=void 0);l.previousState=n,l.previousRTT=s,l.previousTotalRTT=o,n!==l.previousState&&(l.stateTransitionTime=r)}dispose(){O(this._name,"[dispose]"),this.stop(),this._candidatePairHealth.clear(),this._connection=void 0,this._client=void 0}}const nt=/(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b) \d+ typ srflx/,st=e=>{const t=e.match(nt);return t&&t.length>1?t[1]:null},ot=[Te.PUBLISH_START,Te.PUBLISH_FAIL,Te.PUBLISH_INSUFFICIENT_BANDWIDTH,Te.PUBLISH_SUFFICIENT_BANDWIDTH,Te.PUBLISH_RECOVERING_BANDWIDTH,Te.STATISTICS_ENDPOINT_CHANGE];class at extends it{constructor(e,t){if(super("RTCPublisherStats",e,t),this.estimatedAudioBitrate=0,this.estimatedVideoBitrate=0,this.lastAudioReport=null,this.lastVideoReport=null,this._eventHandler=e=>{const{type:t,data:i}=e;if(ot.indexOf(t)>-1){if(t===Te.STATISTICS_ENDPOINT_CHANGE){const{statisticsEndpoint:e}=i;this.updateEndpoint(e,!1)}this.postEvent(t)}},this._candidateCreateHandler=({data:{candidate:e}})=>{const{candidate:t}=e,i=st(t);i&&(this._identifier.publicIP=i)},this._hostEndpointChangedHandler=({data:{endpoint:e,iceServers:t}})=>{this._appendClientDetails({node:e,iceServers:t})},this._client.on("*",this._eventHandler),this._client.on(ye.CANDIDATE_CREATE,this._candidateCreateHandler),this._client.on(ye.HOST_ENDPOINT_CHANGED,this._hostEndpointChangedHandler),this._client.getPeerConnection())this.start(this._client.getPeerConnection());else{const e=({data:t})=>{this._client.off(ye.PEER_CONNECTION_AVAILABLE,e),this.start(t)};this._client.on(ye.PEER_CONNECTION_AVAILABLE,e)}}_handleStatsReport(e){const{type:t}=e,{include:i}=this._config,n=i&&i.length>0;if(n&&i.indexOf(t)>=-1)this.post(e);else if(!n)if(t===et.CODEC){const{id:i,clockRate:n,mimeType:s,payloadType:o}=e;this.post({id:i,type:t,clockRate:n,mimeType:s,payloadType:o})}else if(t===et.CANDIDATE_PAIR){const{availableOutgoingBitrate:i,currentRoundTripTime:n,totalRoundTripTime:s,state:o}=e;this._checkCandidatePairHealth(e),this.post({type:t,availableOutgoingBitrate:i,currentRoundTripTime:n,totalRoundTripTime:s,state:o})}else if(t===et.MEDIA_SOURCE){const{kind:i}=e;if("audio"===i)this.post({type:t,kind:i});else if("video"===i){const{framesPerSecond:n,height:s,width:o}=e;this.post({type:t,kind:i,framesPerSecond:n,height:s,width:o})}}else if([et.OUTBOUND,"outboundrtp"].indexOf(t)>-1){const{timestamp:i,kind:n,codecId:s,mediaType:o,active:a,bytesSent:r,packetsSent:l,totalPacketsSendDelay:d}=e,h={type:t,kind:n,codecId:s,mediaType:o,active:a,bytesSent:r,packetsSent:l,totalPacketsSendDelay:d};if("audio"===n){if(this.lastAudioReport){const{bytesSent:e,timestamp:t}=this.lastAudioReport,n=8*(r-e)/(i-t);this.estimatedAudioBitrate=n}this.post({...h,estimatedBitrate:Math.floor(this.estimatedAudioBitrate)}),this.lastAudioReport=e}else if("video"===n){const{firCount:t,pliCount:n,frameWidth:s,frameHeight:o,framesEncoded:a,framesPerSecond:l,framesSent:d,keyFramesEncoded:c,qualityLimitationReason:u,qualityLimitationDurations:p}=e;let _={...h,firCount:t,pliCount:n,frameWidth:s,frameHeight:o,framesEncoded:a,framesPerSecond:l,framesSent:d,keyFramesEncoded:c,qualityLimitationReason:"none"!==u?u:void 0,qualityLimitationDurations:"none"!==u?p:void 0};if(this.lastVideoReport){const{bytesSent:e,timestamp:t}=this.lastVideoReport,n=8*(r-e)/(i-t);this.estimatedVideoBitrate=n}this.post({..._,estimatedBitrate:Math.floor(this.estimatedVideoBitrate)}),this.lastVideoReport=e}}}dispose(){this._client.off("*",this._eventHandler),this._client.off(ye.CANDIDATE_CREATE,this._candidateCreateHandler),this._client.off(ye.HOST_ENDPOINT_CHANGED,this._hostEndpointChangedHandler),super.dispose()}}const rt={pubnub:window.PubNub,userId:`user-${Math.floor(65536*Math.random()).toString(16)}`,publishKey:void 0,subscribeKey:void 0,authToken:void 0,cloudEndpoint:void 0,backendUrl:void 0,backendURL:void 0,expiryMinutes:120,channelId:"red5",logLevel:"trace"};var lt;!function(e){e.CONNECTED="PubNub.Connected",e.DISCONNECTED="PubNub.Disconnected",e.SUBSCRIBE_SUCCESS="PubNub.Subscribe.Success",e.SUBSCRIBE_FAILURE="PubNub.Subscribe.Failure",e.UNSUBSCRIBE_SUCCESS="PubNub.Unsubscribe.Success",e.UNSUBSCRIBE_FAILURE="PubNub.Unsubscribe.Failure",e.MESSAGE_RECEIVED="PubNub.Message.Received",e.MESSAGE_SEND_SUCCESS="PubNub.Message.Send.Success",e.MESSAGE_SEND_FAILURE="PubNub.Message.Send.Failure",e.AUTH_TOKEN_GENERATED="PubNub.AuthToken.Generated",e.AUTH_TOKEN_GENERATION_ERROR="PubNub.AuthToken.Generation.Error",e.STATUS="PubNub.Status",e.ERROR="PubNub.Error"}(lt||(lt={}));const dt="PubNubService";class ht{constructor(){}_decodeToken(e){const t=e.split(".")[1].replace(/-/g,"+").replace(/_/g,"/"),i=decodeURIComponent(atob(t).split("").map((e=>"%"+("00"+e.charCodeAt(0).toString(16)).slice(-2))).join(""));return JSON.parse(i)}async getAuthTokenFromBackendService(e){var t;const{userId:i,backendUrl:n,backendURL:s,channelId:o="red5",expiryMinutes:a=120}=e;if(!n&&!s)throw new Error("Backend URL is required. Please provide a backend URL in the pubnub configuration.");const r={userId:i,channelId:o,read:!0,write:!0,ttlMinutes:a};try{const e=await fetch(n||s,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)});if(!e.ok)throw new Error("Failed to generate auth token. Please try again later.");const t=await e.json(),{token:i}=t;return i}catch(e){throw new Error(null!==(t=e.message)&&void 0!==t?t:"Failed to generate auth token. Please try again later.")}}async getAuthTokenFromCloud(e){var t;const{userId:i,cloudEndpoint:n,publishKey:s,subscribeKey:o,channelId:a="red5",expiryMinutes:r=120}=e;if(!n)throw new Error("Cloud endpoint is required. Please provide a cloud endpoint in the pubnub configuration.");try{const e=n.match(/^https?:\/\//)?n:`https://${n}`,t=await fetch(`${e}/config-meetings/api/generate-token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({userId:i,channelId:a,expirationMinutes:r})});if(!t.ok)throw new Error("Failed to generate auth token. Please try again later.");const d=await t.json(),{success:h,token:c}=d;if(!h)throw new Error("Failed to generate auth token. Please try again later.");const u=this._decodeToken(c);if(!u)throw new Error("Failed to decode auth token. Please try again later.");l=`[${dt}] :: Decoded auth token: ${JSON.stringify(u)}`,O(dt,l);const{uid:p,roomId:_,pubnubPublishKey:g,pubnubSubscribeKey:m,pubnubToken:v}=u;if(p!==i||_!==a)throw new Error("Invalid auth token. Please try again later.");if(g!==s||m!==o)throw new Error("Invalid auth token. Please try again later.");return v}catch(e){throw new Error(null!==(t=e.message)&&void 0!==t?t:"Failed to generate auth token. Please try again later.")}var l}}const ct="PubNubClient",ut={receivePresenceEvents:!0,withPresence:!1},pt=e=>O(ct,e),_t=e=>H(ct,e),gt=e=>k(ct,e);class mt extends U{constructor(){super(),this._subscriptions={}}async _getAuthFromCloud(e){const t=new ht;return await t.getAuthTokenFromCloud(e)}async _getAuthFromBackend(e){const t=new ht;return await t.getAuthTokenFromBackendService(e)}async init(e){var t,i,n,s,o,a,r;if(this._config={...rt,...e},(null===(t=this._config)||void 0===t?void 0:t.cloudEndpoint)||(null===(i=this._config)||void 0===i?void 0:i.backendUrl)||(null===(n=this._config)||void 0===n?void 0:n.backendURL)){let e;try{if((null===(s=this._config)||void 0===s?void 0:s.cloudEndpoint)?e=await this._getAuthFromCloud(this._config):((null===(o=this._config)||void 0===o?void 0:o.backendUrl)||(null===(a=this._config)||void 0===a?void 0:a.backendURL))&&(e=await this._getAuthFromBackend(this._config)),!e)throw new Error("Failed to get auth token.");this._config.authToken=e,this.trigger(new be(lt.AUTH_TOKEN_GENERATED,this,{authToken:e}))}catch(e){return gt(null!==(r=e.message)&&void 0!==r?r:"Failed to get auth token."),this.trigger(new be(lt.AUTH_TOKEN_GENERATION_ERROR,this,{error:e.message})),this}}const{pubnub:l,publishKey:d,subscribeKey:h,authToken:c,userId:u,logLevel:p}=this._config;if(!l){const e="PubNub library is not initialized. Please provide a PubNub library reference in the configuration.";throw this.trigger(new be(lt.ERROR,this,{error:e})),gt(e),new Error(e)}return pt(`Initializing PubNub client with options: ${JSON.stringify(this._config)}`),this._pubnub=new l({userId:u,publishKey:d,subscribeKey:h,logLevel:p}),this._pubnub.setToken(c),this._pubnub.addListener({message:e=>{var t;pt(`Message received on channel ${e.channel}: ${e.message}`),this.trigger(new be(lt.MESSAGE_RECEIVED,this,{...e,userId:null===(t=this._config)||void 0===t?void 0:t.userId}))},presence:e=>{pt(`Presence event on channel ${e.channel}: ${JSON.stringify(e)}`)},status:e=>{const{category:t,operation:i}=e;pt(`Status event ${t}`),this.trigger(new be(lt.STATUS,this,e)),"PNConnectedCategory"===t?(this.trigger(new be(lt.CONNECTED,this,e)),"PNSubscribeOperation"===i&&this.trigger(new be(lt.SUBSCRIBE_SUCCESS,this,e))):"PNDisconnectedCategory"===t?this.trigger(new be(lt.DISCONNECTED,this,e)):"PNReconnectedCategory"===t||("PNAcknowledgmentCategory"===t?"PNUnsubscribeOperation"===i&&this.trigger(new be(lt.UNSUBSCRIBE_SUCCESS,this,e)):("PNBadRequestCategory"===t||"PNAccessDeniedCategory"===t)&&this.trigger(new be(lt.ERROR,this,e)))}}),this}async publishMessage(e,t){var i,n;if(!this._pubnub)return gt("PubNub client not initialized."),!1;try{const n=await this._pubnub.publish({channel:e,message:t});this.trigger(new be(lt.MESSAGE_SEND_SUCCESS,this,{...n,channel:e,message:t,userId:null===(i=this._config)||void 0===i?void 0:i.userId}))}catch(i){return gt(null!==(n=i.message)&&void 0!==n?n:`Failed to publish message to channel ${e}.`),this.trigger(new be(lt.MESSAGE_SEND_FAILURE,this,{channel:e,message:t})),!1}return!0}async subscribe(e,t){var i;if(!this._pubnub)return gt("PubNub client not initialized."),!1;if(this._subscriptions[e])return!0;try{const i=this._pubnub.channel(e),n=await i.subscription({...ut,...t});if(!n)throw new Error(`Failed to subscribe to channel ${e}.`);n.subscribe(),this._subscriptions[e]=n}catch(t){return gt(null!==(i=t.message)&&void 0!==i?i:`Failed to subscribe to channel ${e}.`),this.trigger(new be(lt.SUBSCRIBE_FAILURE,this,{channel:e})),!1}return!0}async unsubscribe(e){var t;if(!this._pubnub)return!0;if(!this._subscriptions[e])return _t(`Subscription ${e} not found.`),!1;try{await this._subscriptions[e].unsubscribe()}catch(i){gt(null!==(t=i.message)&&void 0!==t?t:`Failed to unsubscribe from channel ${e}.`),this.trigger(new be(lt.UNSUBSCRIBE_FAILURE,this,{channel:e}))}return delete this._subscriptions[e],!0}async destroy(){var e;if(this._pubnub)try{await this._pubnub.destroy()}catch(t){_t(null!==(e=t.message)&&void 0!==e?e:"Failed to destroy PubNub client.")}return this._subscriptions={},this._pubnub=void 0,this._config=void 0,!0}getOptions(){var e;return null!==(e=this._config)&&void 0!==e?e:{}}get config(){return this._config}get pubnub(){return this._pubnub}}const vt="WHIPClient",Et=ge,St=e=>O(vt,e),Ct=e=>k(vt,e),bt=e=>H(vt,e);class ft extends U{constructor(e,t,i){super();const n=e?se(e):Et,s=i||Et,o={...s,...n,endpoint:e,mediaElementId:t?t.id:s.mediaElementId};e&&this.internalInit(o),this._onOrientationChange=this._onOrientationChange.bind(this)}async internalInit(e){await this.init(e),await this.publish()}async generateMediaStream(e){var t,i;const{onGetUserMedia:n}=e;if(n){St("Requesting gUM from user-defined configuration:onGetUserMedia.");const e=await n();return this.trigger(new Ee(ye.CONSTRAINTS_ACCEPTED,this,ae(e))),e}{const{mediaConstraints:n}=e;let s;St(`Requesting gUM using mediaConstraints: ${JSON.stringify(n,null,2)}`);let o=n;const a=await Ve(o);return a&&a.media||(s=await ie.gUM(o)),s=null!==(t=null==a?void 0:a.media)&&void 0!==t?t:s,o=null!==(i=null==a?void 0:a.constraints)&&void 0!==i?i:n,St(`Constraints accepted: ${JSON.stringify(o,null,2)}`),this.trigger(new Ee(ye.CONSTRAINTS_ACCEPTED,this,{constraints:o,...ae(s)})),s}}async getAndPreviewStreamIfAvailable(){var e;let t=this._mediaStream;if(!t){try{t=null!=t?t:await this.generateMediaStream(this._options)}catch(t){const i=null!==(e=t.message)&&void 0!==e?e:"Could not generate media stream.";throw this.trigger(new Ee(ye.CONSTRAINTS_REJECTED,this,{constraints:this._options.mediaConstraints})),new Error(i)}if(!t)throw new Error("Could not generate media stream.")}return this.trigger(new Ee(ye.MEDIA_STREAM_AVAILABLE,this,t)),this.preview(t),t}establishStatsMonitor(e){return new at(e,{onStatsReport:this._onStatsReport.bind(this),getPeerConnection:this.getPeerConnection.bind(this),getMessageTransport:this.getMessageTransport.bind(this),on:this.on.bind(this),off:this.off.bind(this),trigger:this.trigger.bind(this),emit:this.emit.bind(this)})}postStatsMonitorEvent(e,t){this._statsMonitor&&this._statsMonitor.postEvent(e,t)}reorderCodecPreferences(e,t,i){e.getTransceivers().forEach((e=>{if(e.sender&&e.sender.track){const{kind:n}=e.sender.track;if(t&&"video"===n&&e.setCodecPreferences)try{const{codecs:i}=RTCRtpSender.getCapabilities("video"),n=i.findIndex((e=>e.mimeType===`video/${t}`));if(n>-1){const t=i.slice(0),s=i[n];t.splice(n,1),t.unshift(s),e.setCodecPreferences(t)}}catch(e){bt(`[videoEncoding] Could not set codec preferences for ${t}. ${e.message||e}`)}else if(i&&"audio"===n&&e.setCodecPreferences)try{const{codecs:t}=RTCRtpSender.getCapabilities("audio"),n=t.findIndex((e=>e.mimeType===`audio/${i}`));if(n>-1){const i=t[n];t.splice(n,1),t.unshift(i),e.setCodecPreferences(t)}}catch(e){bt(`[audioEncoding] Could not set codec preferences for ${i}. ${e.message||e}`)}}}))}async postOffer(e){var t;try{const{sdp:i}=e;let{videoEncoding:n}=this._options;const{mungeOffer:s,streamMode:o,keyFramerate:a,iceTransport:r,connectionParams:d,mediaConstraints:h,forceVP8:c,audioEncoding:u,offerSDPResolution:p}=this._options;c&&!n&&(n=l.VP8);let _=i;s&&(St(`[MUNGE:before] offer: ${_}`),_=s(_),St(`[MUNGE:after] offer: ${_}`)),p&&(St(`[MUNGE] Setting resolution on offer: ${_}`),_=((e,t)=>{if(!t)return e;const{width:i,height:n}=t;if(!i||!n)return e;const s=`a=framesize:${i}-${n}`,o=e.split("\r\n");let a=o.length;const r=/^m=video/;for(;--a>-1;)if(r.exec(o[a])){for(;++a-1){o.splice(a+1,0,s);break}break}return o.join("\r\n")})(_,((e,t)=>{let i;if(e)try{const t=e.getVideoTracks()&&e.getVideoTracks()[0];if(t){const e=t.getSettings();i={width:e.width,height:e.height}}}catch(e){H("[determineMediaResolution]",`Could not determine resolution from MediaStream. ${e.message||e}`)}if(!i)try{const e=t.video,{width:n,height:s}=e;if(n&&s)if("number"==typeof n&&"number"==typeof s)i={width:n,height:s};else{i={width:n.exact||n.min||n.max||n.ideal||640,height:s.exact||s.min||s.max||s.ideal||480}}}catch(e){H("[determineMediaResolution]",`Could not determine resolution from MediaConstraints. ${e.message||e}`)}return i&&O("[determineMediaResolution]",`constraints: ${JSON.stringify(i,null,2)}`),i})(this._mediaStream,h)),St(`[MUNGE:after] offer: ${_}`));const g={...d,mode:o,transport:r,keyFramerate:a};return n&&(g.videoEncoding=n),u&&(g.audioEncoding=u),await(null===(t=this._whipWhepService)||void 0===t?void 0:t.postSDPOffer(_,g))}catch(e){throw Ct(e.message||e),e instanceof xe?this.trigger(new Ee(Te.PUBLISH_INVALID_NAME,this)):(this.trigger(new Ee(Te.CONNECT_FAILURE,this,e)),this.unpublish()),e}}async postCandidateFragments(e){var t;const{connectionParams:i}=this._options,n=Fe(e,void 0,!0);return await(null===(t=this._whipWhepService)||void 0===t?void 0:t.trickle(n,i))}async initPubNub(e){var t;try{const t=new mt;this._pubnubClient=t,this._pubnubClient.on("*",(e=>{this.trigger(e)})),await t.init(e)}catch(e){return e(null!==(t=e.message)&&void 0!==t?t:"Failed to initialize PubNub."),!1}return!0}async deinitPubNub(){var e,t;try{await(null===(e=this._pubnubClient)||void 0===e?void 0:e.destroy()),this._pubnubClient=void 0}catch(e){return e(null!==(t=e.message)&&void 0!==t?t:"Failed to deinitialize PubNub."),!1}return!0}async init(e){var t,i;this._options={...Et,...e};const n=oe(this._options),{includeDataChannel:s,disableProxy:o}=this._options;return this._whipWhepService=new Xe(n,s,o),this._messageTransport=this._whipWhepService,(null===(t=this._options)||void 0===t?void 0:t.stats)&&this.monitorStats(this._options.stats),this._mediaStream=await this.getAndPreviewStreamIfAvailable(),(null===(i=this._options)||void 0===i?void 0:i.pubnub)&&await this.initPubNub(this._options.pubnub),this}async initWithStream(e,t){return this._mediaStream=t,this.init(e)}async publish(e){var t,i,n,s,o;e&&(this._options.streamName=e);const{forceVP8:a,audioEncoding:r,rtcConfiguration:d,dataChannelConfiguration:h,includeDataChannel:c,signalingSocketOnly:u,enableChannelSignaling:p,connectionParams:_,bandwidth:g,mungeAnswer:m}=this._options;let{videoEncoding:v}=this._options;a&&(v=l.VP8,this._options.videoEncoding=v),this._mediaStream||(this._mediaStream=await this.getAndPreviewStreamIfAvailable());try{const e=null!=_?_:{};if(_){const{transcode:t}=_;t&&(e.transcode=t)}const o=await(null===(t=this._whipWhepService)||void 0===t?void 0:t.getOptions(e)),a=!!(null===(i=this._options)||void 0===i?void 0:i.rtcConfiguration)&&Array.isArray(this._options.rtcConfiguration.iceServers)&&this._options.rtcConfiguration.iceServers.length>0;(null==o?void 0:o.links)&&!a&&(this._options.rtcConfiguration={...d,iceServers:o.links}),(null==o?void 0:o.origin)&&this.trigger(new Ee(ye.HOST_ENDPOINT_CHANGED,this,{endpoint:o.origin})),(null==o?void 0:o.statisticsEndpoint)&&this._onStatisticsEndpointChange(o.statisticsEndpoint);const l=c||p||u?h:void 0;this._peerConnectionHelper=new Ge({onDataChannelError:this._onDataChannelError.bind(this),onSendReceived:this._onSendReceived.bind(this),onMetaData:this._onMetaData.bind(this),onConnectionClosed:this._onConnectionClosed.bind(this),onDataChannelOpen:this._onDataChannelOpen.bind(this),onDataChannelClose:this._onDataChannelClose.bind(this),onDataChannelMessage:this._onDataChannelMessage.bind(this),onPeerConnectionOpen:this._onPeerConnectionOpen.bind(this),onPeerConnectionFail:this._onPeerConnectionFail.bind(this),onPeerConnectionClose:this._onPeerConnectionClose.bind(this),onIceCandidate:this._onIceCandidate.bind(this),onSDPSuccess:this._onSDPSuccess.bind(this),onSDPError:this._onSDPError.bind(this),onStatisticsEndpointChange:this._onStatisticsEndpointChange.bind(this),onPublisherStatus:this._onPublisherStatus.bind(this),onPeerConnectionTrackAdd:this._onPeerConnectionTrackAdd.bind(this),onInsufficientBandwidth:this._onInsufficientBandwidth.bind(this),onSufficientBandwidth:this._onSufficientBandwidth.bind(this),onRecoveringBandwidth:this._onRecoveringBandwidth.bind(this),onUnpublish:this._onUnpublish.bind(this)}),await this._peerConnectionHelper.setUpWithPeerConfiguration(this._options.rtcConfiguration,l),this.trigger(new Ee(ye.PEER_CONNECTION_AVAILABLE,this,this.getPeerConnection())),this._mediaStream&&this._mediaStream.getTracks().forEach((e=>{var t;null===(t=this.getPeerConnection())||void 0===t||t.addTransceiver(e,{direction:"sendonly"})})),this.reorderCodecPreferences(this.getPeerConnection(),v,r);const E=await(null===(n=this._peerConnectionHelper)||void 0===n?void 0:n.createOfferWithoutSetLocal(g));await this._peerConnectionHelper.setLocalDescription(E),this.trigger(new Ee(ye.OFFER_START,this,E));const{sdp:S}=await this.postOffer(E);let C=S;m&&(St(`[MUNGE:before] answer: ${C}`),C=m(C),St(`[MUNGE:after] answer: ${C}`)),await this._peerConnectionHelper.setRemoteDescription({type:"answer",sdp:C}),this.trigger(new Ee(ye.OFFER_END,this,C));const b=await this._peerConnectionHelper.waitToGatherIce(),{sdp:f}=b;return await this.postCandidateFragments(f),this.trigger(new Ee(ye.ICE_TRICKLE_COMPLETE,this)),ie.addOrientationChangeHandler(this._onOrientationChange),(null===(s=this._options)||void 0===s?void 0:s.includeDataChannel)||this.trigger(new Ee(Te.PUBLISH_START,this)),this}catch(e){throw Ct(null!==(o=e.message)&&void 0!==o?o:"Could not publish."),this.trigger(new Ee(Te.CONNECT_FAILURE,this,e)),this.unpublish(!0),e}}async unpublish(e=!1){var t;St("[unpublish]"),this._peerConnectionHelper&&await this._peerConnectionHelper.tearDown(),this._whipWhepService&&await this._whipWhepService.tearDown(null,e),(null===(t=this._options)||void 0===t?void 0:t.clearMediaOnUnpublish)&&this.unpreview(),this._pubnubClient&&await this.deinitPubNub(),this.unmonitorStats(),this._pubnubClient=void 0,this._mediaStream=void 0,this._peerConnectionHelper=void 0,this._whipWhepService=void 0,this._messageTransport=void 0,this._publishView=void 0,this.trigger(new Ee(Te.UNPUBLISH_SUCCESS,this)),ie.removeOrientationChangeHandler(this._onOrientationChange)}preview(e){const{mediaElementId:t}=this._options;t&&(St("[preview]"),this._publishView=new Ze(t),this._publishView.preview(e))}unpreview(){this._mediaStream&&this._mediaStream.getTracks().forEach((e=>{e.stop()})),this._publishView&&(St("[unpreview]"),this._publishView.unpreview()),this._publishView=void 0}monitorStats(e){St("[monitorStats]");const{host:t,endpoint:i,app:n,streamName:s,connectionParams:o}=this._options,a=null!=e?e:pe;return this._statisticsConfiguration={...a,host:t,hostEndpoint:i,app:n,streamName:s,connectionParams:o},this._statsMonitor?bt("Cannot monitor stats without a Peer Connection. Please call `init` before calling `monitorStats`."):this._statsMonitor=this.establishStatsMonitor(this._statisticsConfiguration),this}unmonitorStats(){return this._statsMonitor&&this._statsMonitor.dispose(),this._statsMonitor=void 0,this._statisticsConfiguration=void 0,this}muteAudio(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteAudio:!0}})}unmuteAudio(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteAudio:!1}})}muteVideo(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteVideo:!0}})}unmuteVideo(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteVideo:!1}})}async send(e,t){var i;let n=t;try{n="string"==typeof t?JSON.parse(t):t}catch(e){bt(`Could not parse data as JSON. Sending as message. Error: ${e.message||e}`),n={message:t}}return null===(i=this.getMessageTransport())||void 0===i?void 0:i.post({send:{method:e,data:n}})}async sendPubNub(e,t){return this._pubnubClient?await this._pubnubClient.publishMessage(e,t):(Ct("PubNub client not initialized."),!1)}async subscribePubNub(e,t){return this._pubnubClient?await this._pubnubClient.subscribe(e,t):(Ct("PubNub client not initialized."),!1)}async unsubscribePubNub(e){return this._pubnubClient?await this._pubnubClient.unsubscribe(e):(Ct("PubNub client not initialized."),!1)}async callServer(e,t){var i;try{if(!this.getMessageTransport())throw new Error("Message transport not available");return null===(i=this.getMessageTransport())||void 0===i?void 0:i.postAsync({callAdapter:{method:e,arguments:t}})}catch(e){Ct(e.message||e)}}sendLog(e,t){var i;try{const n=Object.keys(L).find((t=>t.toLowerCase()===e.toLowerCase()))?e:L.DEBUG,s="string"==typeof t?t:JSON.stringify(t);null===(i=this.getMessageTransport())||void 0===i||i.post({log:n.toUpperCase(),message:s})}catch(e){const t=e.message||e;Ct("Could not send log to server. Message parameter expected to be String or JSON-serializable object."),Ct(t)}}get options(){return this._options}getOptions(){return this._options}getPeerConnection(){var e;return null===(e=this._peerConnectionHelper)||void 0===e?void 0:e.connection}getDataChannel(){var e;return null===(e=this._peerConnectionHelper)||void 0===e?void 0:e.dataChannel}getMediaStream(){return this._mediaStream}getMessageTransport(){return this._messageTransport}getPubNubClient(){return this._pubnubClient}_onDataChannelError(e,t){Ct(`Data channel error: ${t}`),this.trigger(new Ee(ye.DATA_CHANNEL_ERROR,this,{dataChannel:e,error:t}))}_onSendReceived(e,t){St(`Send received: ${e} ${JSON.stringify(t)}`),"onMetaData"===e?this._onMetaData(t):this.trigger(new Ee(Te.PUBLISH_SEND_INVOKE,this,{methodName:e,data:t}))}_onMetaData(e){St(`Metadata received: ${JSON.stringify(e)}`),this.trigger(new Ee(Te.PUBLISH_METADATA,this,e))}_onConnectionClosed(){St("Connection closed"),this.unpublish(),this.trigger(new Ee(Te.CONNECTION_CLOSED,this))}_onDataChannelOpen(e){St(`Data channel opened: ${e.label}`),this.trigger(new Ee(ye.DATA_CHANNEL_OPEN,this,{dataChannel:e})),this.trigger(new Ee(ye.DATA_CHANNEL_AVAILABLE,this,{name:e.label,dataChannel:e})),this._messageTransport=this._peerConnectionHelper,this.trigger(new Ce(Ne.CHANGE,this,{controller:this,transport:this._messageTransport})),this.trigger(new Ee(Te.PUBLISH_START,this))}_onDataChannelClose(e){St(`Data channel closed: ${e.label}`),this.trigger(new Ee(ye.DATA_CHANNEL_CLOSE,this,{dataChannel:e}))}_onDataChannelMessage(e,t){St(`Data channel message: ${t.data}`),this.trigger(new Ee(ye.DATA_CHANNEL_MESSAGE,this,{dataChannel:e,message:t}))}_onPeerConnectionTrackAdd(e){St(`Peer connection track added: ${e.id}`),this.trigger(new Ee(ye.TRACK_ADDED,this,{track:e}))}_onPeerConnectionOpen(){St("Peer connection opened"),this.trigger(new Ee(ye.PEER_CONNECTION_OPEN,this,this.getPeerConnection()))}_onPeerConnectionFail(){Ct("Peer connection failed"),this.trigger(new Ee(Te.PUBLISH_FAIL,this))}_onPeerConnectionClose(e){St(`Peer connection closed: ${e.type}`),this._peerConnectionHelper&&this._peerConnectionHelper.tearDown(),this.trigger(new Ee(Te.CONNECTION_CLOSED,this,e))}_onIceCandidate(e){St(`ICE candidate: ${JSON.stringify(e,null,2)}`),this.trigger(new Ee(ye.CANDIDATE_CREATE,this,{candidate:e}))}_onUnpublish(){St("Unpublish received")}_onPublisherStatus(e){St("[publisherstatus] - "+JSON.stringify(e,null,2)),e.code&&"NetStream.Publish.IsAvailable"===e.code?this.trigger(new Ee(Te.PUBLISH_AVAILABLE,this,e)):this.trigger(new Ee(Te.PUBLISH_STATUS,this,e))}_onInsufficientBandwidth(e){this.trigger(new Ee(Te.PUBLISH_INSUFFICIENT_BANDWIDTH,this,e))}_onSufficientBandwidth(e){this.trigger(new Ee(Te.PUBLISH_SUFFICIENT_BANDWIDTH,this,e))}_onRecoveringBandwidth(e){this.trigger(new Ee(Te.PUBLISH_RECOVERING_BANDWIDTH,this,e))}_onSDPSuccess(e=void 0){const t=e?": "+JSON.stringify(e,null,2):"";St(`[onsdpsuccess]:: ${t}`)}_onSDPError(e=void 0){this.trigger(new Ee(Te.PUBLISH_FAIL,this));const t=e?": "+JSON.stringify(e,null,2):"";Ct(`[onsdperror]:: ${t}`)}_onOrientationChange(e){const t=this.getMessageTransport();t&&t.post({send:{method:"onMetaData",data:{deviceOrientation:e}}})}_onStatisticsEndpointChange(e){St(`Statistics endpoint changed: ${e}`),this._statsMonitor&&this._statsMonitor.updateEndpoint(e),this.trigger(new Ee(Te.STATISTICS_ENDPOINT_CHANGE,this,{statisticsEndpoint:e}))}_onStatsReport(e,t){this.trigger(new Ee(ye.STATS_REPORT,this,{connection:e,report:t}))}on(e,t){super.on(e,t)}off(e,t){super.off(e,t)}trigger(e){super.trigger(e)}emit(e,t){this.trigger(new Ee(e,this,t))}getType(){return"RTC"}}const Tt={...{protocol:"https",port:443,app:"live",autoLayoutOrientation:!0,mediaElementId:"red5pro-subscriber",rtcConfiguration:{iceCandidatePoolSize:2,bundlePolicy:"max-bundle"},iceTransport:de.UDP,muteOnAutoplayRestriction:!0,maintainConnectionOnSubscribeErrors:!1,dataChannelConfiguration:{name:"red5pro"},signalingSocketOnly:!1,includeDataChannel:!0,maintainStreamVariant:!1,buffer:0,stats:void 0,pubnub:void 0,renegotiationPolicy:void 0},signalingSocketOnly:!1,enableChannelSignaling:!1,includeDataChannel:!0,disableProxy:!0,trickleIce:!0,postEmptyOffer:!1,mungeOffer:void 0,mungeAnswer:void 0},yt={protocol:"https",port:443,app:"live",mediaElementId:"red5pro-subscriber",muteOnAutoplayRestriction:!0},wt={endpoint:_e.DEV_NULL,interval:3e3},At="R5ProPlaybackView";class Nt{constructor(e="red5pro-subscriber"){try{this._targetElement=ie.resolveElement(e)}catch(e){throw k(At,`Could not instantiate a new instance of Red5ProSubscriber. Reason: ${e.message||e}`),e}}attachStream(e){const t=this.isAutoplay;O(At,"[attachstream]"),ie.setVideoSource(this._targetElement,e,t)}detachStream(){O(At,"[detachstream]"),ie.setVideoSource(this._targetElement,null,this.isAutoplay)}get isAutoplay(){return ie.hasAttributeDefined(this._targetElement,"autoplay")}get view(){return this._targetElement}}const Pt="RTCPeerConnectionSubscriber";class Lt extends Ie{constructor(e){super(e,Pt)}_removeConnectionHandlers(e){e.onconnectionstatechange=null,e.oniceconnectionstatechange=null,e.onicegatheringstatechange=null,e.onsignalingstatechange=null,e.onicecandidate=null,e.ontrack=null,e.onnegotiationneeded=null}_addConnectionHandlers(e){let t;e.onsignalingstatechange=()=>{const t=e.signalingState;O(Pt,`[peer.onsignalingstatechange] - State: ${t}`)},e.onconnectionstatechange=()=>{const{connectionState:t}=e;"connected"===t?(O(this._name,"[peerconnection:open]"),this._responder.onPeerConnectionOpen()):"failed"===t||"disconnected"===t?(H(this._name,`[peerconnection:error]:: ${t}`),"failed"===t&&this._responder.onPeerConnectionFail()):O(this._name,`[peerconnection:state]:: ${t}`)},e.oniceconnectionstatechange=i=>{const{iceConnectionState:n}=e;O(this._name,`[peer.oniceconnectionstatechange] - State: ${n}`),"failed"===n?(t&&clearTimeout(t),this._responder.onPeerConnectionFail(),this._responder.onPeerConnectionClose(i)):"disconnected"===n?t=setTimeout((()=>{O(this._name,"[peer.oniceconnectionstatechange] - Reconnect timeout reached."),clearTimeout(t),this._responder.onPeerConnectionClose(i)}),3e3):t&&(O(this._name,"[peer.oniceconnectionstatechange] - Clearing timeout for reconnect."),clearTimeout(t))},e.onicecandidate=e=>{const{candidate:t}=e;O(this._name,`[peer.onicecandidate] - Peer Candidate: ${null==t?void 0:t.candidate}`),t&&this._responder.onIceCandidate(t)},e.onnegotiationneeded=()=>{O(this._name,"[peer.onnegotiationneeded]")},e.onicegatheringstatechange=()=>{const{iceGatheringState:t}=e;O(this._name,`[peer.onicegatheringstatechange] - State: ${t}`)}}_onDataChannelMessage(e){const t=e;if(super._onDataChannelMessage(e))return!0;const i=this.getJsonFromSocketMessage(t);if(null===i)return H(this._name,"Determined websocket response not in correct format. Aborting message handle."),!0;O(this._name,"[datachannel-response]: "+JSON.stringify(i,null,2));const{data:n}=i;if(n&&"status"===n.type)return"NetStream.Play.UnpublishNotify"===n.code?(this._responder.onUnpublish(),this._responder.onConnectionClosed(),!0):"Application.Statistics.Endpoint"===n.code?(this._responder.onStatisticsEndpointChange(n.statistics),!0):(O(Pt,`[datachannel.message] status :: ${n.code}`),this._responder.onSubscriberStatus(n),!0);if(n&&n.status&&"NetStream.Play.UnpublishNotify"===n.status)return this._responder.onUnpublish(),this._responder.onConnectionClosed(),!0;if(n&&"result"===n.type){const{message:e}=n;if("Stream switch: Success"===e)try{return this._responder.onStreamSwitchComplete(),!0}catch(e){}}return this._responder.onDataChannelMessage(this._dataChannel,t),!1}}var Rt;!function(e){e.EMPTY="Empty",e.VIDEO="Video",e.AUDIO="Audio",e.FULL="Video/Audio"}(Rt||(Rt={}));class It extends U{trigger(e){super.trigger(e)}on(e,t){super.on(e,t)}off(e,t){super.off(e,t)}}class Dt extends It{}const Ot=[we.SUBSCRIBE_START,we.SUBSCRIBE_STOP,we.SUBSCRIBE_FAIL,we.SUBSCRIBE_PUBLISHER_CONGESTION,we.SUBSCRIBE_PUBLISHER_RECOVERY,we.PLAY_UNPUBLISH,we.STREAMING_MODE_CHANGE,we.PLAYBACK_STATE_CHANGE,we.STATISTICS_ENDPOINT_CHANGE];class Ht extends it{constructor(e,t,n){if(super("RTCSubscriberStats",e,t,n),this.estimatedAudioBitrate=0,this.estimatedVideoBitrate=0,this.lastAudioReport=null,this.lastVideoReport=null,this._eventHandler=e=>{const{type:t,data:n}=e;if(Ot.indexOf(t)>-1)if(t===we.STREAMING_MODE_CHANGE){const{streamingMode:e,previousStreamingMode:i}=n;this.postEvent(t,{data:{streamingMode:e,previousStreamingMode:i}})}else if(t===we.PLAYBACK_STATE_CHANGE){const{code:e}=n;let t;e===i.AVAILABLE&&(t={timeToFirstFrameMS:(new Date).getTime()-this._startTime}),this.postEvent(s[e],t)}else{if(t===we.STATISTICS_ENDPOINT_CHANGE){const{statisticsEndpoint:e}=n;this.updateEndpoint(e,!1)}this.postEvent(t)}},this._candidateCreateHandler=({data:{candidate:e}})=>{const{candidate:t}=e,i=st(t);i&&(this._identifier.publicIP=i)},this._hostEndpointChangedHandler=({data:{endpoint:e,iceServers:t}})=>{this._appendClientDetails({node:e,iceServers:t})},this._client.on("*",this._eventHandler),this._client.on(Ae.CANDIDATE_CREATE,this._candidateCreateHandler),this._client.on(Ae.HOST_ENDPOINT_CHANGED,this._hostEndpointChangedHandler),this._client.getPeerConnection())this.start(this._client.getPeerConnection());else{const e=({data:t})=>{this._client.off(Ae.PEER_CONNECTION_AVAILABLE,e),this.start(t)};this._client.on(Ae.PEER_CONNECTION_AVAILABLE,e)}}_handleStatsReport(e){const{type:t}=e,{include:i}=this._config,n=i&&i.length>0;if(n&&i.indexOf(t)>=-1)this.post(e);else if(!n)if(t===et.CODEC){const{id:i,clockRate:n,mimeType:s,payloadType:o}=e;this.post({id:i,type:t,clockRate:n,mimeType:s,payloadType:o})}else if(t===et.CANDIDATE_PAIR){const{availableOutgoingBitrate:i,currentRoundTripTime:n,totalRoundTripTime:s,state:o}=e;this._checkCandidatePairHealth(e),this.post({type:t,availableOutgoingBitrate:i,currentRoundTripTime:n,totalRoundTripTime:s,state:o})}else if([et.INBOUND,"inboundrtp"].indexOf(t)>-1){const{timestamp:i,kind:n,codecId:s,jitter:o,packetsLost:a,packetsReceived:r,bytesReceived:l}=e,d={type:t,kind:n,codecId:s,jitter:o,packetsLost:a,packetsReceived:r,bytesReceived:l};if("audio"===n){const{packetsDiscarded:t}=e;if(this.lastAudioReport){const{bytesReceived:e,timestamp:t}=this.lastAudioReport,n=8*(l-e)/(i-t);this.estimatedAudioBitrate=n}this.post({...d,packetsDiscarded:t,estimatedBitrate:Math.floor(this.estimatedAudioBitrate)}),this.lastAudioReport=e}else if("video"===n){const{firCount:t,frameWidth:n,frameHeight:s,framesDecoded:o,framesDropped:a,framesPerSecond:r,framesReceived:h,freezeCount:c,keyFramesDecoded:u,nackCount:p,pauseCount:_,pliCount:g,totalFreezesDuration:m,totalPausesDuration:v}=e,E={...d,firCount:t,frameWidth:n,frameHeight:s,framesDecoded:o,framesDropped:a,framesPerSecond:r,framesReceived:h,freezeCount:c,keyFramesDecoded:u,nackCount:p,pauseCount:_,pliCount:g,totalFreezesDuration:m,totalPausesDuration:v};if(this.lastVideoReport){const{bytesReceived:e,timestamp:t}=this.lastVideoReport,n=8*(l-e)/(i-t);this.estimatedVideoBitrate=n}this.post({...E,estimatedBitrate:Math.floor(this.estimatedVideoBitrate)}),this.lastVideoReport=e}}}dispose(){this._client.off("*",this._eventHandler),this._client.off(Ae.CANDIDATE_CREATE,this._candidateCreateHandler),this._client.off(Ae.HOST_ENDPOINT_CHANGED,this._hostEndpointChangedHandler),super.dispose()}}class kt extends Dt{constructor(e,t){super(),this._isVOD=!1,this._name=`SourceHandler-${t}`,this._view=e,this._playbackNotificationCenter=this._view,this.onCanPlay=this._onCanPlay.bind(this),this.onDurationChange=this._onDurationChange.bind(this),this.onEnded=this._onEnded.bind(this),this.onTimeUpdate=this._onTimeUpdate.bind(this),this.onPlay=this._onPlay.bind(this),this.onPause=this._onPause.bind(this),this.onVolumeChange=this._onVolumeChange.bind(this),this.onLoadedData=this._onLoadedData.bind(this),this.onLoadedMetadata=this._onLoadedMetadata.bind(this),this.onResize=this._onResize.bind(this),this.onLoadStart=this._onLoadStart.bind(this),this.onSuspend=this._onSuspend.bind(this),this.onStalled=this._onStalled.bind(this),this.onWaiting=this._onWaiting.bind(this),this.onError=this._onError.bind(this),this.onEncrypted=this._onEncrypted.bind(this),this._addPlaybackNotificationCenterHandlers(this._playbackNotificationCenter),ie.onFullScreenStateChange(this._handleFullScreenChange.bind(this))}_addPlaybackNotificationCenterHandlers(e){e.addEventListener("canplay",this.onCanPlay),e.addEventListener("durationchange",this.onDurationChange),e.addEventListener("ended",this.onEnded),e.addEventListener("timeupdate",this.onTimeUpdate),e.addEventListener("play",this.onPlay),e.addEventListener("pause",this.onPause),e.addEventListener("volumechange",this.onVolumeChange),e.addEventListener("loadeddata",this.onLoadedData),e.addEventListener("loadedmetadata",this.onLoadedMetadata),e.addEventListener("resize",this.onResize),e.addEventListener("loadstart",this.onLoadStart),e.addEventListener("suspend",this.onSuspend),e.addEventListener("stalled",this.onStalled),e.addEventListener("waiting",this.onWaiting),e.addEventListener("error",this.onError),e.addEventListener("encrypted",this.onEncrypted)}_removePlaybackNotificationCenterHandlers(e){e.removeEventListener("canplay",this.onCanPlay),e.removeEventListener("durationchange",this.onDurationChange),e.removeEventListener("ended",this.onEnded),e.removeEventListener("timeupdate",this.onTimeUpdate),e.removeEventListener("play",this.onPlay),e.removeEventListener("pause",this.onPause),e.removeEventListener("volumechange",this.onVolumeChange),e.removeEventListener("loadeddata",this.onLoadedData),e.removeEventListener("loadedmetadata",this.onLoadedMetadata),e.removeEventListener("resize",this.onResize),e.removeEventListener("loadstart",this.onLoadStart),e.removeEventListener("suspend",this.onSuspend),e.removeEventListener("stalled",this.onStalled),e.removeEventListener("waiting",this.onWaiting),e.removeEventListener("error",this.onError)}_handleFullScreenChange(e){var t,i;e?null===(t=this._view)||void 0===t||t.classList.add("red5pro-media-container-full-screen"):null===(i=this._view)||void 0===i||i.classList.remove("red5pro-media-container-full-screen"),this.trigger(new Se(we.FULL_SCREEN_STATE_CHANGE,void 0,e))}_cleanup(){this._playbackNotificationCenter&&this._removePlaybackNotificationCenterHandlers(this._playbackNotificationCenter),this._playbackNotificationCenter=void 0,this._view=void 0}_onCanPlay(e){var t;O(this._name,"[videoelement:event] canplay");const s=null!==(t=this._playbackNotificationCenter)&&void 0!==t?t:e.target,o=this.getControls();o&&o.enable(!0),this.trigger(new Se(we.PLAYBACK_STATE_CHANGE,void 0,{code:i.AVAILABLE,state:n.AVAILABLE})),this.trigger(new Se(we.VOLUME_CHANGE,void 0,{volume:s.volume}))}_onDurationChange(e){var t;O(this._name,"[videoelement:event] durationchange");const i=null!==(t=this._playbackNotificationCenter)&&void 0!==t?t:e.target,n=this.getControls();n&&n.setPlaybackDuration(i.duration),!isNaN(i.duration)&&Number.isFinite(i.duration)&&(this._isVOD=!0)}_onEnded(){O(this._name,"[videoelement:event] ended");const e=this.getControls();e&&e.setState(i.IDLE),this.trigger(new Se(we.PLAYBACK_STATE_CHANGE,void 0,{code:i.IDLE,state:n.IDLE}))}_onTimeUpdate(e){var t;const i=null!==(t=this._playbackNotificationCenter)&&void 0!==t?t:e.target,n=this.getControls();n&&n.setSeekTime(i.currentTime,this.isVOD()?i.duration:void 0),this.trigger(new Se(we.PLAYBACK_TIME_UPDATE,void 0,{time:i.currentTime,duration:i.duration}))}_onPlay(){O(this._name,"[videoelement:event] play");const e=this.getControls();e&&e.setState(i.PLAYING),this.trigger(new Se(we.PLAYBACK_STATE_CHANGE,void 0,{code:i.PLAYING,state:n.PLAYING}))}_onPause(){O(this._name,"[videoelement:event] pause");const e=this.getControls();e&&e.setState(i.PAUSED),this.trigger(new Se(we.PLAYBACK_STATE_CHANGE,void 0,{code:i.PAUSED,state:n.PAUSED}))}_onVolumeChange(e){var t;O(this._name,"[videoelement:event] volumechange");const i=null!==(t=this._playbackNotificationCenter)&&void 0!==t?t:e.target,n=this.getControls();n&&n.getVolume()!==i.volume&&n.setVolume(i.volume),this.trigger(new Se(we.VOLUME_CHANGE,void 0,{volume:i.volume}))}_onLoadedData(e){var t,i,n;O(this._name,"[videoelement:event] loadeddata");const s=null!==(t=this._view)&&void 0!==t?t:e.target;this.trigger(new Se(we.VIDEO_DIMENSIONS_CHANGE,void 0,{width:null!==(i=s.videoWidth)&&void 0!==i?i:0,height:null!==(n=s.videoHeight)&&void 0!==n?n:0}))}_onLoadedMetadata(e){var t,i;O(this._name,"[videoelement:event] loadedmetadata");const n=null!==(t=this._view)&&void 0!==t?t:e.target;this.trigger(new Se(we.LOADED_METADATA,void 0,{duration:null!==(i=n.duration)&&void 0!==i?i:0}))}_onResize(e){var t,i,n;O(this._name,"[videoelement:event] resize");const s=null!==(t=this._view)&&void 0!==t?t:e.target;this.trigger(new Se(we.VIDEO_DIMENSIONS_CHANGE,void 0,{width:null!==(i=s.videoWidth)&&void 0!==i?i:0,height:null!==(n=s.videoHeight)&&void 0!==n?n:0}))}_onLoadStart(){O(this._name,"[videoelement:event] loadstart")}_onSuspend(){O(this._name,"[videoelement:event] suspend")}_onStalled(){O(this._name,"[videoelement:event] stalled")}_onWaiting(){O(this._name,"[videoelement:event] waiting")}_onEncrypted(){O(this._name,"[videoelement:event] encrypted")}_onError(e){O(this._name,"[videoelement:event] error"),this.trigger(new Se(we.CONNECT_FAILURE,void 0,{error:e.message}))}async attemptAutoplay(e=!1){try{await this.play(),this.isMuted()&&this.trigger(new Se(we.AUTO_PLAYBACK_MUTED,void 0,{element:this._view}))}catch(t){e?(this.mute(),this.attemptAutoplay(e)):this.trigger(new Se(we.AUTO_PLAYBACK_FAILURE,void 0,{error:t.message?t.message:t,element:this._view}))}}async play(){var e,t;if(O(this._name,"[videoelement:action] play"),!(null===(e=this._view)||void 0===e?void 0:e.paused))return O(this._name,"[videoelement:action] play (ALREADY PLAYING)"),!0;try{return await(null===(t=this._view)||void 0===t?void 0:t.play()),!0}catch(e){throw k(this._name,"[videoelement:action] play (FAULT) - "+e.message),e}}async pause(){var e;O(this._name,"[videoelement:action] pause");try{return await(null===(e=this._view)||void 0===e?void 0:e.pause()),!0}catch(e){H(this._name,"[videoelement:action] pause (CATCH::FAULT) - "+e.message)}return!1}async resume(){var e;O(this._name,"[videoelement:action] resume");try{return await(null===(e=this._view)||void 0===e?void 0:e.play()),!0}catch(e){H(this._name,"[videoelement:action] resume (CATCH::FAULT) - "+e.message)}return!1}async stop(){var e;O(this._name,"[videoelement:action] stop");try{return await(null===(e=this._view)||void 0===e?void 0:e.pause()),!0}catch(e){H(this._name,"[videoelement:action] stop (CATCH::FAULT) - "+e.message)}return!1}mute(){this._view&&(this._view.muted=!0);const e=this.getControls();e&&e.setMutedState(!0)}unmute(){this._view&&(this._view.muted=!1);const e=this.getControls();e&&e.setMutedState(!1)}setVolume(e){this.unmute(),this._view&&(this._view.volume=e)}getVolume(){var e,t;return null!==(t=null===(e=this._view)||void 0===e?void 0:e.volume)&&void 0!==t?t:0}seekTo(e,t=void 0){this._view&&(this._view.currentTime=t?e*t:e)}toggleFullScreen(e){try{(e||this._view)&&ie.toggleFullScreen(null!=e?e:this._view)}catch(e){}}async unpublish(){var e;try{await this.stop(),null===(e=this._view)||void 0===e||e.dispatchEvent(new Event("ended"))}catch(e){}}disconnect(){this._cleanup()}isVOD(){return this._isVOD}isMuted(){var e,t;return null!==(t=null===(e=this._view)||void 0===e?void 0:e.muted)&&void 0!==t&&t}getControls(){}}const Mt="WHEPClient",Ut=Tt,Bt=e=>O(Mt,e),Vt=e=>k(Mt,e),Ft=e=>H(Mt,e);class $t extends It{constructor(e,t,i){super(),this._videoMuted=!0,this._audioMuted=!0;const n=e?se(e):Ut,s=i||Ut,o={...s,...n,endpoint:e,mediaElementId:t?t.id:s.mediaElementId};this._videoUnmuteHandler=this._onVideoUnmute.bind(this),this._audioUnmuteHandler=this._onAudioUnmute.bind(this),e&&this.internalInit(o)}async internalInit(e){await this.init(e),await this.subscribe()}async _runMuteCheck(){var e,t,i;if(this.getPeerConnection())try{let n=this._videoMuted,s=this._audioMuted;const o=await(null===(e=this.getPeerConnection())||void 0===e?void 0:e.getStats());if(null==o||o.forEach((e=>{const{type:t,kind:i,bytesReceived:o}=e;"inbound-rtp"!==t&&"inboundrtp"!==t||("video"===i?n=o<=0:"audio"===i&&(s=o<=0))})),n===this._videoMuted&&s===this._audioMuted)return;this._videoMuted=n,this._audioMuted=s;const a={data:{streamingMode:(t=!this._videoMuted,i=!this._audioMuted,t&&i?Rt.FULL:t?Rt.VIDEO:i?Rt.AUDIO:Rt.EMPTY),method:"onMetaData"},type:"metadata",method:"onMetaData",eventTimestamp:(new Date).getTime()};this._onMetaData(a)}catch(e){Vt(e.message||e)}}_onVideoUnmute(e){const t=e.target;null==t||t.removeEventListener("unmute",this._videoUnmuteHandler);const i=setTimeout((async()=>{clearTimeout(i),this._runMuteCheck()}),1e3)}_onAudioUnmute(e){const t=e.target;null==t||t.removeEventListener("unmute",this._audioUnmuteHandler);const i=setTimeout((async()=>{clearTimeout(i),this._runMuteCheck()}),1e3)}_attachSourceHandler(e){this._sourceHandler=new kt(e,this.getType())}_glomTrigger(e){e.on("*",(e=>{const{type:t,data:i}=e;this.trigger(new Se(t,this,i))}))}_playIfAutoplaySet(e,t){var i;if(e&&t){const{muteOnAutoplayRestriction:n}=e;ie.hasAttributeDefined(t,"autoplay")&&(null===(i=this._sourceHandler)||void 0===i||i.attemptAutoplay(n))}}addMediaStreamToPlayback(e,t){var i;!this._playbackView&&e&&(this._playbackView=new Nt(e)),null===(i=this._playbackView)||void 0===i||i.attachStream(t)}async requestOffer(i){var n;Bt("[requestoffer]");const{iceTransport:s,maintainStreamVariant:o,videoEncoding:a,audioEncoding:r,connectionParams:l,mungeOffer:d}=this._options;i.addTransceiver("video",{direction:"recvonly"}),i.addTransceiver("audio",{direction:"recvonly"});const h={transport:s,doNotSwitch:o};a&&a!==t.NONE&&(h.videoEncoding=a),r&&r!==e.NONE&&(h.audioEncoding=r);const c=null!=l?l:{},u=await i.createOffer(),p=await(null===(n=this._whipWhepService)||void 0===n?void 0:n.postSDPOffer(u.sdp,{...c,...h},!1));if(!p)throw Vt("Failed to get offer from WHEP"),new Error("Failed to get offer from WHEP");const{sdp:_}=p;let g=_;return d&&(Bt(`[MUNGE:before] offer: ${g}`),g=d(g),Bt(`[MUNGE:after] offer: ${g}`)),g}async requestAnswer(e){const{mungeAnswer:t}=this._options;let i=(await e.createAnswer()).sdp;return t&&(Bt(`[MUNGE:before] answer: ${i}`),i=t(i),Bt(`[MUNGE:after] answer: ${i}`)),i}async sendAnswer(e){var t;const{connectionParams:i}=this._options;return await(null===(t=this._whipWhepService)||void 0===t?void 0:t.postSDPAnswer(e,i))}async postCandidateFragments(e){var t;const{connectionParams:i}=this._options,n=Fe(e,void 0,!0);return await(null===(t=this._whipWhepService)||void 0===t?void 0:t.trickle(n,i))}async initPubNub(e){var t;try{const t=new mt;this._pubnubClient=t,this._pubnubClient.on("*",(e=>{this.trigger(e)})),await t.init(e)}catch(e){return e(null!==(t=e.message)&&void 0!==t?t:"Failed to initialize PubNub."),!1}return!0}async deinitPubNub(){var e,t;try{await(null===(e=this._pubnubClient)||void 0===e?void 0:e.destroy()),this._pubnubClient=void 0}catch(e){return e(null!==(t=e.message)&&void 0!==t?t:"Failed to deinitialize PubNub."),!1}return!0}_evaluateRenegotiationPolicy(e){const{renegotiationPolicy:t}=this._options;if(t){const{type:i}=t,n=i.toLowerCase();Bt(`[evaluateRenegotiationPolicy] - Type: ${e}, Renegotiation Policy: ${t.type}`),(e===Pe.CONNECTION_HEALTH_STATE_REGRESSION&&"regression"===n||e===Pe.CONNECTION_HEALTH_ICE_TIMEOUT&&"timeout"===n||e===we.CONNECTION_CLOSED&&"disconnect"===n)&&this._reconnect()}}async _reconnect(){var e,t;Bt("[reconnect]"),this.trigger(new Se(we.RECONNECT_START,this));try{await this.unsubscribe(!0),await this.init(this._options),await this.subscribe()}catch(i){Vt(null!==(e=i.message)&&void 0!==e?e:"Could not reconnect."),this.trigger(new Se(we.RECONNECT_FAILURE,this,{error:null!==(t=i.message)&&void 0!==t?t:"Could not reconnect."}))}}async init(e){var t,i,n;this._options={...Ut,...e},this._options.subscriptionId=this._options.subscriptionId||`subscriber-${Math.floor(65536*Math.random()).toString(16)}`;const s=oe(this._options,"whep"),{includeDataChannel:o,disableProxy:a}=this._options;return this._whipWhepService=new Xe(`${s}?requestId=${this._options.subscriptionId}`,o,a),this._messageTransport=this._whipWhepService,((null===(t=this._options)||void 0===t?void 0:t.stats)||(null===(i=this._options)||void 0===i?void 0:i.renegotiationPolicy))&&(!this._options.stats&&this._options.renegotiationPolicy&&(this._options.stats=wt),this.monitorStats(this._options.stats,this._options.renegotiationPolicy)),(null===(n=this._options)||void 0===n?void 0:n.pubnub)&&await this.initPubNub(this._options.pubnub),this}async subscribe(){var e,t,i,n,s,o,a,r,l;const{connectionParams:d,rtcConfiguration:h,includeDataChannel:c,signalingSocketOnly:u,enableChannelSignaling:p,dataChannelConfiguration:_}=this._options;try{const l=d||{},m=await(null===(e=this._whipWhepService)||void 0===e?void 0:e.getOptions(l));this.trigger(new Se(we.CONNECT_SUCCESS,this,null===(t=this._whipWhepService)||void 0===t?void 0:t.getUrl()));const v=!!(null===(i=this._options)||void 0===i?void 0:i.rtcConfiguration)&&Array.isArray(this._options.rtcConfiguration.iceServers)&&this._options.rtcConfiguration.iceServers.length>0;(null==m?void 0:m.links)&&!v&&(this._options.rtcConfiguration={...h,iceServers:m.links}),(null==m?void 0:m.origin)&&this.trigger(new Se(Ae.HOST_ENDPOINT_CHANGED,this,{endpoint:m.origin})),(null==m?void 0:m.statisticsEndpoint)&&this._onStatisticsEndpointChange(m.statisticsEndpoint);const E=c||p||u?_:void 0;this._peerConnectionHelper=new Lt({onUnpublish:this._onUnpublish.bind(this),onStreamUnavailable:this._onStreamUnavailable.bind(this),onSubscriberStatus:this._onSubscriberStatus.bind(this),onStreamSwitchComplete:this._onStreamSwitchComplete.bind(this),onDataChannelError:this._onDataChannelError.bind(this),onSendReceived:this._onSendReceived.bind(this),onMetaData:this._onMetaData.bind(this),onConnectionClosed:this._onConnectionClosed.bind(this),onDataChannelOpen:this._onDataChannelOpen.bind(this),onDataChannelClose:this._onDataChannelClose.bind(this),onDataChannelMessage:this._onDataChannelMessage.bind(this),onPeerConnectionOpen:this._onPeerConnectionOpen.bind(this),onPeerConnectionFail:this._onPeerConnectionFail.bind(this),onPeerConnectionClose:this._onPeerConnectionClose.bind(this),onIceCandidate:this._onIceCandidate.bind(this),onSDPSuccess:this._onSDPSuccess.bind(this),onSDPError:this._onSDPError.bind(this),onStatisticsEndpointChange:this._onStatisticsEndpointChange.bind(this)}),await this._peerConnectionHelper.setUpWithPeerConfiguration(this._options.rtcConfiguration,E),null===(n=this.getPeerConnection())||void 0===n||n.addEventListener("track",(e=>{const{buffer:t}=this._options;Bt("[peerconnection.ontrack]");const{streams:i,track:n,receiver:s,transceiver:o}=e;s.jitterBufferDelayHint=t,this.trigger(new Se(Ae.TRACK_ADDED,this,{streams:i,track:n,receiver:s,transceiver:o})),this._mediaStream=i&&i.length>0?i[0]:void 0,"video"===n.kind?(this._videoMuted=n.muted,n.muted&&n.addEventListener("unmute",this._videoUnmuteHandler)):"audio"===n.kind&&(this._audioMuted=n.muted,n.muted&&n.addEventListener("unmute",this._audioUnmuteHandler)),this._runMuteCheck()})),this.trigger(new Se(Ae.PEER_CONNECTION_AVAILABLE,this,this.getPeerConnection())),this.trigger(new Se(Ae.OFFER_START,this));const S=await this.requestOffer(this.getPeerConnection()),C=new RTCSessionDescription({type:"offer",sdp:S});await(null===(s=this.getPeerConnection())||void 0===s?void 0:s.setRemoteDescription(C)),this.trigger(new Se(Ae.OFFER_END,this)),this.trigger(new Se(Ae.ANSWER_START,this));const b=await this.requestAnswer(this.getPeerConnection()),f=(g=b).includes("stereo=1")?g:g.replace("useinbandfec=1","useinbandfec=1;stereo=1;sprop-stereo=1"),T=new RTCSessionDescription({type:"answer",sdp:f});await(null===(o=this.getPeerConnection())||void 0===o?void 0:o.setLocalDescription(T)),await this.sendAnswer(f),this.trigger(new Se(Ae.ANSWER_END,this));const y=await this._peerConnectionHelper.waitToGatherIce(),{sdp:w}=y;return await this.postCandidateFragments(w),this.trigger(new Se(Ae.ICE_TRICKLE_COMPLETE,this)),this._mediaStream&&(this.trigger(new Se(Ae.ON_ADD_STREAM,this,this._mediaStream)),this.addMediaStreamToPlayback(this._options.mediaElementId,this._mediaStream)),(null===(a=this._playbackView)||void 0===a?void 0:a.view)&&this._attachSourceHandler(this._playbackView.view),this._sourceHandler&&this._glomTrigger(this._sourceHandler),this._playIfAutoplaySet(this._options,null===(r=this._playbackView)||void 0===r?void 0:r.view),this}catch(e){throw Vt(null!==(l=e.message)&&void 0!==l?l:"Could not subscribe."),e instanceof xe?this._onStreamUnavailable(e):this.trigger(new Se(we.CONNECT_FAILURE,this,e)),this._options.maintainConnectionOnSubscribeErrors||this.unsubscribe(!0),e}var g}async unsubscribe(e=!1){var t;Bt("[unsubscribe]"),this._peerConnectionHelper&&await this._peerConnectionHelper.tearDown(),this._whipWhepService&&await this._whipWhepService.tearDown(null,e),this._sourceHandler&&this._sourceHandler.disconnect(),this._pubnubClient&&await this.deinitPubNub(),this.unmonitorStats(),null===(t=this._playbackView)||void 0===t||t.detachStream(),this._playbackView=void 0,this._pubnubClient=void 0,this._whipWhepService=void 0,this._messageTransport=void 0,this._peerConnectionHelper=void 0,this._sourceHandler=void 0,this._mediaStream=void 0,this.trigger(new Se(we.SUBSCRIBE_STOP,this))}async send(e,t){var i;let n=t;try{n="string"==typeof t?JSON.parse(t):t}catch(e){Ft(`Could not parse data as JSON. Sending as message. Error: ${e.message||e}`),n={message:t}}return null===(i=this.getMessageTransport())||void 0===i?void 0:i.post({send:{method:e,data:n}})}async sendPubNub(e,t){return this._pubnubClient?await this._pubnubClient.publishMessage(e,t):(Vt("PubNub client not initialized."),!1)}async subscribePubNub(e,t){return this._pubnubClient?await this._pubnubClient.subscribe(e,t):(Vt("PubNub client not initialized."),!1)}async unsubscribePubNub(e){return this._pubnubClient?await this._pubnubClient.unsubscribe(e):(Vt("PubNub client not initialized."),!1)}async callServer(e,t){var i;const n="switchStreams"===e,{app:s,streamName:o}=this._options;if(n){const{path:i}=t[0];this._requestedStreamSwitch=i,Bt(`[callServer:switch]:: ${e}, ${s}/${o} -> ${i}`)}return null===(i=this.getMessageTransport())||void 0===i?void 0:i.postAsync({callAdapter:{method:e,arguments:t}})}sendLog(e,t){var i;try{const n=Object.keys(L).find((t=>t.toLowerCase()===e.toLowerCase()))?e:L.DEBUG,s="string"==typeof t?t:JSON.stringify(t);null===(i=this.getMessageTransport())||void 0===i||i.post({log:n.toUpperCase(),message:s})}catch(e){const t=e.message||e;Vt("Could not send log to server. Message parameter expected to be String or JSON-serializable object."),Vt(t)}}enableStandby(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteAudio:!0,muteVideo:!0}})}disableStandby(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteAudio:!1,muteVideo:!1}})}muteAudio(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteAudio:!0}})}unmuteAudio(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteAudio:!1}})}muteVideo(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteVideo:!0}})}unmuteVideo(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteVideo:!1}})}get options(){return this._options}getOptions(){return this._options}getPeerConnection(){var e;return null===(e=this._peerConnectionHelper)||void 0===e?void 0:e.connection}getDataChannel(){var e;return null===(e=this._peerConnectionHelper)||void 0===e?void 0:e.dataChannel}getMediaStream(){return this._mediaStream}getMessageTransport(){return this._messageTransport}getPubNubClient(){return this._pubnubClient}getPlayer(){var e;return null===(e=this._playbackView)||void 0===e?void 0:e.view}play(){Bt("[play]"),this._sourceHandler?this._sourceHandler.play():Ft("Cannot play without a Source Handler.")}pause(){Bt("[pause]"),this._sourceHandler?this._sourceHandler.pause():Ft("Cannot pause without a Source Handler.")}resume(){Bt("[resume]"),this._sourceHandler?this._sourceHandler.resume():Ft("Cannot resume without a Source Handler.")}stop(){Bt("[stop]"),this._sourceHandler?this._sourceHandler.stop():Ft("Cannot stop without a Source Handler.")}setVolume(e){Bt("[setVolume]"),this._sourceHandler?this._sourceHandler.setVolume(e):Ft("Cannot set volume without a Source Handler.")}getVolume(){var e,t,i;return Bt("[getVolume]"),this._sourceHandler?this._sourceHandler.getVolume():(Ft("Cannot get volume without a Source Handler."),null!==(i=null===(t=null===(e=this._playbackView)||void 0===e?void 0:e.view)||void 0===t?void 0:t.volume)&&void 0!==i?i:0)}mute(){Bt("[mute]"),this._sourceHandler?this._sourceHandler.mute():Ft("Cannot mute without a Source Handler.")}unmute(){Bt("[unmute]"),this._sourceHandler?this._sourceHandler.unmute():Ft("Cannot unmute without a Source Handler.")}seekTo(e){Bt("[seekTo]"),this._sourceHandler?this._sourceHandler.seekTo(e):Ft("Cannot seek without a Source Handler.")}toggleFullScreen(){Bt("[toggleFullScreen]"),this._sourceHandler?this._sourceHandler.toggleFullScreen():Ft("Cannot toggle full screen without a Source Handler.")}monitorStats(e,t){Bt(`[monitorStats]:: Stats: ${e?JSON.stringify(e):"undefined"}`),Bt(`[monitorStats]:: Renegotiation Policy: ${t?JSON.stringify(t):"undefined"}`);const{host:i,endpoint:n,app:s,streamName:o,subscriptionId:a,connectionParams:r}=this._options,l=null!=e?e:pe;return this._statisticsConfiguration={...l,host:i,app:s,hostEndpoint:n,streamName:o,subscriptionId:a,connectionParams:r},this._statsMonitor?Ft("Cannot monitor stats without a Peer Connection. Please call `init` before calling `monitorStats`."):this._statsMonitor=new Ht(this._statisticsConfiguration,{onStatsReport:this._onStatsReport.bind(this),getPeerConnection:this.getPeerConnection.bind(this),getMessageTransport:this.getMessageTransport.bind(this),on:this.on.bind(this),off:this.off.bind(this),trigger:this.trigger.bind(this),emit:this.emit.bind(this)},t),this}unmonitorStats(){return this._statsMonitor&&this._statsMonitor.dispose(),this._statsMonitor=void 0,this._statisticsConfiguration=void 0,this}_onUnpublish(){Bt("[unpublish]"),this.trigger(new Se(we.PLAY_UNPUBLISH,this)),this._sourceHandler&&this._sourceHandler.unpublish()}_onStreamUnavailable(e){Bt(`Stream ${this._options.streamName} does not exist.`),Bt("[onstreamunavailable]: "+JSON.stringify(e,null,2)),this.trigger(new Se(we.SUBSCRIBE_INVALID_NAME,this))}_onDataChannelError(e,t){Vt(`Data channel error: ${t}`),this.trigger(new Se(Ae.DATA_CHANNEL_ERROR,this,{dataChannel:e,error:t}))}_onSendReceived(e,t){Bt(`Send received: ${e} ${JSON.stringify(t)}`),"onMetaData"===e?this._onMetaData(t):this.trigger(new Se(we.SUBSCRIBE_SEND_INVOKE,this,{methodName:e,data:t}))}_onStreamSwitchComplete(){Bt("[streamswitch::complete]");const e=this._requestedStreamSwitch;this.trigger(new Se(Ae.SUBSCRIBE_STREAM_SWITCH,this,{path:e})),this._requestedStreamSwitch=void 0}_onMetaData(e){const{orientation:t,streamingMode:i}=e,n=this._streamingMode;void 0!==t&&t!==this._orientation&&(this._orientation=t,this.trigger(new Se(we.ORIENTATION_CHANGE,this,{orientation:parseInt(t,10),viewElement:this._playbackView?this._playbackView.view:void 0}))),i&&void 0!==i&&i!==n&&(this._streamingMode=i,this.trigger(new Se(we.STREAMING_MODE_CHANGE,this,{streamingMode:i,previousStreamingMode:n,viewElement:this._playbackView?this._playbackView.view:void 0}))),this.trigger(new Se(we.SUBSCRIBE_METADATA,this,e))}_onConnectionClosed(){Bt("Connection closed"),this.unsubscribe(!0),this.trigger(new Se(we.CONNECTION_CLOSED,this))}_onDataChannelOpen(e){Bt(`Data channel opened: ${e.label}`),this.trigger(new Se(Ae.DATA_CHANNEL_OPEN,this,{dataChannel:e})),this.trigger(new Se(Ae.DATA_CHANNEL_AVAILABLE,this,{name:e.label,dataChannel:e})),this._messageTransport=this._peerConnectionHelper,this.trigger(new Ce(Ne.CHANGE,this,{controller:this,transport:this._messageTransport})),this.trigger(new Se(we.SUBSCRIBE_START,this))}_onDataChannelClose(e){Bt(`Data channel closed: ${e.label}`),this.trigger(new Se(Ae.DATA_CHANNEL_CLOSE,this,{dataChannel:e}))}_onDataChannelMessage(e,t){Bt(`Data channel message: ${t.data}`),this.trigger(new Se(Ae.DATA_CHANNEL_MESSAGE,this,{dataChannel:e,message:t}))}_onPeerConnectionOpen(){var e;Bt("Peer connection opened"),this.trigger(new Se(Ae.PEER_CONNECTION_OPEN,this,this.getPeerConnection())),(null===(e=this._options)||void 0===e?void 0:e.includeDataChannel)||this.trigger(new Se(we.SUBSCRIBE_START,this))}_onPeerConnectionFail(){Vt("Peer connection failed"),this.trigger(new Se(we.SUBSCRIBE_FAIL,this))}_onPeerConnectionClose(e){Bt(`Peer connection closed: ${e.type}`),this._evaluateRenegotiationPolicy(we.CONNECTION_CLOSED)}_onIceCandidate(e){Bt(`ICE candidate: ${e.candidate}`),this.trigger(new Se(Ae.CANDIDATE_CREATE,this,{candidate:e}))}_onPeerConnectionTrackAdd(e){Bt(`Peer connection track added: ${e.id}`)}_onSubscriberStatus(e){Bt(`Subscriber status: ${JSON.stringify(e)}`)}_onSDPSuccess(){Bt("SDP success")}_onSDPError(e){Vt(`SDP error: ${e}`)}_onStatisticsEndpointChange(e){Bt(`Statistics endpoint changed: ${e}`),this._statsMonitor&&this._statsMonitor.updateEndpoint(e),this.trigger(new Se(we.STATISTICS_ENDPOINT_CHANGE,this,{statisticsEndpoint:e}))}_onStatsReport(e,t){this.trigger(new Se(Ae.STATS_REPORT,this,{connection:e,report:t}))}on(e,t){super.on(e,t)}off(e,t){super.off(e,t)}trigger(e){super.trigger(e)}emit(e,t){this.trigger(new Se(e,this,t)),this._evaluateRenegotiationPolicy(e)}getType(){return"RTC"}}const Gt={stream:3,datachannel:4},xt=[Le.OPEN,Le.CLOSE,Le.ERROR,Le.FAIL,Te.STATISTICS_ENDPOINT_CHANGE];class Wt extends it{constructor(e,t){if(super("MessageChannelStats",e,t),this.estimatedAudioBitrate=0,this.estimatedVideoBitrate=0,this.lastAudioReport=null,this.lastVideoReport=null,this._eventHandler=e=>{const{type:t,data:i}=e;if(xt.indexOf(t)>-1){if(t===Te.STATISTICS_ENDPOINT_CHANGE){const{statisticsEndpoint:e}=i;this.updateEndpoint(e,!1)}this.postEvent(t)}else xt.indexOf(t)>-1&&this.postEvent(t)},this._candidateCreateHandler=({data:{candidate:e}})=>{const{candidate:t}=e,i=st(t);i&&(this._identifier.publicIP=i)},this._hostEndpointChangedHandler=({data:{endpoint:e,iceServers:t}})=>{this._appendClientDetails({node:e,iceServers:t})},this._client.on("*",this._eventHandler),this._client.on(ye.CANDIDATE_CREATE,this._candidateCreateHandler),this._client.on(ye.HOST_ENDPOINT_CHANGED,this._hostEndpointChangedHandler),this._client.getPeerConnection())this.start(this._client.getPeerConnection());else{const e=({data:t})=>{this._client.off(ye.PEER_CONNECTION_AVAILABLE,e),this.start(t)};this._client.on(ye.PEER_CONNECTION_AVAILABLE,e)}}_handleStatsReport(e){const{type:t}=e,{include:i}=this._config,n=i&&i.length>0;if(n&&i.indexOf(t)>=-1)this.post(e);else if(!n)if(t===et.CODEC){const{id:i,clockRate:n,mimeType:s,payloadType:o}=e;this.post({id:i,type:t,clockRate:n,mimeType:s,payloadType:o})}else if(t===et.CANDIDATE_PAIR){const{availableOutgoingBitrate:i,currentRoundTripTime:n,totalRoundTripTime:s,state:o}=e;this._checkCandidatePairHealth(e),this.post({type:t,availableOutgoingBitrate:i,currentRoundTripTime:n,totalRoundTripTime:s,state:o});const{timestamp:a,kind:r,codecId:l,mediaType:d,active:h,bytesSent:c,packetsSent:u,totalPacketsSendDelay:p}=e,_={type:t,kind:r,codecId:l,mediaType:d,active:h,bytesSent:c,packetsSent:u,timestamp:a,totalPacketsSendDelay:p};this.post(_)}else if(t===et.DATA_CHANNEL){const{id:t,timestamp:i,type:n,label:s,state:o,messagesSent:a,messagesReceived:r,bytesSent:l,bytesReceived:d}=e;this.post({id:t,timestamp:i,type:n,label:s,state:o,messagesSent:a,messagesReceived:r,bytesSent:l,bytesReceived:d})}}dispose(){this._client.off("*",this._eventHandler),this._client.off(ye.CANDIDATE_CREATE,this._candidateCreateHandler),this._client.off(ye.HOST_ENDPOINT_CHANGED,this._hostEndpointChangedHandler),super.dispose()}}const Kt="DataChannelClient",jt=e=>O(Kt,e),zt=e=>k(Kt,e);class Jt extends ft{constructor(e,t){super(e,void 0,t),this._inactivePingIntervalMS=3e4,this._inactivePingTimeout=null}async internalInit(e){await this.init(e),await this.open()}establishStatsMonitor(e){return new Wt(e,{onStatsReport:this._onStatsReport.bind(this),getPeerConnection:this.getPeerConnection.bind(this),getMessageTransport:this.getMessageTransport.bind(this),on:this.on.bind(this),off:this.off.bind(this),trigger:this.trigger.bind(this),emit:this.emit.bind(this)})}async init(e){const{connectionParams:t}=e;e={...e,mediaConstraints:{audio:!1,video:!1},mediaElementId:void 0,includeDataChannel:!0,connectionParams:{...null!=t?t:{},capabilities:Gt.datachannel}};const i=await super.init(e);return jt(`Initialized MessageChannel with options: ${JSON.stringify(e,null,2)}`),i}async getAndPreviewStreamIfAvailable(){}_startInactivePing(){this._stopInactivePing(),this._inactivePingTimeout=setTimeout((()=>{const e=(new Date).toISOString();super.send("ping",{timestamp:e}),this._startInactivePing()}),this._inactivePingIntervalMS)}_stopInactivePing(){this._inactivePingTimeout&&(clearTimeout(this._inactivePingTimeout),this._inactivePingTimeout=null)}async open(e=1e4){return this._inactivePingIntervalMS=e,await super.publish()}async close(){return this._stopInactivePing(),this.postStatsMonitorEvent(Le.CLOSE),await super.unpublish()}async publish(){return await this.open()}async unpublish(){return await this.close()}async send(e,t){let i=t;try{i="string"==typeof t?JSON.parse(t):t}catch(e){i={data:t}}return await this.sendMessage({...i,methodName:e})}async sendMessage(e){const t=this.getDataChannel(),{streamName:i}=this.options?this.options:{},n=i||"unknown";if(t){let i=e;try{i="string"==typeof e?JSON.parse(e):e}catch(t){i={message:e}}const s={...i,sender_id:n,send_timestamp:(new Date).toISOString()};try{return t.send(JSON.stringify(s)),jt(`Sent message: ${JSON.stringify(s)}`),this.trigger(new fe(Le.SEND,this,s)),this._startInactivePing(),!0}catch(e){zt(`Error sending message: ${e.message||e}`),this.trigger(new fe(Le.ERROR,this,{error:e.message||e}))}}return!1}async sendData(e){const t=this.getDataChannel();if(t)try{return t.send(e),this.trigger(new fe(Le.SEND,this,e)),this._startInactivePing(),!0}catch(e){zt(`Error sending data: ${e.message||e}`),this.trigger(new fe(Le.ERROR,this,{error:e.message||e}))}return!1}_onDataChannelOpen(e){super._onDataChannelOpen(e),this._startInactivePing()}_onDataChannelMessage(e,t){const{data:i}=t;jt(`Incoming Data channel message: ${i}`),this.trigger(new fe(Le.RECEIVE,this,{dataChannel:e,message:t}))}_onDataChannelClose(e){this._stopInactivePing(),super._onDataChannelClose(e),this.trigger(new fe(Le.CLOSE,this))}_onPeerConnectionFail(){zt("Peer connection failed"),this.trigger(new fe(Le.FAIL,this))}_onSDPError(e=void 0){this.trigger(new fe(Le.ERROR,this));const t=e?": "+JSON.stringify(e,null,2):"";zt(`[onsdperror]:: ${t}`)}trigger(e){if(e.type===Te.PUBLISH_START)super.trigger(new fe(Le.OPEN,this));else if(e.type===Te.UNPUBLISH_SUCCESS)super.trigger(new fe(Le.CLOSE,this));else{const{type:t,data:i}=e;super.trigger(new fe(t,this,i))}}getType(){return"DATA_CHANNEL"}}class Yt extends kt{constructor(e,t){super(e,t),this._playingStarted=!1,this.onOrientation=this._onOrientationMetadata.bind(this),this.onStreamingMode=this._onStreamingModeMetadata.bind(this),ie.onOrientationMetadata(this._view,this.onOrientation),ie.onStreamingModeMetadata(this._view,this.onStreamingMode),this.onPlaying=this._onPlaying.bind(this),this.onSourceError=this._onSourceError.bind(this),this._view.addEventListener("playing",this.onPlaying)}addSource(e){this._source=ie.createElement("source"),this._source.type="application/x-mpegURL",this._source.src=e,this._view.firstChild?this._view.insertBefore(this._source,this._view.firstChild):this._view.appendChild(this._source),this._source.addEventListener("error",this.onSourceError)}_onPlaying(){this._playingStarted||this.trigger(new Se(we.SUBSCRIBE_START,this._view)),this._playingStarted=!0}_onSourceError(e){O(this._name,"[source:event] error"),this.trigger(new Se(we.CONNECT_FAILURE,void 0,e))}_onOrientationMetadata(e){const{orientation:t}=e,i=parseInt(t,10);t&&this._orientation!==i&&(O(this._name,"Metadata received: "+JSON.stringify(e,null,2)),this._orientation=i,this.trigger(new Se(we.ORIENTATION_CHANGE,{orientation:this._orientation,viewElement:this._view})),this.trigger(new Se(we.SUBSCRIBE_METADATA,void 0,e)))}_onStreamingModeMetadata(e){const{streamingMode:t}=e,i=this._streamingMode;t&&i!==t&&(O(this._name,"Metadata received: "+JSON.stringify(e,null,2)),this._streamingMode=t,this.trigger(new Se(we.STREAMING_MODE_CHANGE,void 0,{streamingMode:this._streamingMode,previousStreamingMode:i,viewElement:this._view})),this.trigger(new Se(we.SUBSCRIBE_METADATA,void 0,e)))}_cleanup(){this._view&&this._view.removeEventListener("playing",this.onPlaying),this._source&&(this._source.removeEventListener("error",this.onSourceError),this._view.removeChild(this._source),this._source=void 0),super._cleanup()}}const qt="HLSSubscriber",Xt=e=>O(qt,e),Qt=e=>H(qt,e);class Zt extends It{constructor(){super()}_glomTrigger(e){e.on("*",(e=>{const{type:t,data:i}=e;this.trigger(new Se(t,this,i))}))}_playIfAutoplaySet(e,t){var i;if(e&&t){const{muteOnAutoplayRestriction:n}=e;ie.hasAttributeDefined(t,"autoplay")&&(null===(i=this._sourceHandler)||void 0===i||i.attemptAutoplay(n))}}async init(e){if(!ie.supportsHLS())throw new Error("Native HLS playback is not supported on this browser.");return this._options={...yt,...e},this}async subscribe(){var e;try{const t=/^http(|s).*\.m3u8/g,{endpoint:i,mediaElementId:n}=this._options;return this._fileURL=i&&i.match(t)?i:(e=>{const{host:t,protocol:i,port:n,app:s,streamName:o,connectionParams:a}=e,r="ws"===i||"http"===i?"http":"https",l=`${r}://${t}:${n||("http"===r?5080:443)}/${s}/${o}.m3u8`;if(a)return`${l}?${Object.entries(a).map((([e,t])=>`${e}=${t}`)).join("&")}`;return l})(this._options),!this._playbackView&&n&&(this._playbackView=new Nt(n),this._sourceHandler=new Yt(this._playbackView.view,this.getType()),this._sourceHandler.addSource(this._fileURL),this._glomTrigger(this._sourceHandler)),this.trigger(new Se(we.CONNECT_SUCCESS,this,this._fileURL)),this._playIfAutoplaySet(this._options,null===(e=this._playbackView)||void 0===e?void 0:e.view),this}catch(e){throw e(e.message),this.trigger(new Se(we.CONNECT_FAILURE,this,e.message)),e}}async unsubscribe(){var e;return this._sourceHandler&&this._sourceHandler.disconnect(),null===(e=this._playbackView)||void 0===e||e.detachStream(),this._playbackView=void 0,this._sourceHandler=void 0,this.trigger(new Se(we.SUBSCRIBE_STOP,this)),this}play(){Xt("[play]"),this._sourceHandler?this._sourceHandler.play():Qt("Cannot play without a Source Handler.")}pause(){Xt("[pause]"),this._sourceHandler?this._sourceHandler.pause():Qt("Cannot pause without a Source Handler.")}resume(){Xt("[resume]"),this._sourceHandler?this._sourceHandler.resume():Qt("Cannot resume without a Source Handler.")}stop(){Xt("[stop]"),this._sourceHandler?this._sourceHandler.stop():Qt("Cannot stop without a Source Handler.")}setVolume(e){Xt("[setVolume]"),this._sourceHandler?this._sourceHandler.setVolume(e):Qt("Cannot set volume without a Source Handler.")}getVolume(){var e,t,i;return Xt("[getVolume]"),this._sourceHandler?this._sourceHandler.getVolume():(Qt("Cannot get volume without a Source Handler."),null!==(i=null===(t=null===(e=this._playbackView)||void 0===e?void 0:e.view)||void 0===t?void 0:t.volume)&&void 0!==i?i:0)}mute(){Xt("[mute]"),this._sourceHandler?this._sourceHandler.mute():Qt("Cannot mute without a Source Handler.")}unmute(){Xt("[unmute]"),this._sourceHandler?this._sourceHandler.unmute():Qt("Cannot unmute without a Source Handler.")}seekTo(e){Xt("[seekTo]"),this._sourceHandler?this._sourceHandler.seekTo(e):Qt("Cannot seek without a Source Handler.")}toggleFullScreen(){Xt("[toggleFullScreen]"),this._sourceHandler?this._sourceHandler.toggleFullScreen():Qt("Cannot toggle full screen without a Source Handler.")}getPlayer(){var e;return null===(e=this._playbackView)||void 0===e?void 0:e.view}get options(){return this._options}getOptions(){return this._options}get fileURL(){return this._fileURL}getFileURL(){return this._fileURL}getType(){return"HLS"}}const ei={baseURL:void 0,fullURL:void 0,hlsjsRef:void 0,hlsElement:void 0,usePlaybackControlsUI:!0,options:{debug:!1,backBufferLength:0}},ti={...Tt,liveSeek:ei};class ii extends U{trigger(e){super.trigger(e)}on(e,t){super.on(e,t)}off(e,t){super.off(e,t)}}var ni,si;!function(e){e.SEEK_START="Seek.Start",e.SEEK_END="Seek.End"}(ni||(ni={})),function(e){e.CHANGE="Slider.Change",e.CHANGE_START="Slider.Change.Start",e.CHANGE_COMPLETE="Slider.Change.Complete"}(si||(si={}));class oi extends ve{constructor(e,t,i){super(e,i),this._slider=t}get slider(){return this._slider}}const{createElement:ai,addGlobalEventListener:ri,removeGlobalEventListener:li,globalUnassign:di,getAssignedValue:hi,globalAssign:ci}=ie,ui="ControlSlider",pi="r5_liveseek_event_owner";class _i extends U{constructor(e){super(),this._value=0,this._disabled=!1,this._eventStartPosition=0,this.debug=e=>O(ui,e),this.warn=e=>H(ui,e),this.name=[ui,e].join("::"),this.debug("[init]"),this._container=ai("div"),this._button=this.createButton(),this._track=this.createTrack(),this._progressBar=this.createProgressBar(),this._container.appendChild(this._track),this._container.appendChild(this._progressBar),this._container.appendChild(this._button),this._layout(),this._mouseupHandler=this._mouseup.bind(this),this._mousedownHandler=this._mousedown.bind(this),this._mousemoveHandler=this._mousemove.bind(this),this._touchupHandler=this._touchproxy.bind(this),this._touchdownHandler=this._touchproxy.bind(this),this._touchmoveHandler=this._touchproxy.bind(this),this._updateHandlers(this._disabled)}_touchproxy(e){var t,i,n,s;const o=e;this.debug(`${o.type} touches: ${(null===(t=o.changedTouches)||void 0===t?void 0:t.length)||0}`);try{o.preventDefault()}catch(e){this.warn("Failed to prevent default on touch event.")}if(!o.touches||o.touches.length>1||"touchend"===o.type&&o.touches.length>0)return;let a,r="";const l=o.target||document.body;switch(o.type){case"touchstart":r="mousedown",a=null===(i=o.changedTouches)||void 0===i?void 0:i[0];break;case"touchmove":r="mousemove",a=null===(n=o.changedTouches)||void 0===n?void 0:n[0];break;case"touchend":r="mouseup",a=null===(s=o.changedTouches)||void 0===s?void 0:s[0]}if(a&&r){const e=new MouseEvent(r,{bubbles:!0,cancelable:!0,view:l.ownerDocument.defaultView,screenX:a.screenX,screenY:a.screenY,clientX:a.clientX,clientY:a.clientY,ctrlKey:o.ctrlKey,altKey:o.altKey,shiftKey:o.shiftKey,metaKey:o.metaKey,button:0,relatedTarget:null});l.dispatchEvent(e)}}_mouseup(){this._eventStartPosition=0,di(pi),li("mousemove",this._mousemoveHandler),li("mouseup",this._mouseupHandler),li("touchmove",this._touchmoveHandler),li("touchend",this._touchupHandler),this.trigger(new oi(si.CHANGE_COMPLETE,this))}_mousemove(e){if(hi(pi)!==this.name)return;this.debug(`[mousemove] ${this.name}`);const t=e.clientX-this._eventStartPosition,i=this._button.parentNode.getBoundingClientRect();let n=this._eventStartPosition+t-i.left;n=Math.max(0,n),n=Math.min(n,i.width);const s=n/i.width;this.trigger(new oi(si.CHANGE,this,s))}_mousedown(e){this._eventStartPosition=e.clientX,this.trigger(new oi(si.CHANGE_START,this)),ci(pi,this.name),ri("mousemove",this._mousemoveHandler),ri("mouseup",this._mouseupHandler),ri("touchmove",this._touchmoveHandler),ri("touchend",this._touchupHandler)}_updateHandlers(e){this._eventStartPosition=0,e?(this._track.removeEventListener("click",this._mousemoveHandler),this._progressBar.removeEventListener("click",this._mousemoveHandler),this._button.removeEventListener("mousedown",this._mousedownHandler),li("mousemove",this._mousemoveHandler),li("mouseup",this._mouseupHandler),li("touchmove",this._touchmoveHandler),li("touchend",this._touchupHandler),this._track.classList.add("red5pro-media-slider-disabled"),this._progressBar.classList.add("red5pro-media-slider-disabled"),this._button.classList.add("red5pro-media-slider-disabled")):(this._track.addEventListener("click",this._mousemoveHandler),this._progressBar.addEventListener("click",this._mousemoveHandler),this._button.addEventListener("mousedown",this._mousedownHandler),this._button.addEventListener("touchstart",this._touchdownHandler),this._track.classList.remove("red5pro-media-slider-disabled"),this._progressBar.classList.remove("red5pro-media-slider-disabled"),this._button.classList.remove("red5pro-media-slider-disabled"))}_layout(){const e=this._progressBar.parentNode.clientWidth*this._value;this._progressBar.style.width=e+"px",this._button.style.left=e-.5*this._button.clientWidth+"px"}createButton(){const e=ai("span");return e.classList.add("red5pro-media-slider-button"),e}createProgressBar(){const e=ai("span");return e.classList.add("red5pro-media-slider-progress"),e}createTrack(){const e=ai("span");return e.classList.add("red5pro-media-slider-track"),e}get value(){return this._value}set value(e){this._value=e,this._layout()}get disabled(){return this._disabled}set disabled(e){this._disabled=e,this._updateHandlers(e)}get view(){return this._container}}const{createElement:gi,isTouchEnabled:mi,isPossiblySafari:vi}=ie,Ei=e=>O("PlaybackControls",e);class Si extends ii{constructor(e,t){super(),this._state=i.IDLE,this._mutedState=!1,this._resumeAfterSeek=!1,this._playbackDuration=0,this._volumeValue=1,this._player=e,this._container=t,this._onPlayPauseClickBound=this._onPlayPauseClick.bind(this),this._decorate(this._container)}_decorate(e){if(!e)return;Ei("[decorate]");const t=gi("div");let n;t.classList.add("red5pro-media-control-bar"),this._playPauseButton=this._createPlayPauseButton(),this._muteButton=this._createMuteButton(),this._volumeField=this._createVolumeControl(),this._seekTimeField=this._createSeekControl(),this._timeField=this._createPlaybackTime(),this._fullScreenButton=this._createFullScreenToggle(),t.appendChild(this._playPauseButton),t.appendChild(this._timeField),t.appendChild(this._seekTimeField.view),t.appendChild(this._muteButton),t.appendChild(this._volumeField.view),t.appendChild(this._fullScreenButton),e.appendChild(t),this._controlbar=t;const s=()=>{clearTimeout(n),n=setTimeout((()=>{t.classList.remove("red5pro-media-control-bar-show")}),6e3)};mi()?(t.classList.add("red5pro-media-control-bar-show"),e.addEventListener("touchend",(()=>{t.classList.toggle("red5pro-media-control-bar-show"),s()})),s()):(e.addEventListener("mouseover",(()=>{t.classList.add("red5pro-media-control-bar-show")})),e.addEventListener("mouseout",(()=>{t.classList.remove("red5pro-media-control-bar-show")}))),this.setState(i.IDLE).onFullScreenChange(!1).setSeekTime(0).enable(!1)}_onPlayPauseClick(){return this.getState()===i.PLAYING?this._player.pause(!0):this.getState()===i.PAUSED?this._player.resume(!0):this._player.play(!0),this}_createPlayPauseButton(){const e=gi("button");return e.setAttribute("aria-label","Toggle Playback"),e.classList.add("red5pro-media-control-element"),e.classList.add("red5pro-media-element-button"),e.classList.add("red5pro-media-playpause-button"),e}_createMuteButton(){const e=gi("button");return e.setAttribute("aria-label","Toggle Mute Audio"),e.classList.add("red5pro-media-control-element"),e.classList.add("red5pro-media-element-button"),e.classList.add("red5pro-media-muteunmute-button"),e.addEventListener("click",(()=>{this.getMutedState()?(this._player.unmute(),this.setMutedState(!1)):(this._player.mute(),this.setMutedState(!0))})),e}_createVolumeControl(){const e=new _i("volume");return e.view.classList.add("red5pro-media-control-element"),e.view.classList.add("red5pro-media-volume-slider"),e.view.classList.add("red5pro-media-slider"),e.on(si.CHANGE,(e=>{const t=Number(e.data);this._player.setVolume(t)})),e}_createSeekControl(){const e=new _i("seek");return e.view.classList.add("red5pro-media-control-element"),e.view.classList.add("red5pro-media-seektime-slider"),e.view.classList.add("red5pro-media-slider"),e.on(si.CHANGE_START,(()=>{this.getState()===i.PLAYING&&(this._resumeAfterSeek=!0,this._player.pause(!0,!0)),this.trigger(new ve(ni.SEEK_START))})),e.on(si.CHANGE,(e=>{const t=Number(e.data);this._player.seekTo(t,0===this._playbackDuration?void 0:this._playbackDuration),this.setSeekTime(t*this._playbackDuration,this._playbackDuration)})),e.on(si.CHANGE_COMPLETE,(()=>{this._resumeAfterSeek&&this.getState()===i.PAUSED&&(this._resumeAfterSeek=!1,this._player.resume(!0)),this.trigger(new ve(ni.SEEK_END))})),e}_createPlaybackTime(){const e=gi("span"),t=gi("text");return t.textContent="00:00",e.classList.add("red5pro-media-control-element"),e.classList.add("red5pro-media-time-field"),e.appendChild(t),e}_createFullScreenToggle(){const e=gi("button");return e.setAttribute("aria-label","Toggle Fullscreen"),e.classList.add("red5pro-media-control-element"),e.classList.add("red5pro-media-element-button"),e.classList.add("red5pro-media-fullscreen-button"),e.addEventListener("click",(()=>{this._player.toggleFullScreen()})),e}_formatTime(e){const t=new Date(1e3*e);return`${String(t.getUTCHours()).padStart(2,"0")}:${String(t.getUTCMinutes()).padStart(2,"0")}:${String(t.getUTCSeconds()).padStart(2,"0")}`}onStateChange(e){var t,n,s,o;return e===i.PLAYING?(null===(t=this._playPauseButton)||void 0===t||t.classList.remove("red5pro-media-play-button"),null===(n=this._playPauseButton)||void 0===n||n.classList.add("red5pro-media-pause-button")):(null===(s=this._playPauseButton)||void 0===s||s.classList.add("red5pro-media-play-button"),null===(o=this._playPauseButton)||void 0===o||o.classList.remove("red5pro-media-pause-button")),this}onMutedStateChange(e){var t,i,n,s;return e?(null===(t=this._muteButton)||void 0===t||t.classList.add("red5pro-media-mute-button"),null===(i=this._muteButton)||void 0===i||i.classList.remove("red5pro-media-unmute-button"),this._volumeField&&(this._volumeField.value=0)):(null===(n=this._muteButton)||void 0===n||n.classList.remove("red5pro-media-mute-button"),null===(s=this._muteButton)||void 0===s||s.classList.add("red5pro-media-unmute-button"),this._volumeField&&(this._volumeField.value=this._volumeValue)),this}onFullScreenChange(e){var t,i,n,s;return e?(null===(t=this._fullScreenButton)||void 0===t||t.classList.add("red5pro-media-exit-fullscreen-button"),null===(i=this._fullScreenButton)||void 0===i||i.classList.remove("red5pro-media-fullscreen-button")):(null===(n=this._fullScreenButton)||void 0===n||n.classList.remove("red5pro-media-exit-fullscreen-button"),null===(s=this._fullScreenButton)||void 0===s||s.classList.add("red5pro-media-fullscreen-button")),this}enable(e){var t,i,n,s;return e?(null===(t=this._playPauseButton)||void 0===t||t.classList.remove("red5pro-media-element-button-disabled"),null===(i=this._playPauseButton)||void 0===i||i.addEventListener("click",this._onPlayPauseClickBound)):(null===(n=this._playPauseButton)||void 0===n||n.classList.add("red5pro-media-element-button-disabled"),null===(s=this._playPauseButton)||void 0===s||s.removeEventListener("click",this._onPlayPauseClickBound)),this}getVolume(){return this._volumeValue}setVolume(e){return this._volumeField&&(this._volumeField.value=e),this._volumeValue=e,0===e?this.setMutedState(!0):this.getMutedState()&&this.setMutedState(!1),this}setSeekTime(e,t=0){return this._seekTimeField&&(this._seekTimeField.value=0===t?0:e/t,0!==this._playbackDuration&&this._playbackDuration<=e&&(this._seekTimeField.value=1)),this._timeField&&(!isFinite(this._playbackDuration)&&vi()?this._timeField.innerText="Live Broadcast":this._timeField.innerText=this._formatTime(Math.floor(e))),this}setPlaybackDuration(e){return this._playbackDuration=e,this}getPlaybackDuration(){return this._playbackDuration}getState(){return this._state}setState(e){return Ei(`[setState]: ${s[e]}`),this._state=e,this.onStateChange(this._state),this}setMutedState(e){return this._mutedState=e,this.onMutedStateChange(this._mutedState),this}getMutedState(){return"muted"in this._player?this._player.muted:this._mutedState}setAsVOD(e){return Ei(`[setAsVOD]: ${e}`),this._seekTimeField&&(e?this._seekTimeField.disabled=!1:(this._seekTimeField.value=0,this._seekTimeField.disabled=!0)),this}detach(){this.enable(!1),this._controlbar&&this._controlbar.parentNode&&this._controlbar.parentNode.removeChild(this._controlbar),this._controlbar=void 0,this._container=void 0}}var Ci,bi;!function(e){e[e.LIVE=0]="LIVE",e[e.VOD=1]="VOD"}(Ci||(Ci={})),function(e){e.LIVE="LiveSeek.LIVE",e.VOD="LiveSeek.VOD"}(bi||(bi={}));const fi={[Ci.LIVE]:bi.LIVE,[Ci.VOD]:bi.VOD};var Ti;!function(e){e.LIVE_SEEK_UNSUPPORTED="WebRTC.LiveSeek.Unsupported",e.LIVE_SEEK_ERROR="WebRTC.LiveSeek.Error",e.LIVE_SEEK_ENABLED="WebRTC.LiveSeek.Enabled",e.LIVE_SEEK_DISABLED="WebRTC.LiveSeek.Disabled",e.LIVE_SEEK_LOADING="WebRTC.LiveSeek.FragmentLoading",e.LIVE_SEEK_LOADED="WebRTC.LiveSeek.FragmentLoaded",e.LIVE_SEEK_CHANGE="WebRTC.LiveSeek.Change"}(Ti||(Ti={}));const{createElement:yi,findByQuerySelector:wi,createHLSClient:Ai,getHLSClientEventEnum:Ni}=ie,Pi="SourceHandlerSeekable",Li=e=>O(Pi,e),Ri=e=>k(Pi,e),Ii=e=>H(Pi,e);class Di extends kt{constructor(e,t,i,n,s=!0){super(e,`${t}-Seekable`),this._hlsElementGenerated=!1,this._hlsRecoverFlop=!1,this._hlsRecoverAttempts=0,this._isFragLoading=!1,this._wallOffset=NaN,this._lastDurationUpdate=0,this._averageSegmentDuration=6,this._isSeekable=!1,this._isHLSPlaybackActive=!1,this._container=s?this._determineContainer(e):void 0,this._liveSeekConfig=i,this._hlsOptions=n,this._usePlaybackControls=s,this.onHLSDurationChange=this._onHLSDurationChange.bind(this),this.onHLSTimeUpdate=this._onHLSTimeUpdate.bind(this),this.onHLSPlay=this._onHLSPlay.bind(this),this.onHLSPause=this._onHLSPause.bind(this)}_determineContainer(e){if(e.parentNode&&e.parentNode.classList.contains("red5pro-media-container"))return e.classList.add("red5pro-media"),e.parentNode;{const t=e.parentNode,i=yi("div");return i.classList.add("red5pro-media-container"),e.classList.add("red5pro-media"),t.insertBefore(i,e),t.removeChild(e),i.appendChild(e),i}}_generateHLSLivePlayback(e,t,i){const n=`${i}-hls-vod`;let s=wi(`#${n}`);return s||(s=yi("video"),s.id=n,s.classList.add("red5pro-hls-vod"),s.classList.add("red5pro-media-background"),s.setAttribute("playsinline","playsinline"),s.style.width="100%",s.style.height="100%",s.style.display="none",e.insertBefore(s,t),this._hlsElementGenerated=!0),s}_onDurationChange(e){var t;Li("[videoelement:event] durationchange");const i=null!==(t=this._playbackNotificationCenter)&&void 0!==t?t:e.target,n=this.getControls();!this.isSeekable&&n&&n.setPlaybackDuration(i.duration)}_onTimeUpdate(e){var t;const i=null!==(t=this._playbackNotificationCenter)&&void 0!==t?t:e.target,n=this.getControls();if(this.isSeekable){if(!this._isHLSPlaybackActive){const e=this._hlsElement.duration,t=i.currentTime-this._lastDurationUpdate,s=isNaN(e)||0===e?i.currentTime:e+this._averageSegmentDuration+t;n&&n.setSeekTime(s,s),this.trigger(new Se(we.PLAYBACK_TIME_UPDATE,void 0,{time:s,duration:s,action:"rtc time update (1)"}))}}else super._onTimeUpdate(e)}_onEnded(){this.isHLSPlaybackActive||super._onEnded()}_onHLSDurationChange(e){const t=e.target,i=e.duration||t.duration;isNaN(this._wallOffset)&&(this._wallOffset=i-this._view.currentTime),this._lastDurationUpdate=this._view.currentTime;const n=i+this._averageSegmentDuration;Li(`[HLS:videoelement:duration] ${i}, ${this._averageSegmentDuration}`);const s=this.getControls();s&&s.setPlaybackDuration(n),this._isHLSPlaybackActive?this.trigger(new Se(we.PLAYBACK_TIME_UPDATE,void 0,{time:t.currentTime,duration:n,action:"hls time update"})):this.trigger(new Se(we.PLAYBACK_TIME_UPDATE,void 0,{time:n,duration:n,action:"hls time update"}))}_onHLSTimeUpdate(e){const t=e.target,i=this.getControls();i&&i.setSeekTime(t.currentTime,i.getPlaybackDuration()),t.currentTime>=t.duration?this._showHLSLivePlayback(!1,this._hlsElement,this._view,this._container):!isNaN(t.duration)&&this._isHLSPlaybackActive&&this.trigger(new Se(we.PLAYBACK_TIME_UPDATE,void 0,{time:t.currentTime,duration:t.duration+this._averageSegmentDuration,action:"hls time update"}))}_onHLSPlay(){Li("[HLS:videoelement:event] play");const e=this.getControls();e&&e.setState(i.PLAYING),this.trigger(new Se(we.PLAYBACK_STATE_CHANGE,void 0,{code:i.PLAYING,state:s[i.PLAYING]}))}_onHLSPause(){Li("[HLS:videoelement:event] pause");const e=this.getControls();e&&e.setState(i.PAUSED),this.trigger(new Se(we.PLAYBACK_STATE_CHANGE,void 0,{code:i.PAUSED,state:s[i.PAUSED]}))}_addSeekableHandlers(e,t,i){if(t){const i=Ni();t.on(i.ERROR,((i,n)=>{const{type:s,details:o,fatal:a,url:r}=n;if("networkerror"===s.toLowerCase()){if("levelemptyerror"===o.toLowerCase()){this.trigger(new Se(Ti.LIVE_SEEK_DISABLED,void 0,{hlsElement:e,hlsControl:t})),this.isSeekable=!1,t.destroy();const i=setTimeout((()=>{clearTimeout(i),this.enableLiveSeek(r,this._subscriptionId,this._hlsElement,!1)}),3e3);return}this.trigger(new Se(Ti.LIVE_SEEK_ERROR,void 0,{hlsElement:e,hlsControl:t,error:n}))}else this.trigger(new Se(Ti.LIVE_SEEK_ERROR,void 0,{hlsElement:e,hlsControl:t,error:n}));"mediaerror"===s.toLowerCase()&&(this._hlsRecoverFlop&&t.swapAudioCodec(),this._hlsRecoverFlop=!this._hlsRecoverFlop,this._hlsRecoverAttempts=this._hlsRecoverAttempts+1,t.recoverMediaError()),a&&"networkerror"===s.toLowerCase()&&t.startLoad()})),t.on(i.MANIFEST_PARSED,(()=>{try{e.pause()}catch(e){Li(`Could not pause seekable live stream: ${e.message}`)}this.isSeekable=!0,this.trigger(new Se(Ti.LIVE_SEEK_ENABLED,void 0,{hlsElement:e,hlsControl:t}))})),t.on(i.FRAG_LOADING,((i,n)=>{const{frag:{stats:{loaded:s,total:o}}}=n;this.trigger(new Se(Ti.LIVE_SEEK_LOADING,void 0,{hlsElement:e,hlsControl:t,progress:s/o*100})),(this._isHLSPlaybackActive||this._isFragLoading)&&(this._isFragLoading=s/o>=1)})),t.on(i.FRAG_LOADED,((i,n)=>{this._isFragLoading=!1;const{frag:{endDTS:s,loader:o}}=n;if(!this._isHLSPlaybackActive&&!s)return;let a=6,r=0;if(o&&o.stats&&o.stats.segments){const e=o.stats.segments;for(let t=0;t{this._isFragLoading=!1;const{frag:{endDTS:s,loader:o}}=n;if(!this._isHLSPlaybackActive&&!s)return;let a=6,r=0;if(o&&o.stats&&o.stats.segments){const e=o.stats.segments;for(let t=0;tn.test(e)));if(!a)return void Ii(`Could not find last segment in manifest: ${e}`);const r=o.find((e=>i.test(e)));if(!r)return void Ii(`Could not find duration line in manifest: ${e}`);const l=r.match(i);if(!l)return void Ii(`Could not find duration in manifest: ${e}`);const d=l[1],h=parseFloat(d),c=a.match(n);if(!c)return void Ii(`Could not find segment length in manifest: ${e}`);const u=c[1];let p=parseInt(u,10);isNaN(p)&&(p=1),p=p>1?p-1:p,this._averageSegmentDuration=h,this.isSeekable=!0,this.trigger(new Se(Ti.LIVE_SEEK_ENABLED,void 0,{hlsElement:this._hlsElement,hlsControl:void 0})),this.onHLSDurationChange({target:t,duration:h*p}),this._manifestLoadTimeout=setTimeout((()=>{clearTimeout(this._manifestLoadTimeout),this._loadManifest(e,t)}),1e3*h)}catch(e){Ri(`Could not load manifest: ${e.message}.`),this.trigger(new Se(Ti.LIVE_SEEK_DISABLED,void 0,{hlsElement:t,hlsControl:void 0})),this.isSeekable=!1}}_cleanup(){this._removeSeekableHandlers(this._hlsElement,this._hlsjsRef),this._hlsjsRef&&(this._hlsjsRef.detachMedia(),this._hlsjsRef=void 0),this._hlsElement&&(this._hlsElement.parentNode&&this._hlsElementGenerated&&this._hlsElement.parentNode.removeChild(this._hlsElement),this._hlsElement=void 0),this._playbackControls&&(this._playbackControls.detach(),this._playbackControls=void 0),this._isVOD=!1,this._isSeekable=!1,this._isHLSPlaybackActive=!1,this._isFragLoading=!1,this._hlsRecoverFlop=!1,this._hlsRecoverAttempts=0,this._averageSegmentDuration=6,this._hlsElementGenerated=!1,this._wallOffset=NaN,this._lastDurationUpdate=0,this._manifestLoadTimeout&&(clearTimeout(this._manifestLoadTimeout),this._manifestLoadTimeout=void 0),super._cleanup()}addSource(){Li("[addSource]"),this._view.controls=!0,this._view.classList.add("red5pro-media");this._view.hasAttribute("controls")&&this._view.classList.contains("red5pro-media")&&(this._container=this._determineContainer(this._view));const e=this._view.hasAttribute("muted");this._usePlaybackControls?(this._playbackControls=new Si(this,this._container),this._view.controls=!1,this._playbackControls.setAsVOD(this.isSeekable),this._playbackControls.setMutedState(e)):this._view.controls=!1}enableLiveSeek(e,t,i,n=!1){if(this.getControls()&&this.getControls().setSeekTime(1,1),this._url=e,this._subscriptionId=t,this._hlsElement=i||this._generateHLSLivePlayback(this._container,this._view,t),this._showHLSLivePlayback(this._isHLSPlaybackActive,this._hlsElement,this._view,this._container),n){this._addSeekableHandlers(this._hlsElement,void 0,!1);const t=yi("source");t.src=e,this._hlsElement.appendChild(t),this._loadManifest(e,this._hlsElement)}else{const t=this._hlsOptions,{liveSeek:{hlsjsRef:i}}=this._liveSeekConfig,n=i?new i(t):Ai(t);this._addSeekableHandlers(this._hlsElement,n,!0),n.attachMedia(this._hlsElement,e),n.on(Ni().MEDIA_ATTACHED,(()=>{n.loadSource(e)})),this._hlsjsRef=n}}switchLiveSeek(e){this._hlsjsRef&&(this._hlsjsRef.destroy(),this._hlsjsRef=void 0),this.enableLiveSeek(e,this._subscriptionId,this._hlsElement),this.seekTo(1);try{this._view.play()}catch(e){Ii("[videoelement:action] play (FAULT) - "+e.message)}this._url=e}async play(e=!1){Li("[videoelement:action] play");try{return e&&this._hlsElement&&this._hlsElement.paused?(await this._hlsElement.play(),!0):super.play()}catch(e){Ii("[videoelement:action] play (CATCH::FAULT) - "+e.message)}return!1}async pause(e=!1,t=!1){Li("[videoelement:action] pause");try{return e&&t&&this._hlsElement?(this._hlsElement.pause(),super.pause()):e&&this._hlsElement&&!this._hlsElement.paused?(this._hlsElement.pause(),!0):super.pause()}catch(e){Ii("[videoelement:action] pause (CATCH::FAULT) - "+e.message)}return!1}async resume(e=!1){var t,i;Li("[videoelement:action] resume");try{const n=this._isHLSPlaybackActive&&this._hlsElement?this._hlsElement.play():null===(t=this._view)||void 0===t?void 0:t.play();if(e&&this._isHLSPlaybackActive)return await(null===(i=this._view)||void 0===i?void 0:i.play()),!0;n&&n.then((()=>Li("[videoelement:action] play (START)"))).catch((e=>Ii("[videoelement:action] play (CATCH::FAULT) "+(e.message?e.message:e))))}catch(e){Ii("[videoelement:action] resume (CATCH::FAULT) - "+e.message)}return!1}async stop(){Li("[videoelement:action] stop");try{return this._hlsElement&&this._hlsElement.pause(),super.stop()}catch(e){Ii("[videoelement:action] stop (CATCH::FAULT) - "+e.message)}return!1}mute(){this._hlsElement&&(this._hlsElement.muted=this._isHLSPlaybackActive),this._view&&(this._view.muted=!0);const e=this.getControls();e&&e.setMutedState(!0)}unmute(){this._hlsElement&&(this._hlsElement.muted=!this._isHLSPlaybackActive,this._view&&(this._view.muted=this._isHLSPlaybackActive)),this._view&&(this._view.muted=!1);const e=this.getControls();e&&e.setMutedState(!1)}setVolume(e){this.unmute(),this._hlsElement&&this._isHLSPlaybackActive?this._hlsElement.volume=e:this._view?this._view.volume=e:Ri("[videoelement:action] setVolume (CATCH::FAULT) - "+e)}seekTo(e,t=void 0){if(this.isSeekable)if(this.getControls()&&this.getControls().setSeekTime(e,t),this.trigger(new Se(Ti.LIVE_SEEK_CHANGE,void 0,{seek:e,duration:t})),this._hlsElement&&e<1)try{this._hlsElement.classList.remove("hidden"),this._hlsElement.currentTime=this._hlsElement.duration*e,this._isFragLoading=!0,this._showHLSLivePlayback(!0,this._hlsElement,this._view,this._container),this._view.paused||(Li("[hlsvod:action] play (START) - (seekTo)"),this.play(!0))}catch(e){Ii("[hlsvod:action] play (CATCH::FAULT) - "+e.message)}else this._hlsElement&&e>=1&&(this._isFragLoading=!1,this._showHLSLivePlayback(!1,this._hlsElement,this._view,this._container));else this._view.currentTime=t?e*t:e}toggleFullScreen(e){var t;this._container&&super.toggleFullScreen(null!==(t=this._container)&&void 0!==t?t:e)}getControls(){return this._playbackControls}get isSeekable(){return this._isSeekable}set isSeekable(e){this._isSeekable=e,this.getControls()&&this.getControls().setAsVOD(e)}get isHLSPlaybackActive(){return this._isHLSPlaybackActive}get url(){return this._url}}const{supportsHLS:Oi,supportsNonNativeHLS:Hi}=ie,ki="WHEPLiveSeekClient",Mi=e=>k(ki,e);class Ui extends $t{constructor(e,t,i){super(e,t,i)}async init(e){const{liveSeek:t}=e;return t||(e.liveSeek=ei),super.init(e)}_attachSourceHandler(e){var t;if((null===(t=this._playbackView)||void 0===t?void 0:t.view)&&!this._enableLiveSeek(this._playbackView.view))return H(ki,"LiveSeek is not enabled, using default source handler"),void super._attachSourceHandler(e);this._startSeekableIfSeekableEnabled(this._options)}_enableLiveSeek(e){const{liveSeek:t}=this._options;if(t){const{hlsjsRef:i,usePlaybackControlsUI:n,options:s}=t;if(Oi()||Hi(i))return this._sourceHandler=new Di(e,this.getType(),this._options,s,n),this._sourceHandler.addSource(),!0;Mi("Could not utilize the 'LiveSeek' request. This feature requires either native HLS playback or hls.js as a depenency."),this.trigger(new Se(Ti.LIVE_SEEK_UNSUPPORTED,this,{feature:"Live Seek",message:"Live Seek requires integration with the HLS.JS plugin in order work properly. Most likely you are viewing this on a browser that does not support the use of HLS.JS."}))}return!1}_startSeekableIfSeekableEnabled(e){const{liveSeek:t,subscriptionId:i}=e;if(!t)return;const{hlsjsRef:n,hlsElement:s}=t;if(this._sourceHandler)try{if(!Oi()&&!Hi(n))throw new Error;{const t=ne(e);this._sourceHandler.enableLiveSeek(t,i,s,!Hi(n))}}catch(e){Mi("Could not utilize the 'LiveSeek' request. This feature requires either native HLS playback or hls.js as a depenency.")}}_onUnpublish(){super._onUnpublish();const{liveSeek:e}=this._options;e||this.unsubscribe(!0)}_onStreamSwitchComplete(){const e=this._requestedStreamSwitch,{liveSeek:t}=this._options;if(t&&e){const{baseURL:i,fullURL:n}=t,s=e.split("/"),o=s.pop(),a=s.join("/"),r={...this._options,app:a,streamName:o};let l=n;if(n){const e=/.*\/(.*)\.m3u8/.exec(n);if(e&&e.length>1){const t=`${e[1]}.m3u8`;l=n.replace(t,`${o}.m3u8`)}}const d=ne(r,i,l);this._sourceHandler&&this._sourceHandler.switchLiveSeek(d)}super._onStreamSwitchComplete()}}const Bi="15.3.0";R(L.ERROR);const Vi=(e,t=!1)=>{Object.prototype.hasOwnProperty.call(L,e.toUpperCase())&&(R(e,t),console&&console.log(`Red5 Pro SDK Version ${Fi()}`))},Fi=()=>Bi;O("RED5",`Red5 Pro HTML SDK Version: ${Bi}`);var $i={version:Bi,LOG_LEVELS:L,getLogger:I,getRecordedLogs:D,setLogLevel:Vi,getVersion:Fi,PlaybackVideoEncoder:t,PlaybackAudioEncoder:e,PlaybackState:i,PlaybackStateReadableMap:s,PublishVideoEncoder:l,PublishAudioEncoder:r,SubscriberEvent:Se,PublisherEvent:Ee,MessageTransportStateEvent:Ce,PubNubEvent:be,MessageChannelEvent:fe,PublisherEventTypes:Te,SubscriberEventTypes:we,RTCPublisherEventTypes:ye,RTCSubscriberEventTypes:Ae,MessageTransportStateEventTypes:Ne,MessageChannelEventTypes:Le,PubNubEventTypes:lt,WHIPClient:ft,WHEPClient:$t,HLSSubscriber:Zt,LiveSeekClient:Ui,PubNubClient:mt,MessageChannel:Jt,Capability:Gt,defaultWhepSubscriberConfig:Tt,defaultWhipPublisherConfig:ge,defaultStatsConfig:pe,StatsEndpointType:_e};export{Gt as Capability,ve as Event,U as EventEmitter,Zt as HLSSubscriber,L as LOG_LEVELS,Ui as LiveSeekClient,Jt as MessageChannel,fe as MessageChannelEvent,Le as MessageChannelEventTypes,Ce as MessageTransportStateEvent,Ne as MessageTransportStateEventTypes,e as PlaybackAudioEncoder,It as PlaybackController,ii as PlaybackControls,i as PlaybackState,s as PlaybackStateReadableMap,t as PlaybackVideoEncoder,mt as PubNubClient,be as PubNubEvent,r as PublishAudioEncoder,l as PublishVideoEncoder,Ee as PublisherEvent,Te as PublisherEventTypes,ye as RTCPublisherEventTypes,Ae as RTCSubscriberEventTypes,Dt as SourceHandler,kt as SourceHandlerImpl,_e as StatsEndpointType,Se as SubscriberEvent,we as SubscriberEventTypes,$t as WHEPClient,ft as WHIPClient,$i as default,yt as defaultHLSSubscriberConfig,ti as defaultLiveSeekConfig,pe as defaultStatsConfig,Tt as defaultWhepSubscriberConfig,ge as defaultWhipPublisherConfig,I as getLogger,D as getRecordedLogs,Fi as getVersion,Vi as setLogLevel};
diff --git a/static/lib/red5pro/red5pro-sdk.min.js b/static/lib/red5pro/red5pro-sdk.min.js
index 6c6bff11..bba312ea 100644
--- a/static/lib/red5pro/red5pro-sdk.min.js
+++ b/static/lib/red5pro/red5pro-sdk.min.js
@@ -2,7 +2,7 @@
*
* red5pro-html-sdk - Red5 Pro HTML SDK
* Author: Infrared5 Inc.
- * Version: 15.2.0
+ * Version: 15.3.0
* Url: https://www.red5.net
*
* Copyright © 2015 Infrared5, Inc. All rights reserved.
@@ -31,4 +31,4 @@
*
*/
-!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).red5prosdk={})}(this,(function(e){"use strict";var t,i,n,s;e.PlaybackAudioEncoder=void 0,(t=e.PlaybackAudioEncoder||(e.PlaybackAudioEncoder={})).OPUS="OPUS",t.NONE="NONE",e.PlaybackVideoEncoder=void 0,(i=e.PlaybackVideoEncoder||(e.PlaybackVideoEncoder={})).VP8="VP8",i.H264="H264",i.H265="H265",i.NONE="NONE",e.PlaybackState=void 0,(n=e.PlaybackState||(e.PlaybackState={}))[n.UNAVAILABLE=1e3]="UNAVAILABLE",n[n.AVAILABLE=0]="AVAILABLE",n[n.IDLE=1]="IDLE",n[n.PLAYING=2]="PLAYING",n[n.PAUSED=3]="PAUSED",function(e){e.UNAVAILABLE="Playback.UNAVAILABLE",e.AVAILABLE="Playback.AVAILABLE",e.IDLE="Playback.IDLE",e.PLAYING="Playback.PLAYING",e.PAUSED="Playback.PAUSED"}(s||(s={}));const o={[e.PlaybackState.UNAVAILABLE]:s.UNAVAILABLE,[e.PlaybackState.AVAILABLE]:s.AVAILABLE,[e.PlaybackState.IDLE]:s.IDLE,[e.PlaybackState.PLAYING]:s.PLAYING,[e.PlaybackState.PAUSED]:s.PAUSED};var r,a,l;!function(e){e.RTMP="rtmp",e.RTC="rtc"}(r||(r={})),function(e){e.LIVE="live",e.RECORD="record",e.APPEND="append"}(a||(a={})),e.PublishAudioEncoder=void 0,(e.PublishAudioEncoder||(e.PublishAudioEncoder={})).OPUS="OPUS",e.PublishVideoEncoder=void 0,(l=e.PublishVideoEncoder||(e.PublishVideoEncoder={})).VP8="VP8",l.H264="H264",l.H265="H265";var d={trace:10,debug:20,info:30,warn:40,error:50,fatal:60},h={};function c(e){return"string"==typeof e?d[e.toLowerCase()]:e}function u(e,t){return u=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e},u(e,t)}function p(e,t,i){return p=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){}))),!0}catch(e){return!1}}()?Reflect.construct:function(e,t,i){var n=[null];n.push.apply(n,t);var s=new(Function.bind.apply(e,n));return i&&u(s,i.prototype),s},p.apply(null,arguments)}function _(e){if(null==e)return e;if(Array.isArray(e))return e.slice();if("object"==typeof e){var t={};return Object.keys(e).forEach((function(i){t[i]=e[i]})),t}return e}function g(e){return void 0===e?"undefined":null===e?"null":Array.isArray(e)?"[ "+e.map((function(e){return g(e)})).join(", ")+" ]":"object"==typeof e?JSON.stringify(e):"function"==typeof e?"[Function: "+e.name+"]":"boolean"==typeof e||"number"==typeof e?e:"'"+e.toString()+"'"}function v(e){if("string"!=typeof e){for(var t=new Array(arguments.length),i=0;i=o)return e;switch(e){case"%s":return String(s[n++]);case"%d":return Number(s[n++]);case"%j":try{return JSON.stringify(s[n++])}catch(e){return"[Circular]"}default:return e}})),a=s[n];ne||(s=function(s){var o;s[0]instanceof Error?(i={err:t.serializers&&t.serializers.err?t.serializers.err(s[0]):y.err(s[0])},o={err:!0},n=1===s.length?[i.err.message]:Array.prototype.slice.call(s,1)):"object"!=typeof s[0]&&null!==s[0]||Array.isArray(s[0])?(i=null,n=Array.prototype.slice.call(s)):(i=s[0],n=1===s.length&&i.err&&i.err instanceof Error?[i.err.message]:Array.prototype.slice.call(s,1));var r=_(t.fields);r.level=e;var a=i?_(i):null;if(a&&(t.serializers&&t._applySerializers(a,o),Object.keys(a).forEach((function(e){r[e]=a[e]}))),r.levelName=h[e],r.msg=n.length?v.apply(t,n):"",r.time||(r.time=new Date),t.src&&!r.src)try{throw new Error("call-stack-error")}catch(e){var l=e.stack?function(e,t){var i=e.split("\n");i[0]&&i[0].indexOf("call-stack-error")>=0&&i.shift();var n=i[t],s=null;if(n){var o=/^\s*(at|.*@)\s*(.+)?$/.exec(n);s=Array.isArray(o)&&o[2]?o[2]:n}return s}(e.stack,2):"";l||function(e){return m[e]}("src")||E("Unable to determine src line info","src"),r.src=l||""}return r.v=1,r}(n),this._emit(s))}}function T(e){var t=e.stack||e.toString();if(e.cause&&"function"==typeof e.cause){var i=e.cause();i&&(t+="\nCaused by: "+T(i))}return t}S.prototype.trace=C(10),S.prototype.debug=C(20),S.prototype.info=C(30),S.prototype.warn=C(40),S.prototype.error=C(50),S.prototype.fatal=C(60);var y={err:function(e){return e&&e.stack?{message:e.message,name:e.name,stack:T(e),code:e.code,signal:e.signal}:e}};const f={10:"TRACE",20:"DEBUG",30:"INFO",40:"WARN",50:"ERROR",60:"FATAL"};class w{write(e){console.log("%s - [%s] %s: %s",e.time.toISOString(),e.name,f[e.level]||"UNKNOWN",e.msg)}}let A,P;const N=e=>(t,i)=>{var n;A&&"function"==typeof A[e]&&A[e]((n=t,e=>`(${n}) ${e}`)(i))},L={TRACE:"trace",INFO:"info",DEBUG:"debug",WARN:"warn",ERROR:"error",FATAL:"fatal"},R=(e,t=!1,i)=>{const n=[{level:e,stream:new w,type:"raw"}];if(i){const t=i.map((t=>({...t,level:e})));n.push(...t)}t&&(P=[],n.push({level:e,stream:{write:t=>{const i=`[${t.time.toISOString()}] ${e.toUpperCase()}: ${t.msg}`;null==P||P.push(i)}},type:"raw"}));A=function(){return p(S,[].slice.call(arguments))}({level:e,name:"red5pro-sdk",streams:n})},I=()=>(A||R(L.INFO),A),D=()=>P||[];N(L.TRACE),N(L.INFO);const O=N(L.DEBUG),k=N(L.WARN),H=N(L.ERROR);N(L.FATAL);const M="RED5PRO";class U{constructor(){this._callbacks={},this._callbacks[M]=[]}_notify(e,t){let i;const n=e.length;for(i=0;i1&&(s=V.exec(e),n[1]===t&&s&&s.length>1)?s[1]:void 0}}function x(e){const t=G(e,"orientation");if(t)return{orientation:parseInt(t)}}function W(e){const t=G(e,"streamingMode");if(t)return{streamingMode:t}}const K=e=>F.get(e),j=e=>{const t=e.textTracks;t&&(e.addTextTrack("metadata"),t.addEventListener("addtrack",(t=>{const i=t.track;i.mode="hidden",i.addEventListener("cuechange",(t=>{let n,s;for(t&&t.currentTarget?n=t.currentTarget.cues:(n=i.cues,n=n&&n.length>0?n:i.activeCues),n=n||[],s=0;s{e(n)})),s&&o&&o.streamingMode&&o.streamingMode.forEach((e=>{e(s)}))}}}))})))},z="BrowserEnvironment",J=e=>O(z,e),Y=e=>k(z,e);let q=[];const X=()=>{const e=screen.orientation?screen.orientation.angle:void 0,t=void 0===e?window.matchMedia("(orientation: portrait)").matches?0:90:e,i=q.length;J(`[window:onorientationchange]: orientation(${t}).`);for(let e=0;e{const e=document.createElement("video");return e.canPlayType("application/vnd.apple.mpegURL").length>0||e.canPlayType("application/x-mpegURL").length>0||e.canPlayType("audio/mpegurl").length>0||e.canPlayType("audio/x-mpegurl").length>0},te="undefined"!=typeof window&&window.adapter;var ie={gUM:async e=>navigator.mediaDevices.getUserMedia(e),createElement:e=>document.createElement(e),resolveElement:e=>document.getElementById(e),getElementId:e=>e.id,setVideoSource:(e,t,i)=>{if(e.srcObject=t,i)try{const t=e.play();t&&t.then((()=>J("[setVideoSource:action]: play (START)"))).catch((t=>{Y(`[setVideoSource:action]: play (CATCH::FAULT) ${t.message}`);try{e.setAttribute("autoplay","false"),e.pause()}catch(e){Y(`[setVideoSource:action]: pause (CATCH::FAULT) ${e.message}`)}}))}catch(e){Y(`[setVideoSource:action]: play (CATCH::FAULT) ${e.message}`)}},hasAttributeDefined:(e,t)=>e.hasAttribute(t),addOrientationChangeHandler:(e,t=!0)=>{"onorientationchange"in window&&(J("[window:orientation:addOrientationChangeHandler]: add"),q.push(e),t&&X()),1===q.length&&(J("[window:orientation:addOrientationChangeHandler]: add"),window.addEventListener("orientationchange",X))},removeOrientationChangeHandler:e=>{q=q.filter((t=>t!==e)),0===q.length&&window.removeEventListener("orientationchange",X)},toggleFullScreen:e=>{window.screenfull&&window.screenfull.enabled?window.screenfull.toggle(e):document.fullscreenEnabled&&(document.fullscreenElement&&document.fullscreenElement===e?document.exitFullscreen():e.requestFullscreen())},onFullScreenStateChange:e=>{var t;Z.push(e),t=window.screenfull,Q||(Q=!0,window.screenfull?window.screenfull.on("change",(()=>{Z.forEach((e=>e(t.isFullscreen)))})):document.fullscreenEnabled&&document.addEventListener("fullscreenchange",(()=>{Z.forEach((e=>e(null!==document.fullscreenElement)))})))},getOrGenerateFingerprint:()=>{const e=window.localStorage;if(e&&e.getItem("red5_fingerprint"))return e.getItem("red5_fingerprint");let t;try{t=window.crypto.randomUUID()}catch(e){t="10000000-1000-4000-8000-100000000000".replace(/[018]/g,(e=>(Number(e)^crypto.getRandomValues(new Uint8Array(1))[0]&15>>Number(e)/4).toString(16)))}return e.setItem("red5_fingerprint",t),t},getBrowserDetails:()=>{const e=void 0!==window.adapter,{navigator:t,adapter:i}=window,{appVersion:n,platform:s,userAgent:o,vendor:r}=t,a={appVersion:n,platform:s,userAgent:o,vendor:r};return e?{...i.browserDetails,...a}:a},supportsHLS:ee,onOrientationMetadata:(e,t)=>{const i=F.get(e);F.has(e)?Object.prototype.hasOwnProperty.call(i,"orientation")||(F.get(e).orientation=[]):(j(e),F.set(e,{orientation:[]})),F.get(e).orientation.push(t)},onStreamingModeMetadata:(e,t)=>{const i=F.get(e);F.has(e)?Object.prototype.hasOwnProperty.call(i,"streamingMode")||(F.get(e).streamingMode=[]):(j(e),F.set(e,{streamingMode:[]})),F.get(e).streamingMode.push(t)},isTouchEnabled:()=>"ontouchstart"in window,isPossiblySafari:()=>te?"safari"===window.adapter.browserDetails.browser.toLowerCase():ee(),findByQuerySelector:e=>document.querySelector(e),addGlobalEventListener:(e,t,i=document)=>{i.addEventListener(e,t)},removeGlobalEventListener:(e,t,i=document)=>{i.removeEventListener(e,t)},supportsNonNativeHLS:e=>{if(e)try{return e.isSupported()}catch(e){return Y("Could not access Hls.js."),!1}return!!window.Hls&&window.Hls.isSupported()},createHLSClient:(e={})=>new window.Hls(e),getHLSClientEventEnum:()=>window.Hls.Events,globalAssign:(e,t)=>{window[e]=t},globalUnassign:e=>{delete window[e]},getAssignedValue:e=>window[e]};const ne=(e,t,i)=>{const{liveSeek:{baseURL:n,fullURL:s}}=e,{host:o,protocol:r,port:a,app:l,streamName:d}=e;if(i||s)return i||s;const h=o,c="ws"===r?"http":"https",u=5080===a?5080:443,p=l,_=t||n;if(_){const e=_.length-1;return`${"/"===_.charAt(e)?_.substring(0,e):_}/${p}/${d}.m3u8`}return`${c}://${h}:${u}/${p}/${d}.m3u8`},se=e=>{const t=new URL(e),i=t.pathname.split("/").filter((e=>e.length>0)),n="https:"===t.protocol?"https":"http",s=t.hostname;return{protocol:n,port:t.port.length>0?t.port:443,app:i[0],host:s,streamName:i[i.length-1]}},oe=(e,t="whip")=>{var i;const{endpoint:n,proxy:s}=e;if(n)return n;{const{protocol:n,host:o,port:r,app:a,streamName:l}=e,d=n.match(/^http/)?n:"ws"===n?"http":"https";return(null==s?void 0:s.enabled)?`${d}://${o}:${r}/as/${null!==(i=s.version)&&void 0!==i?i:"v1"}/proxy/${t}/${a}/${l}`:`${d}://${o}:${r}/${a}/${t}/endpoint/${l}`}},re=e=>{const t={audio:!1,video:!1},i={audio:!1,video:!1};return e.getTracks().forEach((e=>{"video"===e.kind?(i.video=e.getSettings(),t.video=e.getConstraints()):"audio"===e.kind&&(i.audio=e.getSettings(),t.audio=e.getConstraints())})),{requested:t,accepted:i}},ae=e=>{const t=e.length;return function i(...n){return n.length>=t?e(...n):function(...e){return i(...n,...e)}}},le=ae(((e,t)=>{let i=0;const n=t.length,s=[];for(;i{this._responder.onDataChannelError(t,e.error.message)},t.onmessage=e=>{this._onDataChannelMessage(e)},t.onopen=()=>{this._responder.onDataChannelOpen(t)},t.onclose=i=>{this._responder.onDataChannelClose(t),this.trigger(new Se(e.MessageTransportStateEventTypes.CLOSE,this._name,{socket:this,event:i}))}}_isErrorMessage(e){return!("error"!==(null==e?void 0:e.type)||!(null==e?void 0:e.message)&&!(null==e?void 0:e.code))}_isStatusMessage(e){return!("status"!==(null==e?void 0:e.type))}_onDataChannelMessage(e){if(this.handleMessageResponse(e))return!0;const t=this.getJsonFromSocketMessage(e);return t?(O(this._name,`[datachannel-response]: ${JSON.stringify(t,null,2)}`),this._handleMessageContent(t)):(k(this._name,"Determined websocket response not in correct format. Aborting message handle."),!0)}_handleMessageContent(e){const{async:t,data:i,method:n,send:s,type:o,id:r}=e;if(this._isErrorMessage(i)){const e=(null==i?void 0:i.message)||(null==i?void 0:i.code);if(e)return this._responder.onDataChannelError(this._dataChannel,e),!0}if(n)return this._responder.onSendReceived(n,i),!0;if(s){const{senderName:t,dcLabel:i}=e,{data:n,method:o}=s,r={...n,senderName:t,dcLabel:i};return this._responder.onSendReceived(o,r),!0}return"metadata"===o&&i?(this._responder.onMetaData(i),!0):this._isStatusMessage(i)&&"NetConnection.Connect.Closed"===(null==i?void 0:i.code)?(this._responder.onConnectionClosed(),!0):!(!t||!r)&&this._handleAsyncResponse(r,e)}_handleAsyncResponse(e,t){const i=this._asyncTickets.find((t=>t.id===e));if(!i)return!1;const{promise:n}=i,{data:s}=t;if("error"===(null==s?void 0:s.type)){const e=s.message||s.code||"Unknown error";n.reject(new Error(e))}else n.resolve(s);return this._asyncTickets=this._asyncTickets.filter((t=>t.id!==e)),!0}async setUpWithPeerConfiguration(e,t){this.tearDown();(null==e?void 0:e.iceServers)&&e.iceServers.length>0||(e.iceServers=Ne);try{O(this._name,`[peerconnection:setUpWithPeerConfiguration]: ${JSON.stringify(e,null,2)}`);const i=new RTCPeerConnection(e);return t&&(this._dataChannel=i.createDataChannel(t.name,{ordered:!0}),this._addDataChannelHandlers(this._dataChannel)),this._addConnectionHandlers(i),this._peerConnection=i,i}catch(e){throw k(this._name,`Could not establish a PeerConnection. ${e.message}`),new Error(e.message)}}tearDown(){if(this._dataChannel){O(this._name,"[teardown:datachannel]"),this._removeDataChannelHandlers(this._dataChannel);try{this._dataChannel.close()}catch(e){k(this._name,`[datachannel.close] error: ${e.message}`)}finally{this._dataChannel=void 0}}if(this._peerConnection){O(this._name,"[teardown:peerconnection]"),this._removeConnectionHandlers(this._peerConnection);try{this._peerConnection.close()}catch(e){k(this._name,`[peerconnection.close] error: ${e.message}`)}finally{this._peerConnection=void 0}}}async setLocalDescription(e){var t;return O(this._name,"[setlocaldescription]"),null===(t=this._peerConnection)||void 0===t?void 0:t.setLocalDescription(e)}async setRemoteDescription(e){var t;return O(this._name,"[setremotedescription]"),null===(t=this._peerConnection)||void 0===t?void 0:t.setRemoteDescription(new RTCSessionDescription(e))}async addIceCandidate(e){var t;return O(this._name,"[addcandidate]"),null===(t=this._peerConnection)||void 0===t?void 0:t.addIceCandidate(e)}async waitToGatherIce(e=5e3){const t=this._peerConnection;return O(this._name,"[waittogatherice]"),new Promise((i=>{if("complete"===t.iceGatheringState)O(this._name,"[waittogatherice] ice gathering state complete."),t.addIceCandidate(null).then((()=>{i(t.localDescription)})).catch((e=>{k(this._name,"Error adding null candidate: "+e.message||e),i(t.localDescription)}));else{O(this._name,"[waittogatherice] waiting...");const n=setTimeout((()=>{clearTimeout(n),t.addIceCandidate(null).then((()=>{i(t.localDescription)})).catch((e=>{k(this._name,"Error adding null candidate: "+e.message||e),i(t.localDescription)}))}),e);t.onicegatheringstatechange=()=>{clearTimeout(n),O(this._name,"[waittogatherice] ice gathering state complete."),"complete"===t.iceGatheringState&&t.addIceCandidate(null).then((()=>{i(t.localDescription)})).catch((e=>{k(this._name,"Error adding null candidate: "+e.message||e),i(t.localDescription)}))}}}))}post(e){if(this._dataChannel){const t="string"==typeof e?e:JSON.stringify(e,null,2);O(this._name,`[datachannel.send] message: ${t}`);try{return this._dataChannel.send(t),Promise.resolve(!0)}catch(e){H(this._name,e.message)}}return Promise.resolve(!1)}get connection(){return this._peerConnection}get dataChannel(){return this._dataChannel}}const Re=[{label:"4K(UHD)",width:3840,height:2160},{label:"1080p(FHD)",width:1920,height:1080},{label:"UXGA",width:1600,height:1200},{label:"720p(HD)",width:1280,height:720},{label:"SVGA",width:800,height:600},{label:"VGA",width:640,height:480},{label:"360p(nHD)",width:640,height:360},{label:"CIF",width:352,height:288},{label:"QVGA",width:320,height:240},{label:"QCIF",width:176,height:144},{label:"QQVGA",width:160,height:120}],Ie=e=>"number"==typeof e?e:e.exact||e.ideal||e.max||e.min||e,De=ae(((e,t)=>{var i,n;if("boolean"==typeof e.video)return!0;const s=(null===(i=e.video)||void 0===i?void 0:i.width)?Ie(e.video.width):0,o=(null===(n=e.video)||void 0===n?void 0:n.height)?Ie(e.video.height):0,r=s===t.width&&o===t.height;return r&&O("[gum:isExact]",`Found matching resolution for ${t.width}, ${t.height}.`),r})),Oe=ae(((e,t)=>{const i=le(De(t))(e);return O("[gum:hasMatchingFormat]","Filtered list: "+JSON.stringify(i,null,2)),i.length>0})),ke=ae(((e,t)=>{var i,n;if("boolean"==typeof e.video)return!0;const s=((null===(i=e.video)||void 0===i?void 0:i.width)?Ie(e.video.width):0)*((null===(n=e.video)||void 0===n?void 0:n.height)?Ie(e.video.height):0);return t.width*t.height{const i=ke(t);return le(i)(e)})),Me=async e=>{O("[gum:determineSupportedResolution]","Determine next neighbor based on constraints: "+JSON.stringify(e,null,2));const t=He(Re)(e),i={...e};return await(async(e,t)=>{let i={...e};if(0==t.length)i.video;else{const n=t.shift();i={...e,video:{...e.video,width:{exact:n.width},height:{exact:n.height}}}}return{media:await ie.gUM(i),constraints:i}})(i,t)},Ue=async e=>{let t;const i=Oe(Re),n=async t=>{if(t){const e="string"==typeof t?t:[t.name,t.message].join(": ");O("[gum:getUserMedia]",`Failure in getUserMedia: ${e}. Attempting other resolution tests...`)}return await Me(e)};if((e=>e.video&&"object"==typeof e.video&&(e.video.width||e.video.height))(e)){if(!i(e))return await n(void 0);{O("[gum:getUserMedia]","Found constraints in list. Checking quick support for faster setup with: "+JSON.stringify(e,null,2));const i=(e=>{var t,i;const n={...e};return"boolean"==typeof e.video||(n.video={...n.video},(null===(t=e.video)||void 0===t?void 0:t.width)&&(n.video.width={exact:Ie(e.video.width)}),(null===(i=e.video)||void 0===i?void 0:i.height)&&(n.video.height={exact:Ie(e.video.height)})),n})(e);try{return t=await ie.gUM(i),{media:t,constraints:i}}catch(e){return await n(e)}}}else try{return t=await ie.gUM(e),{media:t,constraints:e}}catch(e){return await n(e)}},Be=(e,t,i)=>{const n="a=end-of-candidates",s=/^a=candidate:/,o=/^a=ice-ufrag:/,r=/^a=ice-pwd:/,a=/^m=(audio|video|application)\ /,l=e.split("\r\n");let d,h="",c="";const u=[];l.forEach((e=>{!d&&a.exec(e)?d=e:o.exec(e)?h=e:r.exec(e)?c=e:s.exec(e)&&(t&&-1!=e.indexOf(t)?u.push(e):t||u.push(e))})),i&&u[u.length-1]!==n&&u.push(n);return[h,c,d,"a=mid:0"].concat(u).join("\r\n")},Ve="RTCPeerConnectionPublisher";class Fe extends Le{constructor(e){super(e,Ve)}_removeConnectionHandlers(e){e.onconnectionstatechange=null,e.oniceconnectionstatechange=null,e.onsignalingstatechange=null,e.onicecandidate=null,e.ontrack=null}_addConnectionHandlers(e){let t;e.onsignalingstatechange=()=>{const t=e.signalingState;O(Ve,`[peer.onsignalingstatechange] - State: ${t}`)},e.onconnectionstatechange=()=>{const{connectionState:t}=e;"connected"===t?(O(this._name,"[peerconnection:open]"),this._responder.onPeerConnectionOpen()):"failed"!==t&&"disconnected"!==t||(k(this._name,"[peerconnection:error]"),"failed"===t&&this._responder.onPeerConnectionFail())},e.oniceconnectionstatechange=i=>{const{iceConnectionState:n}=e;O(this._name,`[peer.oniceconnectionstatechange] - State: ${n}`),"failed"===n?(t&&clearTimeout(t),this._responder.onPeerConnectionClose(i)):"disconnected"===n?t=setTimeout((()=>{O(this._name,"[peer.oniceconnectionstatechange] - Reconnect timeout reached. Closing PeerConnection."),clearTimeout(t),this._responder.onPeerConnectionClose(i)}),3e3):t&&(O(this._name,"[peer.oniceconnectionstatechange] - Clearing timeout for reconnect."),clearTimeout(t))},e.onicecandidate=e=>{const{candidate:t}=e;O(this._name,`[peer.onicecandidate] - Peer Candidate: ${null==t?void 0:t.candidate}`),t&&this._responder.onIceCandidate(t)},e.ontrack=e=>{O(this._name,"[peer:ontrack]"),this._responder.onPeerConnectionTrackAdd(e.track)}}_onDataChannelMessage(e){const t=e;if(super._onDataChannelMessage(e))return!0;const i=this.getJsonFromSocketMessage(t);if(null===i)return k(this._name,"Determined websocket response not in correct format. Aborting message handle."),!0;O(this._name,"[datachannel-response]: "+JSON.stringify(i,null,2));const{data:n}=i;return n&&"status"===n.type?"NetStream.Play.UnpublishNotify"===n.code?(this._responder.onUnpublish(),!0):"NetConnection.Publish.InsufficientBW"===n.code?(this._responder.onInsufficientBandwidth(n),!0):"NetConnection.Publish.SufficientBW"===n.code?(this._responder.onSufficientBandwidth(n),!0):"NetConnection.Publish.RecoveringBW"===n.code?(this._responder.onRecoveringBandwidth(n),!0):"Application.Statistics.Endpoint"===n.code?(this._responder.onStatisticsEndpointChange(n.statistics),!0):(O(Ve,`[datachannel.message] status :: ${n.code}`),this._responder.onPublisherStatus(n),!0):(this._responder.onDataChannelMessage(this._dataChannel,t),!1)}addTrack(e){this._peerConnection?this._peerConnection.addTrack(e):k(Ve,"PeerConnection not initialized. Cannot add track.")}async postUnpublish(e){const t=this.post({unpublish:e});return O(Ve,`[peerconnection:unpublish] complete: ${t}`),t}async createOfferWithoutSetLocal(e=null){var t;O(Ve,`[createoffer:withoutlocal]:: bandwidth request: ${JSON.stringify(e,null,2)}`);try{const i=await(null===(t=this._peerConnection)||void 0===t?void 0:t.createOffer());if(e){const t=((e,t)=>{const i=t.indexOf("m=audio");let n,s,o,r=t.indexOf("m=video"),a=t.indexOf("m=application");return i>-1&&e.audio&&(n=t.indexOf("\r\n",i),s=t.slice(0,n),o=t.slice(n+2,t.length),r=(t=[s,"b=AS:"+e.audio,o].join("\r\n")).indexOf("m=video"),a=t.indexOf("m=application")),r>-1&&e.video&&(n=t.indexOf("\r\n",r),s=t.slice(0,n),o=t.slice(n+2,t.length),a=(t=[s,"b=AS:"+e.video,o].join("\r\n")).indexOf("m=application")),a>-1&&e.dataChannel&&(n=t.indexOf("\r\n",a),s=t.slice(0,n),o=t.slice(n+2,t.length),t=[s,"b=AS:"+e.dataChannel,o].join("\r\n")),t})(e,i.sdp);i.sdp=t}return this._responder.onSDPSuccess(),i}catch(e){throw O(Ve,"[createoffer:error]"),this._responder.onSDPError(e),e}}async updateBandwidthRequest(e=null){var t;O(Ve,`[updatebandwidthrequest]:: bandwidth request: ${JSON.stringify(e,null,2)}`);try{const i=null===(t=this._peerConnection)||void 0===t?void 0:t.getSenders();if(e&&(null==i?void 0:i.length)&&i.length>0){const t=(e,t,i)=>new Promise(((n,s)=>{try{O(Ve,`[updatebandwidthrequest:${i}]:: bandwidth(${t.encodings[0].maxBitrate})`),e.setParameters(t).then(n).catch(s)}catch(e){s(e)}})),n=[];null==i||i.forEach((async i=>{var s,o;if("video"===(null===(s=i.track)||void 0===s?void 0:s.kind)&&e.video){const e=i.getParameters();e.encodings||(e.encodings=[{}]),e.encodings[0].maxBitrate=75e4,e.encodings[0].maxFramerate=60,e.encodings[0].priority="high",n.push(t(i,e,"video"))}else if("audio"===(null===(o=i.track)||void 0===o?void 0:o.kind)&&e.audio){const e=i.getParameters();e.encodings||(e.encodings=[{}]),e.encodings[0].maxBitrate=128e3,n.push(t(i,e,"audio"))}})),await Promise.all(n).catch((e=>{H(Ve,`[updatebandwidthrequest:error]:: ${e.message}`)}))}return!0}catch(e){H(Ve,`[updatebandwidthrequest:error]:: ${e.message}`)}return!1}}class $e extends Error{constructor(e){super(e),this.name="InvalidNameError"}}const Ge="WhipWhepSignalingHelper",xe=new Map;xe.set(400,"Invalid offer SDP."),xe.set(401,"Not authorized."),xe.set(404,"Scope resolver failed for the publish name and / or scope."),xe.set(405,"Remember to update the URL passed into the WHIP or WHEP client."),xe.set(406,"Scope connection rejected."),xe.set(409,"Session already initialized."),xe.set(412,"Invalid request body."),xe.set(417,"Session lookup or creation failure.");const We=new Map;We.set(400,"Offer already sent, double POST assumed."),We.set(401,"Not authorized."),We.set(404,"Scope resolver failed for the playback name and / or scope."),We.set(406,"Playback failed due to an exception during creation."),We.set(409,"Stream is not available to playback.");const Ke=["transcode"];var je;!function(e){e.ICE_SERVER="ice-server",e.STATISTICS="statistics"}(je||(je={}));const ze=e=>e&&(e=>{const t=/[?&](.*)=([^]*)/.exec(e);return t&&t.length>0})(e)?"&":"?",Je=e=>e.split(";").map((e=>e.trim())).map((e=>"<"===e.charAt(0)?["url",e.substring(1,e.length-1)]:e.split("="))).reduce(((e,t)=>e.set(t[0].replaceAll('"',""),t[1].replaceAll('"',""))),new Map);class Ye{constructor(e,t=!1,i=!0){O(Ge,`[whipwhep] ${e}`),this._url=e,this._origin=void 0,this._forceHost=i,this._resource=void 0,this._enableSignalingChannel=t}async getOptions(e={}){let t=`${this._url}${ze(this._url)}signal=${this._enableSignalingChannel}`;e&&Object.keys(e).forEach((i=>{t+=`&${i}=${e[i]}`})),O(Ge,`[whipwhep-options] ${t}`);try{const e=await fetch(t,{method:"OPTIONS",mode:"cors"}),{status:i,headers:n}=e;if(200===i||204===i){const e=/^(L|l)ink/,t=/^(S|s)ession-(H|h)ost/,i=[];let s;return n.forEach(((n,o)=>{if(t.exec(o)&&(this._origin=n),e.exec(o))if(n.indexOf(`rel="${je.ICE_SERVER}"`)>-1){const e=Je(n),t=e.get("url"),{protocol:s,host:o}=(e=>{const t=e.split(":");return t.length>1?{protocol:t[0],host:t[1]}:{protocol:void 0,host:e}})(t),r=e.get("username"),a=e.get("credential");s&&o&&r&&a?i.push({username:r,credential:a,urls:t}):t&&i.push({urls:t})}else if(n.indexOf(`rel="${je.STATISTICS}"`)>-1){const e=Je(n).get("url");e&&(s=e)}})),O(Ge,`[whipwhep-links]: ${JSON.stringify(i)}`),O(Ge,`[whipwhep-origin]: ${this._origin}`),{links:i.length>0?i:void 0,origin:this._origin,statisticsEndpoint:s}}throw new Error(`Failed to get options: ${i}`)}catch(e){throw H(Ge,e.message),e}}async postSDPOffer(e,t={},i=!0){let n=`${this._url}${ze(this._url)}signal=${this._enableSignalingChannel}`;t&&Object.keys(t).forEach((e=>{-1===Ke.indexOf(e)&&(n+=`&${e}=${t[e]}`)})),this._forceHost&&this._origin&&!(null==t?void 0:t.host)&&(n+=`&host=${this._origin}`),O(Ge,`[whipwhep:post-offer] ${n}: `+JSON.stringify(e,null,2));try{const t={method:"POST",mode:"cors",headers:{"Content-Type":"application/sdp"}};e&&e.length>0&&(t.body=e);const s=await fetch(n,t),{status:o,headers:r}=s;if(r&&r.forEach(((e,t)=>{O(Ge,`[header] ${t}: ${e}`)})),o>=200&&o<300){const e=await s.text(),t=r.get("Location")||r.get("location");if(t){if(t.match(/^(http|https)/))this._resource=t;else{O(Ge,`[whipwhep-response] Location provided as relative path: ${t}`);const e=new URL(this._url);e.pathname=t.split("?")[0],this._resource=e.toString().replace(/\/endpoint\//,"/resource/")}return O(Ge,`[whipwhep-response] ${this._resource}: ${e}`),{sdp:e,location:this._resource}}return k(Ge,"Location not provided in header response to Offer."),this._resource=new URL(this._url).toString().replace(/\/endpoint\//,"/resource/"),{sdp:e,location:this._resource}}if(i&&xe.get(o)){if(O(Ge,xe.get(o)),404===o||409===o)throw new $e(xe.get(o));throw new Error(xe.get(o))}if(!i&&We.get(o)){if(O(Ge,We.get(o)),404===o||409===o)throw new $e(We.get(o));throw new Error(We.get(o))}{const e=await s.text();throw Error(e)}}catch(e){throw H(Ge,e.message),e}}async postSDPAnswer(e,t={}){O(Ge,`[whipwhep:post-answer] ${this._resource}: `+JSON.stringify(e,null,2));let i=this._resource,n=ze(i);t&&Object.keys(t).forEach((e=>{-1===Ke.indexOf(e)&&(n=ze(i),i+=`${n}${e}=${t[e]}`)})),this._forceHost&&this._origin&&!(null==t?void 0:t.host)&&(n=i.indexOf("?")>-1?"&":"?",i+=`${n}host=${this._origin}`);try{const t=await fetch(i,{method:"PATCH",mode:"cors",headers:{"Content-Type":"application/sdp"},body:e}),{status:n}=t;if(n>=200&&n<300)return{success:!0,code:n};if(We.get(n))throw O(Ge,We.get(n)),new Error(We.get(n));{const e=await t.text();throw Error(e)}}catch(e){throw H(Ge,e.message),e}}async trickle(e,t={}){O(Ge,`[whipwhep-trickle] ${this._resource}: `+JSON.stringify(e,null,2));let i=this._resource,n=ze(i);t&&Object.keys(t).forEach((e=>{-1===Ke.indexOf(e)&&(n=ze(i),i+=`${n}${e}=${t[e]}`)})),this._forceHost&&this._origin&&!(null==t?void 0:t.host)&&(n=ze(i),i+=`${n}host=${this._origin}`);try{const t=await fetch(i,{method:"PATCH",mode:"cors",headers:{"Content-Type":"application/trickle-ice-sdpfrag"},body:e}),{status:n}=t;if(n>=200&&n<300){const e=await t.text();return O(Ge,`[whipwhep-response] ${this._resource}: ${e}`),{candidate:e}}if(405===n)throw O(Ge,"Remember to update the URL passed into the WHIP or WHEP client"),new Error("Remember to update the URL passed into the WHIP or WHEP client");{const e=await t.text();throw Error(e)}}catch(e){throw H(Ge,e.message),e}}async tearDown(e={},t=!1){if(!this._resource)return;let i=this._resource,n=ze(i);e&&Object.keys(e).forEach((t=>{-1===Ke.indexOf(t)&&(n=ze(i),i+=`${n}${t}=${e[t]}`)})),this._forceHost&&this._origin&&!(null==e?void 0:e.host)&&(n=ze(i),i+=`${n}host=${this._origin}`),O(Ge,"[whipwhep-teardown]");try{await fetch(i,{method:"DELETE",mode:"cors"})}catch(e){if(H(Ge,e.message),!t)throw e}this._url=void 0,this._origin=void 0,this._resource=void 0,this._forceHost=!1,this._enableSignalingChannel=!1}async post(){return O(Ge,"[whipwhep:post] transport called."),Promise.resolve(!1)}async postAsync(){return O(Ge,"[whipwhep:postAsync] transport called."),Promise.resolve(null)}getUrl(){return this._url}}const qe="R5ProPublishView";class Xe{constructor(e="red5pro-publisher"){try{this._targetElement=ie.resolveElement(e)}catch(e){throw H(qe,`Could not instantiate a new instance of PublishView. Reason: ${e.message}`),e}}preview(e){const t=this.isAutoplay;O(qe,`[preview]: autoplay(${t})`),ie.setVideoSource(this._targetElement,e,t)}unpreview(){ie.setVideoSource(this._targetElement,null,this.isAutoplay)}get isAutoplay(){return ie.hasAttributeDefined(this._targetElement,"autoplay")}get view(){return this._targetElement}}var Qe,Ze;!function(e){e.INBOUND="inbound-rtp",e.OUTBOUND="outbound-rtp",e.CODEC="codec",e.MEDIA_SOURCE="media-source",e.CANDIDATE_PAIR="candidate-pair",e.CERTIFICATE="certificate",e.DATA_CHANNEL="data-channel",e.LOCAL_CANDIDATE="local-candidate",e.REMOTE_CANDIDATE="remote-candidate",e.PEER_CONNECTION="peer-connection",e.REMOTE_INBOUND="remote-inbound-rtp",e.REMOTE_OUTBOUND="remote-outbound-rtp",e.TRANSPORT="transport"}(Qe||(Qe={})),function(e){e.STALE_STATS="STALE_STATS",e.STATE_REGRESSION="STATE_REGRESSION",e.EXCESSIVE_RTT="EXCESSIVE_RTT",e.ICE_TIMEOUT="ICE_TIMEOUT"}(Ze||(Ze={}));class et{constructor(e,t,i,n){this._name="RTCStatsMonitor",this._queue=[],this._startTime=0,this._stopped=!1,this._interval=0,this._candidatePairHealth=new Map,this._name=e,this._renegotiationPolicy=n,this._config={...pe,...t},this._client=i,this._identifier={name:this._name,created:(new Date).getTime(),fingerprint:ie.getOrGenerateFingerprint(),device:ie.getBrowserDetails(),client:t}}_emptyStatsReportQueue(){for(;this._queue.length>0;){const e=this._client.getMessageTransport();if(e){const t=this._queue.shift();e.post(t)}else k(this._name,"Failed to post stats data to message transport. Message transport is not available.")}}_getStats(){const{_connection:e}=this;if(e)try{e.getStats(null).then((e=>{e.forEach((e=>{this._handleStatsReport(e)}))})).catch((e=>{H(this._name,`Failed to get stats report. ${e.message||e}`)}))}catch(e){H(this._name,`Failed to get stats report. ${e.message||e}`)}}_handleStatsReport(e){console.log(`[${this._name}]: ${JSON.stringify(e,null,2)}`)}_appendClientDetails(e){this._identifier.client={...this._identifier.client,...e}}async start(e){this._startTime=(new Date).getTime(),this._stopped=!1,this._connection=e,this.postAction("started"),this._getStats(),this._interval=setInterval((()=>{this._stopped||this._getStats()}),this._config.interval)}stop(){this._stopped=!0,clearInterval(this._interval),this.postAction("ended")}async post(t){const i={...this._identifier,type:"stats-report",timestamp:(new Date).getTime(),data:t},{endpoint:n,additionalHeaders:s}=this._config;if(n===e.StatsEndpointType.DEV_NULL)return;if(this._client&&this._client.onStatsReport&&(null===n||n===e.StatsEndpointType.EVENT_TRANSPORT))return void this._client.onStatsReport(this._connection,i);let o={"Content-Type":"application/json"};if(s&&(o={...o,...s}),n&&n.match(/^(http|https):\/\//))try{const e=await fetch(n,{method:"POST",headers:o,body:JSON.stringify(i)});e.status>=200&&e.status<300?O(this._name,`Posted stats data to endpoint: ${n}.`):H(this._name,`Failed to post stats data to endpoint: ${n}. ${e.status}`)}catch(e){H(this._name,`Failed to post stats data to endpoint: ${n}. ${e.message||e}`)}else if(this._client&&this._client.getMessageTransport()&&(void 0===n||n===e.StatsEndpointType.DATA_CHANNEL))try{let t=!1;const n=this._client.getMessageTransport();n&&(t=await n.post(i)),t||(this._queue.push(i),this._client.on(e.MessageTransportStateEventTypes.CHANGE,(()=>{this._client.off(e.MessageTransportStateEventTypes.CHANGE),this._emptyStatsReportQueue()})),k(this._name,"Failed to post stats data to message transport. Message transport is not available. Pushed to Queue."))}catch(e){H(this._name,`Failed to post stats data to message transport. ${e.message||e}`)}}async postAction(e,t=void 0){return this.post({action:{type:e,data:t,timestamp:(new Date).getTime()}})}async postEvent(e,t){return this.post({event:{type:e,data:t||void 0,timestamp:(new Date).getTime()}})}updateEndpoint(e,t=!0){const{endpoint:i}=this._config;t?this._config.endpoint=e:t||i||(this._config.endpoint=e)}_checkCandidatePairHealth(e){var t;const{id:i,state:n,currentRoundTripTime:s,totalRoundTripTime:o}=e,r="connected"===this._client.getPeerConnection().iceConnectionState,a=(new Date).getTime();this._candidatePairHealth.has(i)||this._candidatePairHealth.set(i,{id:i,staleSampleCount:0,stateTransitionTime:a,inProgressStartTime:"in-progress"===n?a:void 0});const l=this._candidatePairHealth.get(i);if(void 0!==l.previousRTT&&void 0!==l.previousTotalRTT&&void 0!==s&&void 0!==o&&(s===l.previousRTT&&o===l.previousTotalRTT?(l.staleSampleCount++,l.staleSampleCount>=3&&l.lastIssueReported!==Ze.STALE_STATS&&(this._client.emit(Pe.CONNECTION_HEALTH_STALE_STATS,{candidatePairId:i,frozenRTT:s,frozenTotalRTT:o,staleDurationSeconds:l.staleSampleCount,message:"RTT values frozen - connection may be dead"}),l.lastIssueReported=Ze.STALE_STATS)):(l.staleSampleCount=0,l.lastIssueReported===Ze.STALE_STATS&&(l.lastIssueReported=void 0))),"succeeded"!==l.previousState||"succeeded"===n||r||(this._client.emit(Pe.CONNECTION_HEALTH_STATE_REGRESSION,{candidatePairId:i,previousState:l.previousState,currentState:n,message:`ICE candidate pair regressed from '${l.previousState}' to '${n}' - connection lost`}),l.lastIssueReported=Ze.STATE_REGRESSION,l.stateTransitionTime=a),void 0!==s&&s>1&&l.lastIssueReported!==Ze.EXCESSIVE_RTT?(this._client.emit(Pe.CONNECTION_HEALTH_EXCESSIVE_RTT,{candidatePairId:i,currentRTT:s,message:`Excessive RTT detected: ${(1e3*s).toFixed(0)}ms - possible network issues`}),l.lastIssueReported=Ze.EXCESSIVE_RTT):void 0!==s&&s<=1&&l.lastIssueReported===Ze.EXCESSIVE_RTT&&(l.lastIssueReported=void 0),"in-progress"===n){l.inProgressStartTime||(l.inProgressStartTime=a);const e=a-l.inProgressStartTime;e>((null===(t=this._renegotiationPolicy)||void 0===t?void 0:t.iceTimeoutInterval)||5e3)&&l.lastIssueReported!==Ze.ICE_TIMEOUT&&(this._client.emit(Pe.CONNECTION_HEALTH_ICE_TIMEOUT,{candidatePairId:i,durationSeconds:Math.floor(e/1e3),message:`ICE negotiation timeout - candidate pair stuck in 'in-progress' for ${Math.floor(e/1e3)}s`}),l.lastIssueReported=Ze.ICE_TIMEOUT)}else l.inProgressStartTime=void 0,l.lastIssueReported===Ze.ICE_TIMEOUT&&(l.lastIssueReported=void 0);l.previousState=n,l.previousRTT=s,l.previousTotalRTT=o,n!==l.previousState&&(l.stateTransitionTime=a)}dispose(){this.stop(),this._candidatePairHealth.clear(),this._connection=void 0,this._client=void 0}}const tt=/(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b) \d+ typ srflx/,it=e=>{const t=e.match(tt);return t&&t.length>1?t[1]:null},nt=[e.PublisherEventTypes.PUBLISH_START,e.PublisherEventTypes.PUBLISH_FAIL,e.PublisherEventTypes.PUBLISH_INSUFFICIENT_BANDWIDTH,e.PublisherEventTypes.PUBLISH_SUFFICIENT_BANDWIDTH,e.PublisherEventTypes.PUBLISH_RECOVERING_BANDWIDTH,e.PublisherEventTypes.STATISTICS_ENDPOINT_CHANGE];class st extends et{constructor(t,i){if(super("RTCPublisherStats",t,i),this.estimatedAudioBitrate=0,this.estimatedVideoBitrate=0,this.lastAudioReport=null,this.lastVideoReport=null,this._eventHandler=t=>{const{type:i,data:n}=t;if(nt.indexOf(i)>-1){if(i===e.PublisherEventTypes.STATISTICS_ENDPOINT_CHANGE){const{statisticsEndpoint:e}=n;this.updateEndpoint(e,!1)}this.postEvent(i)}},this._candidateCreateHandler=({data:{candidate:e}})=>{const{candidate:t}=e,i=it(t);i&&(this._identifier.publicIP=i)},this._hostEndpointChangedHandler=({data:{endpoint:e,iceServers:t}})=>{this._appendClientDetails({node:e,iceServers:t})},this._client.on("*",this._eventHandler),this._client.on(e.RTCPublisherEventTypes.CANDIDATE_CREATE,this._candidateCreateHandler),this._client.on(e.RTCPublisherEventTypes.HOST_ENDPOINT_CHANGED,this._hostEndpointChangedHandler),this._client.getPeerConnection())this.start(this._client.getPeerConnection());else{const t=({data:i})=>{this._client.off(e.RTCPublisherEventTypes.PEER_CONNECTION_AVAILABLE,t),this.start(i)};this._client.on(e.RTCPublisherEventTypes.PEER_CONNECTION_AVAILABLE,t)}}_handleStatsReport(e){const{type:t}=e,{include:i}=this._config,n=i&&i.length>0;if(n&&i.indexOf(t)>=-1)this.post(e);else if(!n)if(t===Qe.CODEC){const{id:i,clockRate:n,mimeType:s,payloadType:o}=e;this.post({id:i,type:t,clockRate:n,mimeType:s,payloadType:o})}else if(t===Qe.CANDIDATE_PAIR){const{availableOutgoingBitrate:i,currentRoundTripTime:n,totalRoundTripTime:s,state:o}=e;this._checkCandidatePairHealth(e),this.post({type:t,availableOutgoingBitrate:i,currentRoundTripTime:n,totalRoundTripTime:s,state:o})}else if(t===Qe.MEDIA_SOURCE){const{kind:i}=e;if("audio"===i)this.post({type:t,kind:i});else if("video"===i){const{framesPerSecond:n,height:s,width:o}=e;this.post({type:t,kind:i,framesPerSecond:n,height:s,width:o})}}else if([Qe.OUTBOUND,"outboundrtp"].indexOf(t)>-1){const{timestamp:i,kind:n,codecId:s,mediaType:o,active:r,bytesSent:a,packetsSent:l,totalPacketsSendDelay:d}=e,h={type:t,kind:n,codecId:s,mediaType:o,active:r,bytesSent:a,packetsSent:l,totalPacketsSendDelay:d};if("audio"===n){if(this.lastAudioReport){const{bytesSent:e,timestamp:t}=this.lastAudioReport,n=8*(a-e)/(i-t);this.estimatedAudioBitrate=n}this.post({...h,estimatedBitrate:Math.floor(this.estimatedAudioBitrate)}),this.lastAudioReport=e}else if("video"===n){const{firCount:t,pliCount:n,frameWidth:s,frameHeight:o,framesEncoded:r,framesPerSecond:l,framesSent:d,keyFramesEncoded:c,qualityLimitationReason:u,qualityLimitationDurations:p}=e;let _={...h,firCount:t,pliCount:n,frameWidth:s,frameHeight:o,framesEncoded:r,framesPerSecond:l,framesSent:d,keyFramesEncoded:c,qualityLimitationReason:"none"!==u?u:void 0,qualityLimitationDurations:"none"!==u?p:void 0};if(this.lastVideoReport){const{bytesSent:e,timestamp:t}=this.lastVideoReport,n=8*(a-e)/(i-t);this.estimatedVideoBitrate=n}this.post({..._,estimatedBitrate:Math.floor(this.estimatedVideoBitrate)}),this.lastVideoReport=e}}}dispose(){this._client.off("*",this._eventHandler),this._client.off(e.RTCPublisherEventTypes.CANDIDATE_CREATE,this._candidateCreateHandler),this._client.off(e.RTCPublisherEventTypes.HOST_ENDPOINT_CHANGED,this._hostEndpointChangedHandler),super.dispose()}}const ot={pubnub:window.PubNub,userId:`user-${Math.floor(65536*Math.random()).toString(16)}`,publishKey:void 0,subscribeKey:void 0,authToken:void 0,cloudEndpoint:void 0,backendUrl:void 0,backendURL:void 0,expiryMinutes:120,channelId:"red5",logLevel:"trace"};var rt;!function(e){e.CONNECTED="PubNub.Connected",e.DISCONNECTED="PubNub.Disconnected",e.SUBSCRIBE_SUCCESS="PubNub.Subscribe.Success",e.SUBSCRIBE_FAILURE="PubNub.Subscribe.Failure",e.UNSUBSCRIBE_SUCCESS="PubNub.Unsubscribe.Success",e.UNSUBSCRIBE_FAILURE="PubNub.Unsubscribe.Failure",e.MESSAGE_RECEIVED="PubNub.Message.Received",e.MESSAGE_SEND_SUCCESS="PubNub.Message.Send.Success",e.MESSAGE_SEND_FAILURE="PubNub.Message.Send.Failure",e.AUTH_TOKEN_GENERATED="PubNub.AuthToken.Generated",e.AUTH_TOKEN_GENERATION_ERROR="PubNub.AuthToken.Generation.Error",e.STATUS="PubNub.Status",e.ERROR="PubNub.Error"}(rt||(rt={}));const at="PubNubService";class lt{constructor(){}_decodeToken(e){const t=e.split(".")[1].replace(/-/g,"+").replace(/_/g,"/"),i=decodeURIComponent(atob(t).split("").map((e=>"%"+("00"+e.charCodeAt(0).toString(16)).slice(-2))).join(""));return JSON.parse(i)}async getAuthTokenFromBackendService(e){var t;const{userId:i,backendUrl:n,backendURL:s,channelId:o="red5",expiryMinutes:r=120}=e;if(!n&&!s)throw new Error("Backend URL is required. Please provide a backend URL in the pubnub configuration.");const a={userId:i,channelId:o,read:!0,write:!0,ttlMinutes:r};try{const e=await fetch(n||s,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)});if(!e.ok)throw new Error("Failed to generate auth token. Please try again later.");const t=await e.json(),{token:i}=t;return i}catch(e){throw new Error(null!==(t=e.message)&&void 0!==t?t:"Failed to generate auth token. Please try again later.")}}async getAuthTokenFromCloud(e){var t;const{userId:i,cloudEndpoint:n,publishKey:s,subscribeKey:o,channelId:r="red5",expiryMinutes:a=120}=e;if(!n)throw new Error("Cloud endpoint is required. Please provide a cloud endpoint in the pubnub configuration.");try{const e=n.match(/^https?:\/\//)?n:`https://${n}`,t=await fetch(`${e}/config-meetings/api/generate-token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({userId:i,channelId:r,expirationMinutes:a})});if(!t.ok)throw new Error("Failed to generate auth token. Please try again later.");const d=await t.json(),{success:h,token:c}=d;if(!h)throw new Error("Failed to generate auth token. Please try again later.");const u=this._decodeToken(c);if(!u)throw new Error("Failed to decode auth token. Please try again later.");l=`[${at}] :: Decoded auth token: ${JSON.stringify(u)}`,O(at,l);const{uid:p,roomId:_,pubnubPublishKey:g,pubnubSubscribeKey:v,pubnubToken:m}=u;if(p!==i||_!==r)throw new Error("Invalid auth token. Please try again later.");if(g!==s||v!==o)throw new Error("Invalid auth token. Please try again later.");return m}catch(e){throw new Error(null!==(t=e.message)&&void 0!==t?t:"Failed to generate auth token. Please try again later.")}var l}}const dt="PubNubClient",ht={receivePresenceEvents:!0,withPresence:!1},ct=e=>O(dt,e),ut=e=>k(dt,e),pt=e=>H(dt,e);class _t extends U{constructor(){super(),this._subscriptions={}}async _getAuthFromCloud(e){const t=new lt;return await t.getAuthTokenFromCloud(e)}async _getAuthFromBackend(e){const t=new lt;return await t.getAuthTokenFromBackendService(e)}async init(e){var t,i,n,s,o,r,a;if(this._config={...ot,...e},(null===(t=this._config)||void 0===t?void 0:t.cloudEndpoint)||(null===(i=this._config)||void 0===i?void 0:i.backendUrl)||(null===(n=this._config)||void 0===n?void 0:n.backendURL)){let e;try{if((null===(s=this._config)||void 0===s?void 0:s.cloudEndpoint)?e=await this._getAuthFromCloud(this._config):((null===(o=this._config)||void 0===o?void 0:o.backendUrl)||(null===(r=this._config)||void 0===r?void 0:r.backendURL))&&(e=await this._getAuthFromBackend(this._config)),!e)throw new Error("Failed to get auth token.");this._config.authToken=e,this.trigger(new Ce(rt.AUTH_TOKEN_GENERATED,this,{authToken:e}))}catch(e){return pt(null!==(a=e.message)&&void 0!==a?a:"Failed to get auth token."),this.trigger(new Ce(rt.AUTH_TOKEN_GENERATION_ERROR,this,{error:e.message})),this}}const{pubnub:l,publishKey:d,subscribeKey:h,authToken:c,userId:u,logLevel:p}=this._config;if(!l){const e="PubNub library is not initialized. Please provide a PubNub library reference in the configuration.";throw this.trigger(new Ce(rt.ERROR,this,{error:e})),pt(e),new Error(e)}return ct(`Initializing PubNub client with options: ${JSON.stringify(this._config)}`),this._pubnub=new l({userId:u,publishKey:d,subscribeKey:h,logLevel:p}),this._pubnub.setToken(c),this._pubnub.addListener({message:e=>{var t;ct(`Message received on channel ${e.channel}: ${e.message}`),this.trigger(new Ce(rt.MESSAGE_RECEIVED,this,{...e,userId:null===(t=this._config)||void 0===t?void 0:t.userId}))},presence:e=>{ct(`Presence event on channel ${e.channel}: ${JSON.stringify(e)}`)},status:e=>{const{category:t,operation:i}=e;ct(`Status event ${t}`),this.trigger(new Ce(rt.STATUS,this,e)),"PNConnectedCategory"===t?(this.trigger(new Ce(rt.CONNECTED,this,e)),"PNSubscribeOperation"===i&&this.trigger(new Ce(rt.SUBSCRIBE_SUCCESS,this,e))):"PNDisconnectedCategory"===t?this.trigger(new Ce(rt.DISCONNECTED,this,e)):"PNReconnectedCategory"===t||("PNAcknowledgmentCategory"===t?"PNUnsubscribeOperation"===i&&this.trigger(new Ce(rt.UNSUBSCRIBE_SUCCESS,this,e)):("PNBadRequestCategory"===t||"PNAccessDeniedCategory"===t)&&this.trigger(new Ce(rt.ERROR,this,e)))}}),this}async publishMessage(e,t){var i,n;if(!this._pubnub)return pt("PubNub client not initialized."),!1;try{const n=await this._pubnub.publish({channel:e,message:t});this.trigger(new Ce(rt.MESSAGE_SEND_SUCCESS,this,{...n,channel:e,message:t,userId:null===(i=this._config)||void 0===i?void 0:i.userId}))}catch(i){return pt(null!==(n=i.message)&&void 0!==n?n:`Failed to publish message to channel ${e}.`),this.trigger(new Ce(rt.MESSAGE_SEND_FAILURE,this,{channel:e,message:t})),!1}return!0}async subscribe(e,t){var i;if(!this._pubnub)return pt("PubNub client not initialized."),!1;if(this._subscriptions[e])return!0;try{const i=this._pubnub.channel(e),n=await i.subscription({...ht,...t});if(!n)throw new Error(`Failed to subscribe to channel ${e}.`);n.subscribe(),this._subscriptions[e]=n}catch(t){return pt(null!==(i=t.message)&&void 0!==i?i:`Failed to subscribe to channel ${e}.`),this.trigger(new Ce(rt.SUBSCRIBE_FAILURE,this,{channel:e})),!1}return!0}async unsubscribe(e){var t;if(!this._pubnub)return!0;if(!this._subscriptions[e])return ut(`Subscription ${e} not found.`),!1;try{await this._subscriptions[e].unsubscribe()}catch(i){pt(null!==(t=i.message)&&void 0!==t?t:`Failed to unsubscribe from channel ${e}.`),this.trigger(new Ce(rt.UNSUBSCRIBE_FAILURE,this,{channel:e}))}return delete this._subscriptions[e],!0}async destroy(){var e;if(this._pubnub)try{await this._pubnub.destroy()}catch(t){ut(null!==(e=t.message)&&void 0!==e?e:"Failed to destroy PubNub client.")}return this._subscriptions={},this._pubnub=void 0,this._config=void 0,!0}getOptions(){var e;return null!==(e=this._config)&&void 0!==e?e:{}}get config(){return this._config}get pubnub(){return this._pubnub}}const gt="WHIPClient",vt=ge,mt=e=>O(gt,e),Et=e=>H(gt,e),bt=e=>k(gt,e);class St extends U{constructor(e,t,i){super();const n=e?se(e):vt,s=i||vt,o={...s,...n,endpoint:e,mediaElementId:t?t.id:s.mediaElementId};e&&this.internalInit(o),this._onOrientationChange=this._onOrientationChange.bind(this)}async internalInit(e){await this.init(e),await this.publish()}async generateMediaStream(t){var i,n;const{onGetUserMedia:s}=t;if(s){mt("Requesting gUM from user-defined configuration:onGetUserMedia.");const t=await s();return this.trigger(new Ee(e.RTCPublisherEventTypes.CONSTRAINTS_ACCEPTED,this,re(t))),t}{const{mediaConstraints:s}=t;let o;mt(`Requesting gUM using mediaConstraints: ${JSON.stringify(s,null,2)}`);let r=s;const a=await Ue(r);return a&&a.media||(o=await ie.gUM(r)),o=null!==(i=null==a?void 0:a.media)&&void 0!==i?i:o,r=null!==(n=null==a?void 0:a.constraints)&&void 0!==n?n:s,mt(`Constraints accepted: ${JSON.stringify(r,null,2)}`),this.trigger(new Ee(e.RTCPublisherEventTypes.CONSTRAINTS_ACCEPTED,this,{constraints:r,...re(o)})),o}}async getAndPreviewStreamIfAvailable(){var t;let i=this._mediaStream;if(!i){try{i=null!=i?i:await this.generateMediaStream(this._options)}catch(i){const n=null!==(t=i.message)&&void 0!==t?t:"Could not generate media stream.";throw this.trigger(new Ee(e.RTCPublisherEventTypes.CONSTRAINTS_REJECTED,this,{constraints:this._options.mediaConstraints})),new Error(n)}if(!i)throw new Error("Could not generate media stream.")}return this.trigger(new Ee(e.RTCPublisherEventTypes.MEDIA_STREAM_AVAILABLE,this,i)),this.preview(i),i}reorderCodecPreferences(e,t,i){e.getTransceivers().forEach((e=>{if(e.sender&&e.sender.track){const{kind:n}=e.sender.track;if(t&&"video"===n&&e.setCodecPreferences)try{const{codecs:i}=RTCRtpSender.getCapabilities("video"),n=i.findIndex((e=>e.mimeType===`video/${t}`));if(n>-1){const t=i.slice(0),s=i[n];t.splice(n,1),t.unshift(s),e.setCodecPreferences(t)}}catch(e){bt(`[videoEncoding] Could not set codec preferences for ${t}. ${e.message||e}`)}else if(i&&"audio"===n&&e.setCodecPreferences)try{const{codecs:t}=RTCRtpSender.getCapabilities("audio"),n=t.findIndex((e=>e.mimeType===`audio/${i}`));if(n>-1){const i=t[n];t.splice(n,1),t.unshift(i),e.setCodecPreferences(t)}}catch(e){bt(`[audioEncoding] Could not set codec preferences for ${i}. ${e.message||e}`)}}}))}async postOffer(t){var i;try{const{sdp:n}=t;let{videoEncoding:s}=this._options;const{mungeOffer:o,streamMode:r,keyFramerate:a,iceTransport:l,connectionParams:d,mediaConstraints:h,forceVP8:c,audioEncoding:u,offerSDPResolution:p}=this._options;c&&!s&&(s=e.PublishVideoEncoder.VP8);let _=n;o&&(mt(`[MUNGE:before] offer: ${_}`),_=o(_),mt(`[MUNGE:after] offer: ${_}`)),p&&(mt(`[MUNGE] Setting resolution on offer: ${_}`),_=((e,t)=>{if(!t)return e;const{width:i,height:n}=t;if(!i||!n)return e;const s=`a=framesize:${i}-${n}`,o=e.split("\r\n");let r=o.length;const a=/^m=video/;for(;--r>-1;)if(a.exec(o[r])){for(;++r-1){o.splice(r+1,0,s);break}break}return o.join("\r\n")})(_,((e,t)=>{let i;if(e)try{const t=e.getVideoTracks()&&e.getVideoTracks()[0];if(t){const e=t.getSettings();i={width:e.width,height:e.height}}}catch(e){k("[determineMediaResolution]",`Could not determine resolution from MediaStream. ${e.message||e}`)}if(!i)try{const e=t.video,{width:n,height:s}=e;if(n&&s)if("number"==typeof n&&"number"==typeof s)i={width:n,height:s};else{i={width:n.exact||n.min||n.max||n.ideal||640,height:s.exact||s.min||s.max||s.ideal||480}}}catch(e){k("[determineMediaResolution]",`Could not determine resolution from MediaConstraints. ${e.message||e}`)}return i&&O("[determineMediaResolution]",`constraints: ${JSON.stringify(i,null,2)}`),i})(this._mediaStream,h)),mt(`[MUNGE:after] offer: ${_}`));const g={...d,mode:r,transport:l,keyFramerate:a};return s&&(g.videoEncoding=s),u&&(g.audioEncoding=u),await(null===(i=this._whipWhepService)||void 0===i?void 0:i.postSDPOffer(_,g))}catch(t){throw Et(t.message||t),t instanceof $e?this.trigger(new Ee(e.PublisherEventTypes.PUBLISH_INVALID_NAME,this)):(this.trigger(new Ee(e.PublisherEventTypes.CONNECT_FAILURE,this,t)),this.unpublish()),t}}async postCandidateFragments(e){var t;const{connectionParams:i}=this._options,n=Be(e,void 0,!0);return await(null===(t=this._whipWhepService)||void 0===t?void 0:t.trickle(n,i))}async initPubNub(e){var t;try{const t=new _t;this._pubnubClient=t,this._pubnubClient.on("*",(e=>{this.trigger(e)})),await t.init(e)}catch(e){return e(null!==(t=e.message)&&void 0!==t?t:"Failed to initialize PubNub."),!1}return!0}async deinitPubNub(){var e,t;try{await(null===(e=this._pubnubClient)||void 0===e?void 0:e.destroy()),this._pubnubClient=void 0}catch(e){return e(null!==(t=e.message)&&void 0!==t?t:"Failed to deinitialize PubNub."),!1}return!0}async init(e){var t,i;this._options={...vt,...e};const n=oe(this._options),{includeDataChannel:s,disableProxy:o}=this._options;return this._whipWhepService=new Ye(n,s,o),this._messageTransport=this._whipWhepService,(null===(t=this._options)||void 0===t?void 0:t.stats)&&this.monitorStats(this._options.stats),this._mediaStream=await this.getAndPreviewStreamIfAvailable(),(null===(i=this._options)||void 0===i?void 0:i.pubnub)&&await this.initPubNub(this._options.pubnub),this}async initWithStream(e,t){return this._mediaStream=t,this.init(e)}async publish(t){var i,n,s,o,r;t&&(this._options.streamName=t);const{forceVP8:a,audioEncoding:l,rtcConfiguration:d,dataChannelConfiguration:h,includeDataChannel:c,signalingSocketOnly:u,enableChannelSignaling:p,connectionParams:_,bandwidth:g,mungeAnswer:v}=this._options;let{videoEncoding:m}=this._options;a&&(m=e.PublishVideoEncoder.VP8,this._options.videoEncoding=m),this._mediaStream||(this._mediaStream=await this.getAndPreviewStreamIfAvailable());try{const t=null!=_?_:{};if(_){const{transcode:e}=_;e&&(t.transcode=e)}const r=await(null===(i=this._whipWhepService)||void 0===i?void 0:i.getOptions(t)),a=!!(null===(n=this._options)||void 0===n?void 0:n.rtcConfiguration)&&Array.isArray(this._options.rtcConfiguration.iceServers)&&this._options.rtcConfiguration.iceServers.length>0;(null==r?void 0:r.links)&&!a&&(this._options.rtcConfiguration={...d,iceServers:r.links}),(null==r?void 0:r.origin)&&this.trigger(new Ee(e.RTCPublisherEventTypes.HOST_ENDPOINT_CHANGED,this,{endpoint:r.origin})),(null==r?void 0:r.statisticsEndpoint)&&this._onStatisticsEndpointChange(r.statisticsEndpoint);const E=c||p||u?h:void 0;this._peerConnectionHelper=new Fe({onDataChannelError:this._onDataChannelError.bind(this),onSendReceived:this._onSendReceived.bind(this),onMetaData:this._onMetaData.bind(this),onConnectionClosed:this._onConnectionClosed.bind(this),onDataChannelOpen:this._onDataChannelOpen.bind(this),onDataChannelClose:this._onDataChannelClose.bind(this),onDataChannelMessage:this._onDataChannelMessage.bind(this),onPeerConnectionOpen:this._onPeerConnectionOpen.bind(this),onPeerConnectionFail:this._onPeerConnectionFail.bind(this),onPeerConnectionClose:this._onPeerConnectionClose.bind(this),onIceCandidate:this._onIceCandidate.bind(this),onSDPSuccess:this._onSDPSuccess.bind(this),onSDPError:this._onSDPError.bind(this),onStatisticsEndpointChange:this._onStatisticsEndpointChange.bind(this),onPublisherStatus:this._onPublisherStatus.bind(this),onPeerConnectionTrackAdd:this._onPeerConnectionTrackAdd.bind(this),onInsufficientBandwidth:this._onInsufficientBandwidth.bind(this),onSufficientBandwidth:this._onSufficientBandwidth.bind(this),onRecoveringBandwidth:this._onRecoveringBandwidth.bind(this),onUnpublish:this._onUnpublish.bind(this)}),await this._peerConnectionHelper.setUpWithPeerConfiguration(this._options.rtcConfiguration,E),this.trigger(new Ee(e.RTCPublisherEventTypes.PEER_CONNECTION_AVAILABLE,this,this.getPeerConnection())),this._mediaStream.getTracks().forEach((e=>{var t;null===(t=this.getPeerConnection())||void 0===t||t.addTransceiver(e,{direction:"sendonly"})})),this.reorderCodecPreferences(this.getPeerConnection(),m,l);const b=await(null===(s=this._peerConnectionHelper)||void 0===s?void 0:s.createOfferWithoutSetLocal(g));await this._peerConnectionHelper.setLocalDescription(b),this.trigger(new Ee(e.RTCPublisherEventTypes.OFFER_START,this,b));const{sdp:S}=await this.postOffer(b);let C=S;v&&(mt(`[MUNGE:before] answer: ${C}`),C=v(C),mt(`[MUNGE:after] answer: ${C}`)),await this._peerConnectionHelper.setRemoteDescription({type:"answer",sdp:C}),this.trigger(new Ee(e.RTCPublisherEventTypes.OFFER_END,this,C));const T=await this._peerConnectionHelper.waitToGatherIce(),{sdp:y}=T;return await this.postCandidateFragments(y),this.trigger(new Ee(e.RTCPublisherEventTypes.ICE_TRICKLE_COMPLETE,this)),ie.addOrientationChangeHandler(this._onOrientationChange),(null===(o=this._options)||void 0===o?void 0:o.includeDataChannel)||this.trigger(new Ee(e.PublisherEventTypes.PUBLISH_START,this)),this}catch(t){throw Et(null!==(r=t.message)&&void 0!==r?r:"Could not publish."),this.trigger(new Ee(e.PublisherEventTypes.CONNECT_FAILURE,this,t)),this.unpublish(!0),t}}async unpublish(t=!1){var i;mt("[unpublish]"),this._peerConnectionHelper&&await this._peerConnectionHelper.tearDown(),this._whipWhepService&&await this._whipWhepService.tearDown(null,t),(null===(i=this._options)||void 0===i?void 0:i.clearMediaOnUnpublish)&&this.unpreview(),this._pubnubClient&&await this.deinitPubNub(),this._pubnubClient=void 0,this._mediaStream=void 0,this._peerConnectionHelper=void 0,this._whipWhepService=void 0,this._messageTransport=void 0,this._publishView=void 0,this.trigger(new Ee(e.PublisherEventTypes.UNPUBLISH_SUCCESS,this)),ie.removeOrientationChangeHandler(this._onOrientationChange)}preview(e){mt("[preview]");const{mediaElementId:t}=this._options;t&&(this._publishView=new Xe(t),this._publishView.preview(e))}unpreview(){mt("[unpreview]"),this._mediaStream&&this._mediaStream.getTracks().forEach((e=>{e.stop()})),this._publishView&&this._publishView.unpreview(),this._publishView=void 0}monitorStats(e){mt("[monitorStats]");const{host:t,endpoint:i,app:n,streamName:s,connectionParams:o}=this._options,r=null!=e?e:pe;return this._statisticsConfiguration={...r,host:t,hostEndpoint:i,app:n,streamName:s,connectionParams:o},this._statsMonitor?bt("Cannot monitor stats without a Peer Connection. Please call `init` before calling `monitorStats`."):this._statsMonitor=new st(this._statisticsConfiguration,{onStatsReport:this._onStatsReport.bind(this),getPeerConnection:this.getPeerConnection.bind(this),getMessageTransport:this.getMessageTransport.bind(this),on:this.on.bind(this),off:this.off.bind(this),trigger:this.trigger.bind(this),emit:this.emit.bind(this)}),this}unmonitorStats(){return this._statsMonitor&&this._statsMonitor.dispose(),this._statsMonitor=void 0,this._statisticsConfiguration=void 0,this}muteAudio(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteAudio:!0}})}unmuteAudio(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteAudio:!1}})}muteVideo(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteVideo:!0}})}unmuteVideo(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteVideo:!1}})}send(e,t){var i;return null===(i=this.getMessageTransport())||void 0===i?void 0:i.post({send:{method:e,data:"string"==typeof t?JSON.parse(t):t}})}async sendPubNub(e,t){return this._pubnubClient?await this._pubnubClient.publishMessage(e,t):(Et("PubNub client not initialized."),!1)}async subscribePubNub(e,t){return this._pubnubClient?await this._pubnubClient.subscribe(e,t):(Et("PubNub client not initialized."),!1)}async unsubscribePubNub(e){return this._pubnubClient?await this._pubnubClient.unsubscribe(e):(Et("PubNub client not initialized."),!1)}async callServer(e,t){var i;try{if(!this.getMessageTransport())throw new Error("Message transport not available");return null===(i=this.getMessageTransport())||void 0===i?void 0:i.postAsync({callAdapter:{method:e,arguments:t}})}catch(e){Et(e.message||e)}}sendLog(e,t){var i;try{const n=Object.keys(L).find((t=>t.toLowerCase()===e.toLowerCase()))?e:L.DEBUG,s="string"==typeof t?t:JSON.stringify(t);null===(i=this.getMessageTransport())||void 0===i||i.post({log:n.toUpperCase(),message:s})}catch(e){const t=e.message||e;Et("Could not send log to server. Message parameter expected to be String or JSON-serializable object."),Et(t)}}get options(){return this._options}getOptions(){return this._options}getPeerConnection(){var e;return null===(e=this._peerConnectionHelper)||void 0===e?void 0:e.connection}getDataChannel(){var e;return null===(e=this._peerConnectionHelper)||void 0===e?void 0:e.dataChannel}getMediaStream(){return this._mediaStream}getMessageTransport(){return this._messageTransport}getPubNubClient(){return this._pubnubClient}_onDataChannelError(t,i){Et(`Data channel error: ${i}`),this.trigger(new Ee(e.RTCPublisherEventTypes.DATA_CHANNEL_ERROR,this,{dataChannel:t,error:i}))}_onSendReceived(t,i){mt(`Send received: ${t} ${JSON.stringify(i)}`),"onMetaData"===t?this._onMetaData(i):this.trigger(new Ee(e.PublisherEventTypes.PUBLISH_SEND_INVOKE,this,{methodName:t,data:i}))}_onMetaData(t){mt(`Metadata received: ${JSON.stringify(t)}`),this.trigger(new Ee(e.PublisherEventTypes.PUBLISH_METADATA,this,t))}_onConnectionClosed(){mt("Connection closed"),this.unpublish(),this.trigger(new Ee(e.PublisherEventTypes.CONNECTION_CLOSED,this))}_onDataChannelOpen(t){mt(`Data channel opened: ${t.label}`),this.trigger(new Ee(e.RTCPublisherEventTypes.DATA_CHANNEL_OPEN,this,{dataChannel:t})),this.trigger(new Ee(e.RTCPublisherEventTypes.DATA_CHANNEL_AVAILABLE,this,{name:t.label,dataChannel:t})),this._messageTransport=this._peerConnectionHelper,this.trigger(new Se(e.MessageTransportStateEventTypes.CHANGE,this,{controller:this,transport:this._messageTransport})),this.trigger(new Ee(e.PublisherEventTypes.PUBLISH_START,this))}_onDataChannelClose(t){mt(`Data channel closed: ${t.label}`),this.trigger(new Ee(e.RTCPublisherEventTypes.DATA_CHANNEL_CLOSE,this,{dataChannel:t}))}_onDataChannelMessage(t,i){mt(`Data channel message: ${i.data}`),this.trigger(new Ee(e.RTCPublisherEventTypes.DATA_CHANNEL_MESSAGE,this,{dataChannel:t,message:i}))}_onPeerConnectionTrackAdd(t){mt(`Peer connection track added: ${t.id}`),this.trigger(new Ee(e.RTCPublisherEventTypes.TRACK_ADDED,this,{track:t}))}_onPeerConnectionOpen(){mt("Peer connection opened"),this.trigger(new Ee(e.RTCPublisherEventTypes.PEER_CONNECTION_OPEN,this,this.getPeerConnection()))}_onPeerConnectionFail(){Et("Peer connection failed"),this.trigger(new Ee(e.PublisherEventTypes.PUBLISH_FAIL,this))}_onPeerConnectionClose(t){mt(`Peer connection closed: ${t.type}`),this._peerConnectionHelper&&this._peerConnectionHelper.tearDown(),this.trigger(new Ee(e.PublisherEventTypes.CONNECTION_CLOSED,this,t))}_onIceCandidate(t){mt(`ICE candidate: ${JSON.stringify(t,null,2)}`),this.trigger(new Ee(e.RTCPublisherEventTypes.CANDIDATE_CREATE,this,{candidate:t}))}_onUnpublish(){mt("Unpublish received")}_onPublisherStatus(t){mt("[publisherstatus] - "+JSON.stringify(t,null,2)),t.code&&"NetStream.Publish.IsAvailable"===t.code?this.trigger(new Ee(e.PublisherEventTypes.PUBLISH_AVAILABLE,this,t)):this.trigger(new Ee(e.PublisherEventTypes.PUBLISH_STATUS,this,t))}_onInsufficientBandwidth(t){this.trigger(new Ee(e.PublisherEventTypes.PUBLISH_INSUFFICIENT_BANDWIDTH,this,t))}_onSufficientBandwidth(t){this.trigger(new Ee(e.PublisherEventTypes.PUBLISH_SUFFICIENT_BANDWIDTH,this,t))}_onRecoveringBandwidth(t){this.trigger(new Ee(e.PublisherEventTypes.PUBLISH_RECOVERING_BANDWIDTH,this,t))}_onSDPSuccess(e=void 0){const t=e?": "+JSON.stringify(e,null,2):"";mt(`[onsdpsuccess]:: ${t}`)}_onSDPError(t=void 0){this.trigger(new Ee(e.PublisherEventTypes.PUBLISH_FAIL,this));const i=t?": "+JSON.stringify(t,null,2):"";Et(`[onsdperror]:: ${i}`)}_onOrientationChange(e){const t=this.getMessageTransport();t&&t.post({send:{method:"onMetaData",data:{deviceOrientation:e}}})}_onStatisticsEndpointChange(t){mt(`Statistics endpoint changed: ${t}`),this._statsMonitor&&this._statsMonitor.updateEndpoint(t),this.trigger(new Ee(e.PublisherEventTypes.STATISTICS_ENDPOINT_CHANGE,this,{statisticsEndpoint:t}))}_onStatsReport(t,i){this.trigger(new Ee(e.RTCPublisherEventTypes.STATS_REPORT,this,{connection:t,report:i}))}on(e,t){super.on(e,t)}off(e,t){super.off(e,t)}trigger(e){super.trigger(e)}emit(e,t){this.trigger(new Ee(e,this,t))}getType(){return"RTC"}}const Ct={...{protocol:"https",port:443,app:"live",autoLayoutOrientation:!0,mediaElementId:"red5pro-subscriber",rtcConfiguration:{iceCandidatePoolSize:2,bundlePolicy:"max-bundle"},iceTransport:de.UDP,muteOnAutoplayRestriction:!0,maintainConnectionOnSubscribeErrors:!1,dataChannelConfiguration:{name:"red5pro"},signalingSocketOnly:!1,includeDataChannel:!0,maintainStreamVariant:!1,buffer:0,stats:void 0,pubnub:void 0,renegotiationPolicy:void 0},signalingSocketOnly:!1,enableChannelSignaling:!1,includeDataChannel:!0,disableProxy:!0,trickleIce:!0,postEmptyOffer:!1,mungeOffer:void 0,mungeAnswer:void 0},Tt={protocol:"https",port:443,app:"live",mediaElementId:"red5pro-subscriber",muteOnAutoplayRestriction:!0},yt={endpoint:e.StatsEndpointType.DEV_NULL,interval:3e3},ft="R5ProPlaybackView";class wt{constructor(e="red5pro-subscriber"){try{this._targetElement=ie.resolveElement(e)}catch(e){throw H(ft,`Could not instantiate a new instance of Red5ProSubscriber. Reason: ${e.message||e}`),e}}attachStream(e){const t=this.isAutoplay;O(ft,"[attachstream]"),ie.setVideoSource(this._targetElement,e,t)}detachStream(){O(ft,"[detachstream]"),ie.setVideoSource(this._targetElement,null,this.isAutoplay)}get isAutoplay(){return ie.hasAttributeDefined(this._targetElement,"autoplay")}get view(){return this._targetElement}}const At="RTCPeerConnectionSubscriber";class Pt extends Le{constructor(e){super(e,At)}_removeConnectionHandlers(e){e.onconnectionstatechange=null,e.oniceconnectionstatechange=null,e.onicegatheringstatechange=null,e.onsignalingstatechange=null,e.onicecandidate=null,e.ontrack=null,e.onnegotiationneeded=null}_addConnectionHandlers(e){let t;e.onsignalingstatechange=()=>{const t=e.signalingState;O(At,`[peer.onsignalingstatechange] - State: ${t}`)},e.onconnectionstatechange=()=>{const{connectionState:t}=e;"connected"===t?(O(this._name,"[peerconnection:open]"),this._responder.onPeerConnectionOpen()):"failed"===t||"disconnected"===t?(k(this._name,`[peerconnection:error]:: ${t}`),"failed"===t&&this._responder.onPeerConnectionFail()):O(this._name,`[peerconnection:state]:: ${t}`)},e.oniceconnectionstatechange=i=>{const{iceConnectionState:n}=e;O(this._name,`[peer.oniceconnectionstatechange] - State: ${n}`),"failed"===n?(t&&clearTimeout(t),this._responder.onPeerConnectionFail(),this._responder.onPeerConnectionClose(i)):"disconnected"===n?t=setTimeout((()=>{O(this._name,"[peer.oniceconnectionstatechange] - Reconnect timeout reached."),clearTimeout(t),this._responder.onPeerConnectionClose(i)}),3e3):t&&(O(this._name,"[peer.oniceconnectionstatechange] - Clearing timeout for reconnect."),clearTimeout(t))},e.onicecandidate=e=>{const{candidate:t}=e;O(this._name,`[peer.onicecandidate] - Peer Candidate: ${null==t?void 0:t.candidate}`),t&&this._responder.onIceCandidate(t)},e.onnegotiationneeded=()=>{O(this._name,"[peer.onnegotiationneeded]")},e.onicegatheringstatechange=()=>{const{iceGatheringState:t}=e;O(this._name,`[peer.onicegatheringstatechange] - State: ${t}`)}}_onDataChannelMessage(e){const t=e;if(super._onDataChannelMessage(e))return!0;const i=this.getJsonFromSocketMessage(t);if(null===i)return k(this._name,"Determined websocket response not in correct format. Aborting message handle."),!0;O(this._name,"[datachannel-response]: "+JSON.stringify(i,null,2));const{data:n}=i;if(n&&"status"===n.type)return"NetStream.Play.UnpublishNotify"===n.code?(this._responder.onUnpublish(),this._responder.onConnectionClosed(),!0):"Application.Statistics.Endpoint"===n.code?(this._responder.onStatisticsEndpointChange(n.statistics),!0):(O(At,`[datachannel.message] status :: ${n.code}`),this._responder.onSubscriberStatus(n),!0);if(n&&n.status&&"NetStream.Play.UnpublishNotify"===n.status)return this._responder.onUnpublish(),this._responder.onConnectionClosed(),!0;if(n&&"result"===n.type){const{message:e}=n;if("Stream switch: Success"===e)try{return this._responder.onStreamSwitchComplete(),!0}catch(e){}}return this._responder.onDataChannelMessage(this._dataChannel,t),!1}}var Nt;!function(e){e.EMPTY="Empty",e.VIDEO="Video",e.AUDIO="Audio",e.FULL="Video/Audio"}(Nt||(Nt={}));class Lt extends U{trigger(e){super.trigger(e)}on(e,t){super.on(e,t)}off(e,t){super.off(e,t)}}class Rt extends Lt{}const It=[e.SubscriberEventTypes.SUBSCRIBE_START,e.SubscriberEventTypes.SUBSCRIBE_STOP,e.SubscriberEventTypes.SUBSCRIBE_FAIL,e.SubscriberEventTypes.SUBSCRIBE_PUBLISHER_CONGESTION,e.SubscriberEventTypes.SUBSCRIBE_PUBLISHER_RECOVERY,e.SubscriberEventTypes.PLAY_UNPUBLISH,e.SubscriberEventTypes.STREAMING_MODE_CHANGE,e.SubscriberEventTypes.PLAYBACK_STATE_CHANGE,e.SubscriberEventTypes.STATISTICS_ENDPOINT_CHANGE];class Dt extends et{constructor(t,i,n){if(super("RTCSubscriberStats",t,i,n),this.estimatedAudioBitrate=0,this.estimatedVideoBitrate=0,this.lastAudioReport=null,this.lastVideoReport=null,this._eventHandler=t=>{const{type:i,data:n}=t;if(It.indexOf(i)>-1)if(i===e.SubscriberEventTypes.STREAMING_MODE_CHANGE){const{streamingMode:e,previousStreamingMode:t}=n;this.postEvent(i,{data:{streamingMode:e,previousStreamingMode:t}})}else if(i===e.SubscriberEventTypes.PLAYBACK_STATE_CHANGE){const{code:t}=n;let i;t===e.PlaybackState.AVAILABLE&&(i={timeToFirstFrameMS:(new Date).getTime()-this._startTime}),this.postEvent(o[t],i)}else{if(i===e.SubscriberEventTypes.STATISTICS_ENDPOINT_CHANGE){const{statisticsEndpoint:e}=n;this.updateEndpoint(e,!1)}this.postEvent(i)}},this._candidateCreateHandler=({data:{candidate:e}})=>{const{candidate:t}=e,i=it(t);i&&(this._identifier.publicIP=i)},this._hostEndpointChangedHandler=({data:{endpoint:e,iceServers:t}})=>{this._appendClientDetails({node:e,iceServers:t})},this._client.on("*",this._eventHandler),this._client.on(e.RTCSubscriberEventTypes.CANDIDATE_CREATE,this._candidateCreateHandler),this._client.on(e.RTCSubscriberEventTypes.HOST_ENDPOINT_CHANGED,this._hostEndpointChangedHandler),this._client.getPeerConnection())this.start(this._client.getPeerConnection());else{const t=({data:i})=>{this._client.off(e.RTCSubscriberEventTypes.PEER_CONNECTION_AVAILABLE,t),this.start(i)};this._client.on(e.RTCSubscriberEventTypes.PEER_CONNECTION_AVAILABLE,t)}}_handleStatsReport(e){const{type:t}=e,{include:i}=this._config,n=i&&i.length>0;if(n&&i.indexOf(t)>=-1)this.post(e);else if(!n)if(t===Qe.CODEC){const{id:i,clockRate:n,mimeType:s,payloadType:o}=e;this.post({id:i,type:t,clockRate:n,mimeType:s,payloadType:o})}else if(t===Qe.CANDIDATE_PAIR){const{availableOutgoingBitrate:i,currentRoundTripTime:n,totalRoundTripTime:s,state:o}=e;this._checkCandidatePairHealth(e),this.post({type:t,availableOutgoingBitrate:i,currentRoundTripTime:n,totalRoundTripTime:s,state:o})}else if([Qe.INBOUND,"inboundrtp"].indexOf(t)>-1){const{timestamp:i,kind:n,codecId:s,jitter:o,packetsLost:r,packetsReceived:a,bytesReceived:l}=e,d={type:t,kind:n,codecId:s,jitter:o,packetsLost:r,packetsReceived:a,bytesReceived:l};if("audio"===n){const{packetsDiscarded:t}=e;if(this.lastAudioReport){const{bytesReceived:e,timestamp:t}=this.lastAudioReport,n=8*(l-e)/(i-t);this.estimatedAudioBitrate=n}this.post({...d,packetsDiscarded:t,estimatedBitrate:Math.floor(this.estimatedAudioBitrate)}),this.lastAudioReport=e}else if("video"===n){const{firCount:t,frameWidth:n,frameHeight:s,framesDecoded:o,framesDropped:r,framesPerSecond:a,framesReceived:h,freezeCount:c,keyFramesDecoded:u,nackCount:p,pauseCount:_,pliCount:g,totalFreezesDuration:v,totalPausesDuration:m}=e,E={...d,firCount:t,frameWidth:n,frameHeight:s,framesDecoded:o,framesDropped:r,framesPerSecond:a,framesReceived:h,freezeCount:c,keyFramesDecoded:u,nackCount:p,pauseCount:_,pliCount:g,totalFreezesDuration:v,totalPausesDuration:m};if(this.lastVideoReport){const{bytesReceived:e,timestamp:t}=this.lastVideoReport,n=8*(l-e)/(i-t);this.estimatedVideoBitrate=n}this.post({...E,estimatedBitrate:Math.floor(this.estimatedVideoBitrate)}),this.lastVideoReport=e}}}dispose(){this._client.off("*",this._eventHandler),this._client.off(e.RTCSubscriberEventTypes.CANDIDATE_CREATE,this._candidateCreateHandler),this._client.off(e.RTCSubscriberEventTypes.HOST_ENDPOINT_CHANGED,this._hostEndpointChangedHandler),super.dispose()}}class Ot extends Rt{constructor(e,t){super(),this._isVOD=!1,this._name=`SourceHandler-${t}`,this._view=e,this._playbackNotificationCenter=this._view,this.onCanPlay=this._onCanPlay.bind(this),this.onDurationChange=this._onDurationChange.bind(this),this.onEnded=this._onEnded.bind(this),this.onTimeUpdate=this._onTimeUpdate.bind(this),this.onPlay=this._onPlay.bind(this),this.onPause=this._onPause.bind(this),this.onVolumeChange=this._onVolumeChange.bind(this),this.onLoadedData=this._onLoadedData.bind(this),this.onLoadedMetadata=this._onLoadedMetadata.bind(this),this.onResize=this._onResize.bind(this),this.onLoadStart=this._onLoadStart.bind(this),this.onSuspend=this._onSuspend.bind(this),this.onStalled=this._onStalled.bind(this),this.onWaiting=this._onWaiting.bind(this),this.onError=this._onError.bind(this),this.onEncrypted=this._onEncrypted.bind(this),this._addPlaybackNotificationCenterHandlers(this._playbackNotificationCenter),ie.onFullScreenStateChange(this._handleFullScreenChange.bind(this))}_addPlaybackNotificationCenterHandlers(e){e.addEventListener("canplay",this.onCanPlay),e.addEventListener("durationchange",this.onDurationChange),e.addEventListener("ended",this.onEnded),e.addEventListener("timeupdate",this.onTimeUpdate),e.addEventListener("play",this.onPlay),e.addEventListener("pause",this.onPause),e.addEventListener("volumechange",this.onVolumeChange),e.addEventListener("loadeddata",this.onLoadedData),e.addEventListener("loadedmetadata",this.onLoadedMetadata),e.addEventListener("resize",this.onResize),e.addEventListener("loadstart",this.onLoadStart),e.addEventListener("suspend",this.onSuspend),e.addEventListener("stalled",this.onStalled),e.addEventListener("waiting",this.onWaiting),e.addEventListener("error",this.onError),e.addEventListener("encrypted",this.onEncrypted)}_removePlaybackNotificationCenterHandlers(e){e.removeEventListener("canplay",this.onCanPlay),e.removeEventListener("durationchange",this.onDurationChange),e.removeEventListener("ended",this.onEnded),e.removeEventListener("timeupdate",this.onTimeUpdate),e.removeEventListener("play",this.onPlay),e.removeEventListener("pause",this.onPause),e.removeEventListener("volumechange",this.onVolumeChange),e.removeEventListener("loadeddata",this.onLoadedData),e.removeEventListener("loadedmetadata",this.onLoadedMetadata),e.removeEventListener("resize",this.onResize),e.removeEventListener("loadstart",this.onLoadStart),e.removeEventListener("suspend",this.onSuspend),e.removeEventListener("stalled",this.onStalled),e.removeEventListener("waiting",this.onWaiting),e.removeEventListener("error",this.onError)}_handleFullScreenChange(t){var i,n;t?null===(i=this._view)||void 0===i||i.classList.add("red5pro-media-container-full-screen"):null===(n=this._view)||void 0===n||n.classList.remove("red5pro-media-container-full-screen"),this.trigger(new be(e.SubscriberEventTypes.FULL_SCREEN_STATE_CHANGE,void 0,t))}_cleanup(){this._playbackNotificationCenter&&this._removePlaybackNotificationCenterHandlers(this._playbackNotificationCenter),this._playbackNotificationCenter=void 0,this._view=void 0}_onCanPlay(t){var i;O(this._name,"[videoelement:event] canplay");const n=null!==(i=this._playbackNotificationCenter)&&void 0!==i?i:t.target,o=this.getControls();o&&o.enable(!0),this.trigger(new be(e.SubscriberEventTypes.PLAYBACK_STATE_CHANGE,void 0,{code:e.PlaybackState.AVAILABLE,state:s.AVAILABLE})),this.trigger(new be(e.SubscriberEventTypes.VOLUME_CHANGE,void 0,{volume:n.volume}))}_onDurationChange(e){var t;O(this._name,"[videoelement:event] durationchange");const i=null!==(t=this._playbackNotificationCenter)&&void 0!==t?t:e.target,n=this.getControls();n&&n.setPlaybackDuration(i.duration),!isNaN(i.duration)&&Number.isFinite(i.duration)&&(this._isVOD=!0)}_onEnded(){O(this._name,"[videoelement:event] ended");const t=this.getControls();t&&t.setState(e.PlaybackState.IDLE),this.trigger(new be(e.SubscriberEventTypes.PLAYBACK_STATE_CHANGE,void 0,{code:e.PlaybackState.IDLE,state:s.IDLE}))}_onTimeUpdate(t){var i;const n=null!==(i=this._playbackNotificationCenter)&&void 0!==i?i:t.target,s=this.getControls();s&&s.setSeekTime(n.currentTime,this.isVOD()?n.duration:void 0),this.trigger(new be(e.SubscriberEventTypes.PLAYBACK_TIME_UPDATE,void 0,{time:n.currentTime,duration:n.duration}))}_onPlay(){O(this._name,"[videoelement:event] play");const t=this.getControls();t&&t.setState(e.PlaybackState.PLAYING),this.trigger(new be(e.SubscriberEventTypes.PLAYBACK_STATE_CHANGE,void 0,{code:e.PlaybackState.PLAYING,state:s.PLAYING}))}_onPause(){O(this._name,"[videoelement:event] pause");const t=this.getControls();t&&t.setState(e.PlaybackState.PAUSED),this.trigger(new be(e.SubscriberEventTypes.PLAYBACK_STATE_CHANGE,void 0,{code:e.PlaybackState.PAUSED,state:s.PAUSED}))}_onVolumeChange(t){var i;O(this._name,"[videoelement:event] volumechange");const n=null!==(i=this._playbackNotificationCenter)&&void 0!==i?i:t.target,s=this.getControls();s&&s.getVolume()!==n.volume&&s.setVolume(n.volume),this.trigger(new be(e.SubscriberEventTypes.VOLUME_CHANGE,void 0,{volume:n.volume}))}_onLoadedData(t){var i,n,s;O(this._name,"[videoelement:event] loadeddata");const o=null!==(i=this._view)&&void 0!==i?i:t.target;this.trigger(new be(e.SubscriberEventTypes.VIDEO_DIMENSIONS_CHANGE,void 0,{width:null!==(n=o.videoWidth)&&void 0!==n?n:0,height:null!==(s=o.videoHeight)&&void 0!==s?s:0}))}_onLoadedMetadata(t){var i,n;O(this._name,"[videoelement:event] loadedmetadata");const s=null!==(i=this._view)&&void 0!==i?i:t.target;this.trigger(new be(e.SubscriberEventTypes.LOADED_METADATA,void 0,{duration:null!==(n=s.duration)&&void 0!==n?n:0}))}_onResize(t){var i,n,s;O(this._name,"[videoelement:event] resize");const o=null!==(i=this._view)&&void 0!==i?i:t.target;this.trigger(new be(e.SubscriberEventTypes.VIDEO_DIMENSIONS_CHANGE,void 0,{width:null!==(n=o.videoWidth)&&void 0!==n?n:0,height:null!==(s=o.videoHeight)&&void 0!==s?s:0}))}_onLoadStart(){O(this._name,"[videoelement:event] loadstart")}_onSuspend(){O(this._name,"[videoelement:event] suspend")}_onStalled(){O(this._name,"[videoelement:event] stalled")}_onWaiting(){O(this._name,"[videoelement:event] waiting")}_onEncrypted(){O(this._name,"[videoelement:event] encrypted")}_onError(t){O(this._name,"[videoelement:event] error"),this.trigger(new be(e.SubscriberEventTypes.CONNECT_FAILURE,void 0,{error:t.message}))}async attemptAutoplay(t=!1){try{await this.play(),this.isMuted()&&this.trigger(new be(e.SubscriberEventTypes.AUTO_PLAYBACK_MUTED,void 0,{element:this._view}))}catch(i){t?(this.mute(),this.attemptAutoplay(t)):this.trigger(new be(e.SubscriberEventTypes.AUTO_PLAYBACK_FAILURE,void 0,{error:i.message?i.message:i,element:this._view}))}}async play(){var e,t;if(O(this._name,"[videoelement:action] play"),!(null===(e=this._view)||void 0===e?void 0:e.paused))return O(this._name,"[videoelement:action] play (ALREADY PLAYING)"),!0;try{return await(null===(t=this._view)||void 0===t?void 0:t.play()),!0}catch(e){throw H(this._name,"[videoelement:action] play (FAULT) - "+e.message),e}}async pause(){var e;O(this._name,"[videoelement:action] pause");try{return await(null===(e=this._view)||void 0===e?void 0:e.pause()),!0}catch(e){k(this._name,"[videoelement:action] pause (CATCH::FAULT) - "+e.message)}return!1}async resume(){var e;O(this._name,"[videoelement:action] resume");try{return await(null===(e=this._view)||void 0===e?void 0:e.play()),!0}catch(e){k(this._name,"[videoelement:action] resume (CATCH::FAULT) - "+e.message)}return!1}async stop(){var e;O(this._name,"[videoelement:action] stop");try{return await(null===(e=this._view)||void 0===e?void 0:e.pause()),!0}catch(e){k(this._name,"[videoelement:action] stop (CATCH::FAULT) - "+e.message)}return!1}mute(){this._view&&(this._view.muted=!0);const e=this.getControls();e&&e.setMutedState(!0)}unmute(){this._view&&(this._view.muted=!1);const e=this.getControls();e&&e.setMutedState(!1)}setVolume(e){this.unmute(),this._view&&(this._view.volume=e)}getVolume(){var e,t;return null!==(t=null===(e=this._view)||void 0===e?void 0:e.volume)&&void 0!==t?t:0}seekTo(e,t=void 0){this._view&&(this._view.currentTime=t?e*t:e)}toggleFullScreen(e){try{(e||this._view)&&ie.toggleFullScreen(null!=e?e:this._view)}catch(e){}}async unpublish(){var e;try{await this.stop(),null===(e=this._view)||void 0===e||e.dispatchEvent(new Event("ended"))}catch(e){}}disconnect(){this._cleanup()}isVOD(){return this._isVOD}isMuted(){var e,t;return null!==(t=null===(e=this._view)||void 0===e?void 0:e.muted)&&void 0!==t&&t}getControls(){}}const kt="WHEPClient",Ht=Ct,Mt=e=>O(kt,e),Ut=e=>H(kt,e),Bt=e=>k(kt,e);class Vt extends Lt{constructor(e,t,i){super(),this._videoMuted=!0,this._audioMuted=!0;const n=e?se(e):Ht,s=i||Ht,o={...s,...n,endpoint:e,mediaElementId:t?t.id:s.mediaElementId};this._videoUnmuteHandler=this._onVideoUnmute.bind(this),this._audioUnmuteHandler=this._onAudioUnmute.bind(this),e&&this.internalInit(o)}async internalInit(e){await this.init(e),await this.subscribe()}async _runMuteCheck(){var e,t,i;if(this.getPeerConnection())try{let n=this._videoMuted,s=this._audioMuted;const o=await(null===(e=this.getPeerConnection())||void 0===e?void 0:e.getStats());if(null==o||o.forEach((e=>{const{type:t,kind:i,bytesReceived:o}=e;"inbound-rtp"!==t&&"inboundrtp"!==t||("video"===i?n=o<=0:"audio"===i&&(s=o<=0))})),n===this._videoMuted&&s===this._audioMuted)return;this._videoMuted=n,this._audioMuted=s;const r={data:{streamingMode:(t=!this._videoMuted,i=!this._audioMuted,t&&i?Nt.FULL:t?Nt.VIDEO:i?Nt.AUDIO:Nt.EMPTY),method:"onMetaData"},type:"metadata",method:"onMetaData",eventTimestamp:(new Date).getTime()};this._onMetaData(r)}catch(e){Ut(e.message||e)}}_onVideoUnmute(e){const t=e.target;null==t||t.removeEventListener("unmute",this._videoUnmuteHandler);const i=setTimeout((async()=>{clearTimeout(i),this._runMuteCheck()}),1e3)}_onAudioUnmute(e){const t=e.target;null==t||t.removeEventListener("unmute",this._audioUnmuteHandler);const i=setTimeout((async()=>{clearTimeout(i),this._runMuteCheck()}),1e3)}_attachSourceHandler(e){this._sourceHandler=new Ot(e,this.getType())}_glomTrigger(e){e.on("*",(e=>{const{type:t,data:i}=e;this.trigger(new be(t,this,i))}))}_playIfAutoplaySet(e,t){var i;if(e&&t){const{muteOnAutoplayRestriction:n}=e;ie.hasAttributeDefined(t,"autoplay")&&(null===(i=this._sourceHandler)||void 0===i||i.attemptAutoplay(n))}}addMediaStreamToPlayback(e,t){var i;!this._playbackView&&e&&(this._playbackView=new wt(e)),null===(i=this._playbackView)||void 0===i||i.attachStream(t)}async requestOffer(t){var i;Mt("[requestoffer]");const{iceTransport:n,maintainStreamVariant:s,videoEncoding:o,audioEncoding:r,connectionParams:a,mungeOffer:l}=this._options;t.addTransceiver("video",{direction:"recvonly"}),t.addTransceiver("audio",{direction:"recvonly"});const d={transport:n,doNotSwitch:s};o&&o!==e.PlaybackVideoEncoder.NONE&&(d.videoEncoding=o),r&&r!==e.PlaybackAudioEncoder.NONE&&(d.audioEncoding=r);const h=null!=a?a:{},c=await t.createOffer(),u=await(null===(i=this._whipWhepService)||void 0===i?void 0:i.postSDPOffer(c.sdp,{...h,...d},!1));if(!u)throw Ut("Failed to get offer from WHEP"),new Error("Failed to get offer from WHEP");const{sdp:p}=u;let _=p;return l&&(Mt(`[MUNGE:before] offer: ${_}`),_=l(_),Mt(`[MUNGE:after] offer: ${_}`)),_}async requestAnswer(e){const{mungeAnswer:t}=this._options;let i=(await e.createAnswer()).sdp;return t&&(Mt(`[MUNGE:before] answer: ${i}`),i=t(i),Mt(`[MUNGE:after] answer: ${i}`)),i}async sendAnswer(e){var t;const{connectionParams:i}=this._options;return await(null===(t=this._whipWhepService)||void 0===t?void 0:t.postSDPAnswer(e,i))}async postCandidateFragments(e){var t;const{connectionParams:i}=this._options,n=Be(e,void 0,!0);return await(null===(t=this._whipWhepService)||void 0===t?void 0:t.trickle(n,i))}async initPubNub(e){var t;try{const t=new _t;this._pubnubClient=t,this._pubnubClient.on("*",(e=>{this.trigger(e)})),await t.init(e)}catch(e){return e(null!==(t=e.message)&&void 0!==t?t:"Failed to initialize PubNub."),!1}return!0}async deinitPubNub(){var e,t;try{await(null===(e=this._pubnubClient)||void 0===e?void 0:e.destroy()),this._pubnubClient=void 0}catch(e){return e(null!==(t=e.message)&&void 0!==t?t:"Failed to deinitialize PubNub."),!1}return!0}_evaluateRenegotiationPolicy(t){const{renegotiationPolicy:i}=this._options;if(i){const{type:n}=i,s=n.toLowerCase();Mt(`[evaluateRenegotiationPolicy] - Type: ${t}, Renegotiation Policy: ${i.type}`),(t===Pe.CONNECTION_HEALTH_STATE_REGRESSION&&"regression"===s||t===Pe.CONNECTION_HEALTH_ICE_TIMEOUT&&"timeout"===s||t===e.SubscriberEventTypes.CONNECTION_CLOSED&&"disconnect"===s)&&this._reconnect()}}async _reconnect(){var t,i;Mt("[reconnect]"),this.trigger(new be(e.SubscriberEventTypes.RECONNECT_START,this));try{await this.unsubscribe(!0),await this.init(this._options),await this.subscribe()}catch(n){Ut(null!==(t=n.message)&&void 0!==t?t:"Could not reconnect."),this.trigger(new be(e.SubscriberEventTypes.RECONNECT_FAILURE,this,{error:null!==(i=n.message)&&void 0!==i?i:"Could not reconnect."}))}}async init(e){var t,i,n;this._options={...Ht,...e},this._options.subscriptionId=this._options.subscriptionId||`subscriber-${Math.floor(65536*Math.random()).toString(16)}`;const s=oe(this._options,"whep"),{includeDataChannel:o,disableProxy:r}=this._options;return this._whipWhepService=new Ye(`${s}?requestId=${this._options.subscriptionId}`,o,r),this._messageTransport=this._whipWhepService,((null===(t=this._options)||void 0===t?void 0:t.stats)||(null===(i=this._options)||void 0===i?void 0:i.renegotiationPolicy))&&(!this._options.stats&&this._options.renegotiationPolicy&&(this._options.stats=yt),this.monitorStats(this._options.stats,this._options.renegotiationPolicy)),(null===(n=this._options)||void 0===n?void 0:n.pubnub)&&await this.initPubNub(this._options.pubnub),this}async subscribe(){var t,i,n,s,o,r,a,l,d;const{connectionParams:h,rtcConfiguration:c,includeDataChannel:u,signalingSocketOnly:p,enableChannelSignaling:_,dataChannelConfiguration:g}=this._options;try{const d=h||{},m=await(null===(t=this._whipWhepService)||void 0===t?void 0:t.getOptions(d));this.trigger(new be(e.SubscriberEventTypes.CONNECT_SUCCESS,this,null===(i=this._whipWhepService)||void 0===i?void 0:i.getUrl()));const E=!!(null===(n=this._options)||void 0===n?void 0:n.rtcConfiguration)&&Array.isArray(this._options.rtcConfiguration.iceServers)&&this._options.rtcConfiguration.iceServers.length>0;(null==m?void 0:m.links)&&!E&&(this._options.rtcConfiguration={...c,iceServers:m.links}),(null==m?void 0:m.origin)&&this.trigger(new be(e.RTCSubscriberEventTypes.HOST_ENDPOINT_CHANGED,this,{endpoint:m.origin})),(null==m?void 0:m.statisticsEndpoint)&&this._onStatisticsEndpointChange(m.statisticsEndpoint);const b=u||_||p?g:void 0;this._peerConnectionHelper=new Pt({onUnpublish:this._onUnpublish.bind(this),onStreamUnavailable:this._onStreamUnavailable.bind(this),onSubscriberStatus:this._onSubscriberStatus.bind(this),onStreamSwitchComplete:this._onStreamSwitchComplete.bind(this),onDataChannelError:this._onDataChannelError.bind(this),onSendReceived:this._onSendReceived.bind(this),onMetaData:this._onMetaData.bind(this),onConnectionClosed:this._onConnectionClosed.bind(this),onDataChannelOpen:this._onDataChannelOpen.bind(this),onDataChannelClose:this._onDataChannelClose.bind(this),onDataChannelMessage:this._onDataChannelMessage.bind(this),onPeerConnectionOpen:this._onPeerConnectionOpen.bind(this),onPeerConnectionFail:this._onPeerConnectionFail.bind(this),onPeerConnectionClose:this._onPeerConnectionClose.bind(this),onIceCandidate:this._onIceCandidate.bind(this),onSDPSuccess:this._onSDPSuccess.bind(this),onSDPError:this._onSDPError.bind(this),onStatisticsEndpointChange:this._onStatisticsEndpointChange.bind(this)}),await this._peerConnectionHelper.setUpWithPeerConfiguration(this._options.rtcConfiguration,b),null===(s=this.getPeerConnection())||void 0===s||s.addEventListener("track",(t=>{const{buffer:i}=this._options;Mt("[peerconnection.ontrack]");const{streams:n,track:s,receiver:o,transceiver:r}=t;o.jitterBufferDelayHint=i,this.trigger(new be(e.RTCSubscriberEventTypes.TRACK_ADDED,this,{streams:n,track:s,receiver:o,transceiver:r})),this._mediaStream=n&&n.length>0?n[0]:void 0,"video"===s.kind?(this._videoMuted=s.muted,s.muted&&s.addEventListener("unmute",this._videoUnmuteHandler)):"audio"===s.kind&&(this._audioMuted=s.muted,s.muted&&s.addEventListener("unmute",this._audioUnmuteHandler)),this._runMuteCheck()})),this.trigger(new be(e.RTCSubscriberEventTypes.PEER_CONNECTION_AVAILABLE,this,this.getPeerConnection())),this.trigger(new be(e.RTCSubscriberEventTypes.OFFER_START,this));const S=await this.requestOffer(this.getPeerConnection()),C=new RTCSessionDescription({type:"offer",sdp:S});await(null===(o=this.getPeerConnection())||void 0===o?void 0:o.setRemoteDescription(C)),this.trigger(new be(e.RTCSubscriberEventTypes.OFFER_END,this)),this.trigger(new be(e.RTCSubscriberEventTypes.ANSWER_START,this));const T=await this.requestAnswer(this.getPeerConnection()),y=(v=T).includes("stereo=1")?v:v.replace("useinbandfec=1","useinbandfec=1;stereo=1;sprop-stereo=1"),f=new RTCSessionDescription({type:"answer",sdp:y});await(null===(r=this.getPeerConnection())||void 0===r?void 0:r.setLocalDescription(f)),await this.sendAnswer(y),this.trigger(new be(e.RTCSubscriberEventTypes.ANSWER_END,this));const w=await this._peerConnectionHelper.waitToGatherIce(),{sdp:A}=w;return await this.postCandidateFragments(A),this.trigger(new be(e.RTCSubscriberEventTypes.ICE_TRICKLE_COMPLETE,this)),this._mediaStream&&(this.trigger(new be(e.RTCSubscriberEventTypes.ON_ADD_STREAM,this,this._mediaStream)),this.addMediaStreamToPlayback(this._options.mediaElementId,this._mediaStream)),(null===(a=this._playbackView)||void 0===a?void 0:a.view)&&this._attachSourceHandler(this._playbackView.view),this._sourceHandler&&this._glomTrigger(this._sourceHandler),this._playIfAutoplaySet(this._options,null===(l=this._playbackView)||void 0===l?void 0:l.view),this}catch(t){throw Ut(null!==(d=t.message)&&void 0!==d?d:"Could not subscribe."),t instanceof $e?this._onStreamUnavailable(t):this.trigger(new be(e.SubscriberEventTypes.CONNECT_FAILURE,this,t)),this._options.maintainConnectionOnSubscribeErrors||this.unsubscribe(!0),t}var v}async unsubscribe(t=!1){var i;Mt("[unsubscribe]"),this._peerConnectionHelper&&await this._peerConnectionHelper.tearDown(),this._whipWhepService&&await this._whipWhepService.tearDown(null,t),this._sourceHandler&&this._sourceHandler.disconnect(),this._pubnubClient&&await this.deinitPubNub(),this.unmonitorStats(),null===(i=this._playbackView)||void 0===i||i.detachStream(),this._playbackView=void 0,this._pubnubClient=void 0,this._whipWhepService=void 0,this._messageTransport=void 0,this._peerConnectionHelper=void 0,this._sourceHandler=void 0,this._mediaStream=void 0,this.trigger(new be(e.SubscriberEventTypes.SUBSCRIBE_STOP,this))}send(e,t){var i;return null===(i=this.getMessageTransport())||void 0===i?void 0:i.post({send:{method:e,data:"string"==typeof t?JSON.parse(t):t}})}async sendPubNub(e,t){return this._pubnubClient?await this._pubnubClient.publishMessage(e,t):(Ut("PubNub client not initialized."),!1)}async subscribePubNub(e,t){return this._pubnubClient?await this._pubnubClient.subscribe(e,t):(Ut("PubNub client not initialized."),!1)}async unsubscribePubNub(e){return this._pubnubClient?await this._pubnubClient.unsubscribe(e):(Ut("PubNub client not initialized."),!1)}async callServer(e,t){var i;const n="switchStreams"===e,{app:s,streamName:o}=this._options;if(n){const{path:i}=t[0];this._requestedStreamSwitch=i,Mt(`[callServer:switch]:: ${e}, ${s}/${o} -> ${i}`)}return null===(i=this.getMessageTransport())||void 0===i?void 0:i.postAsync({callAdapter:{method:e,arguments:t}})}sendLog(e,t){var i;try{const n=Object.keys(L).find((t=>t.toLowerCase()===e.toLowerCase()))?e:L.DEBUG,s="string"==typeof t?t:JSON.stringify(t);null===(i=this.getMessageTransport())||void 0===i||i.post({log:n.toUpperCase(),message:s})}catch(e){const t=e.message||e;Ut("Could not send log to server. Message parameter expected to be String or JSON-serializable object."),Ut(t)}}enableStandby(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteAudio:!0,muteVideo:!0}})}disableStandby(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteAudio:!1,muteVideo:!1}})}muteAudio(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteAudio:!0}})}unmuteAudio(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteAudio:!1}})}muteVideo(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteVideo:!0}})}unmuteVideo(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteVideo:!1}})}get options(){return this._options}getOptions(){return this._options}getPeerConnection(){var e;return null===(e=this._peerConnectionHelper)||void 0===e?void 0:e.connection}getDataChannel(){var e;return null===(e=this._peerConnectionHelper)||void 0===e?void 0:e.dataChannel}getMediaStream(){return this._mediaStream}getMessageTransport(){return this._messageTransport}getPubNubClient(){return this._pubnubClient}getPlayer(){var e;return null===(e=this._playbackView)||void 0===e?void 0:e.view}play(){Mt("[play]"),this._sourceHandler?this._sourceHandler.play():Bt("Cannot play without a Source Handler.")}pause(){Mt("[pause]"),this._sourceHandler?this._sourceHandler.pause():Bt("Cannot pause without a Source Handler.")}resume(){Mt("[resume]"),this._sourceHandler?this._sourceHandler.resume():Bt("Cannot resume without a Source Handler.")}stop(){Mt("[stop]"),this._sourceHandler?this._sourceHandler.stop():Bt("Cannot stop without a Source Handler.")}setVolume(e){Mt("[setVolume]"),this._sourceHandler?this._sourceHandler.setVolume(e):Bt("Cannot set volume without a Source Handler.")}getVolume(){var e,t,i;return Mt("[getVolume]"),this._sourceHandler?this._sourceHandler.getVolume():(Bt("Cannot get volume without a Source Handler."),null!==(i=null===(t=null===(e=this._playbackView)||void 0===e?void 0:e.view)||void 0===t?void 0:t.volume)&&void 0!==i?i:0)}mute(){Mt("[mute]"),this._sourceHandler?this._sourceHandler.mute():Bt("Cannot mute without a Source Handler.")}unmute(){Mt("[unmute]"),this._sourceHandler?this._sourceHandler.unmute():Bt("Cannot unmute without a Source Handler.")}seekTo(e){Mt("[seekTo]"),this._sourceHandler?this._sourceHandler.seekTo(e):Bt("Cannot seek without a Source Handler.")}toggleFullScreen(){Mt("[toggleFullScreen]"),this._sourceHandler?this._sourceHandler.toggleFullScreen():Bt("Cannot toggle full screen without a Source Handler.")}monitorStats(e,t){Mt(`[monitorStats]:: Stats: ${e?JSON.stringify(e):"undefined"}`),Mt(`[monitorStats]:: Renegotiation Policy: ${t?JSON.stringify(t):"undefined"}`);const{host:i,endpoint:n,app:s,streamName:o,subscriptionId:r,connectionParams:a}=this._options,l=null!=e?e:pe;return this._statisticsConfiguration={...l,host:i,app:s,hostEndpoint:n,streamName:o,subscriptionId:r,connectionParams:a},this._statsMonitor?Bt("Cannot monitor stats without a Peer Connection. Please call `init` before calling `monitorStats`."):this._statsMonitor=new Dt(this._statisticsConfiguration,{onStatsReport:this._onStatsReport.bind(this),getPeerConnection:this.getPeerConnection.bind(this),getMessageTransport:this.getMessageTransport.bind(this),on:this.on.bind(this),off:this.off.bind(this),trigger:this.trigger.bind(this),emit:this.emit.bind(this)},t),this}unmonitorStats(){return this._statsMonitor&&this._statsMonitor.dispose(),this._statsMonitor=void 0,this._statisticsConfiguration=void 0,this}_onUnpublish(){Mt("[unpublish]"),this.trigger(new be(e.SubscriberEventTypes.PLAY_UNPUBLISH,this)),this._sourceHandler&&this._sourceHandler.unpublish()}_onStreamUnavailable(t){Mt(`Stream ${this._options.streamName} does not exist.`),Mt("[onstreamunavailable]: "+JSON.stringify(t,null,2)),this.trigger(new be(e.SubscriberEventTypes.SUBSCRIBE_INVALID_NAME,this))}_onDataChannelError(t,i){Ut(`Data channel error: ${i}`),this.trigger(new be(e.RTCSubscriberEventTypes.DATA_CHANNEL_ERROR,this,{dataChannel:t,error:i}))}_onSendReceived(t,i){Mt(`Send received: ${t} ${JSON.stringify(i)}`),"onMetaData"===t?this._onMetaData(i):this.trigger(new be(e.SubscriberEventTypes.SUBSCRIBE_SEND_INVOKE,this,{methodName:t,data:i}))}_onStreamSwitchComplete(){Mt("[streamswitch::complete]");const t=this._requestedStreamSwitch;this.trigger(new be(e.RTCSubscriberEventTypes.SUBSCRIBE_STREAM_SWITCH,this,{path:t})),this._requestedStreamSwitch=void 0}_onMetaData(t){const{orientation:i,streamingMode:n}=t,s=this._streamingMode;void 0!==i&&i!==this._orientation&&(this._orientation=i,this.trigger(new be(e.SubscriberEventTypes.ORIENTATION_CHANGE,this,{orientation:parseInt(i,10),viewElement:this._playbackView?this._playbackView.view:void 0}))),n&&void 0!==n&&n!==s&&(this._streamingMode=n,this.trigger(new be(e.SubscriberEventTypes.STREAMING_MODE_CHANGE,this,{streamingMode:n,previousStreamingMode:s,viewElement:this._playbackView?this._playbackView.view:void 0}))),this.trigger(new be(e.SubscriberEventTypes.SUBSCRIBE_METADATA,this,t))}_onConnectionClosed(){Mt("Connection closed"),this.unsubscribe(!0),this.trigger(new be(e.SubscriberEventTypes.CONNECTION_CLOSED,this))}_onDataChannelOpen(t){Mt(`Data channel opened: ${t.label}`),this.trigger(new be(e.RTCSubscriberEventTypes.DATA_CHANNEL_OPEN,this,{dataChannel:t})),this.trigger(new be(e.RTCSubscriberEventTypes.DATA_CHANNEL_AVAILABLE,this,{name:t.label,dataChannel:t})),this._messageTransport=this._peerConnectionHelper,this.trigger(new Se(e.MessageTransportStateEventTypes.CHANGE,this,{controller:this,transport:this._messageTransport})),this.trigger(new be(e.SubscriberEventTypes.SUBSCRIBE_START,this))}_onDataChannelClose(t){Mt(`Data channel closed: ${t.label}`),this.trigger(new be(e.RTCSubscriberEventTypes.DATA_CHANNEL_CLOSE,this,{dataChannel:t}))}_onDataChannelMessage(t,i){Mt(`Data channel message: ${i.data}`),this.trigger(new be(e.RTCSubscriberEventTypes.DATA_CHANNEL_MESSAGE,this,{dataChannel:t,message:i}))}_onPeerConnectionOpen(){var t;Mt("Peer connection opened"),this.trigger(new be(e.RTCSubscriberEventTypes.PEER_CONNECTION_OPEN,this,this.getPeerConnection())),(null===(t=this._options)||void 0===t?void 0:t.includeDataChannel)||this.trigger(new be(e.SubscriberEventTypes.SUBSCRIBE_START,this))}_onPeerConnectionFail(){Ut("Peer connection failed"),this.trigger(new be(e.SubscriberEventTypes.SUBSCRIBE_FAIL,this))}_onPeerConnectionClose(t){Mt(`Peer connection closed: ${t.type}`),this._evaluateRenegotiationPolicy(e.SubscriberEventTypes.CONNECTION_CLOSED)}_onIceCandidate(t){Mt(`ICE candidate: ${t.candidate}`),this.trigger(new be(e.RTCSubscriberEventTypes.CANDIDATE_CREATE,this,{candidate:t}))}_onPeerConnectionTrackAdd(e){Mt(`Peer connection track added: ${e.id}`)}_onSubscriberStatus(e){Mt(`Subscriber status: ${JSON.stringify(e)}`)}_onSDPSuccess(){Mt("SDP success")}_onSDPError(e){Ut(`SDP error: ${e}`)}_onStatisticsEndpointChange(t){Mt(`Statistics endpoint changed: ${t}`),this._statsMonitor&&this._statsMonitor.updateEndpoint(t),this.trigger(new be(e.SubscriberEventTypes.STATISTICS_ENDPOINT_CHANGE,this,{statisticsEndpoint:t}))}_onStatsReport(t,i){this.trigger(new be(e.RTCSubscriberEventTypes.STATS_REPORT,this,{connection:t,report:i}))}on(e,t){super.on(e,t)}off(e,t){super.off(e,t)}trigger(e){super.trigger(e)}emit(e,t){this.trigger(new be(e,this,t)),this._evaluateRenegotiationPolicy(e)}getType(){return"RTC"}}class Ft extends Ot{constructor(e,t){super(e,t),this._playingStarted=!1,this.onOrientation=this._onOrientationMetadata.bind(this),this.onStreamingMode=this._onStreamingModeMetadata.bind(this),ie.onOrientationMetadata(this._view,this.onOrientation),ie.onStreamingModeMetadata(this._view,this.onStreamingMode),this.onPlaying=this._onPlaying.bind(this),this.onSourceError=this._onSourceError.bind(this),this._view.addEventListener("playing",this.onPlaying)}addSource(e){this._source=ie.createElement("source"),this._source.type="application/x-mpegURL",this._source.src=e,this._view.firstChild?this._view.insertBefore(this._source,this._view.firstChild):this._view.appendChild(this._source),this._source.addEventListener("error",this.onSourceError)}_onPlaying(){this._playingStarted||this.trigger(new be(e.SubscriberEventTypes.SUBSCRIBE_START,this._view)),this._playingStarted=!0}_onSourceError(t){O(this._name,"[source:event] error"),this.trigger(new be(e.SubscriberEventTypes.CONNECT_FAILURE,void 0,t))}_onOrientationMetadata(t){const{orientation:i}=t,n=parseInt(i,10);i&&this._orientation!==n&&(O(this._name,"Metadata received: "+JSON.stringify(t,null,2)),this._orientation=n,this.trigger(new be(e.SubscriberEventTypes.ORIENTATION_CHANGE,{orientation:this._orientation,viewElement:this._view})),this.trigger(new be(e.SubscriberEventTypes.SUBSCRIBE_METADATA,void 0,t)))}_onStreamingModeMetadata(t){const{streamingMode:i}=t,n=this._streamingMode;i&&n!==i&&(O(this._name,"Metadata received: "+JSON.stringify(t,null,2)),this._streamingMode=i,this.trigger(new be(e.SubscriberEventTypes.STREAMING_MODE_CHANGE,void 0,{streamingMode:this._streamingMode,previousStreamingMode:n,viewElement:this._view})),this.trigger(new be(e.SubscriberEventTypes.SUBSCRIBE_METADATA,void 0,t)))}_cleanup(){this._view&&this._view.removeEventListener("playing",this.onPlaying),this._source&&(this._source.removeEventListener("error",this.onSourceError),this._view.removeChild(this._source),this._source=void 0),super._cleanup()}}const $t="HLSSubscriber",Gt=e=>O($t,e),xt=e=>k($t,e);class Wt extends Lt{constructor(){super()}_glomTrigger(e){e.on("*",(e=>{const{type:t,data:i}=e;this.trigger(new be(t,this,i))}))}_playIfAutoplaySet(e,t){var i;if(e&&t){const{muteOnAutoplayRestriction:n}=e;ie.hasAttributeDefined(t,"autoplay")&&(null===(i=this._sourceHandler)||void 0===i||i.attemptAutoplay(n))}}async init(e){if(!ie.supportsHLS())throw new Error("Native HLS playback is not supported on this browser.");return this._options={...Tt,...e},this}async subscribe(){var t;try{const i=/^http(|s).*\.m3u8/g,{endpoint:n,mediaElementId:s}=this._options;return this._fileURL=n&&n.match(i)?n:(e=>{const{host:t,protocol:i,port:n,app:s,streamName:o,connectionParams:r}=e,a="ws"===i||"http"===i?"http":"https",l=`${a}://${t}:${n||("http"===a?5080:443)}/${s}/${o}.m3u8`;if(r)return`${l}?${Object.entries(r).map((([e,t])=>`${e}=${t}`)).join("&")}`;return l})(this._options),!this._playbackView&&s&&(this._playbackView=new wt(s),this._sourceHandler=new Ft(this._playbackView.view,this.getType()),this._sourceHandler.addSource(this._fileURL),this._glomTrigger(this._sourceHandler)),this.trigger(new be(e.SubscriberEventTypes.CONNECT_SUCCESS,this,this._fileURL)),this._playIfAutoplaySet(this._options,null===(t=this._playbackView)||void 0===t?void 0:t.view),this}catch(t){throw t(t.message),this.trigger(new be(e.SubscriberEventTypes.CONNECT_FAILURE,this,t.message)),t}}async unsubscribe(){var t;return this._sourceHandler&&this._sourceHandler.disconnect(),null===(t=this._playbackView)||void 0===t||t.detachStream(),this._playbackView=void 0,this._sourceHandler=void 0,this.trigger(new be(e.SubscriberEventTypes.SUBSCRIBE_STOP,this)),this}play(){Gt("[play]"),this._sourceHandler?this._sourceHandler.play():xt("Cannot play without a Source Handler.")}pause(){Gt("[pause]"),this._sourceHandler?this._sourceHandler.pause():xt("Cannot pause without a Source Handler.")}resume(){Gt("[resume]"),this._sourceHandler?this._sourceHandler.resume():xt("Cannot resume without a Source Handler.")}stop(){Gt("[stop]"),this._sourceHandler?this._sourceHandler.stop():xt("Cannot stop without a Source Handler.")}setVolume(e){Gt("[setVolume]"),this._sourceHandler?this._sourceHandler.setVolume(e):xt("Cannot set volume without a Source Handler.")}getVolume(){var e,t,i;return Gt("[getVolume]"),this._sourceHandler?this._sourceHandler.getVolume():(xt("Cannot get volume without a Source Handler."),null!==(i=null===(t=null===(e=this._playbackView)||void 0===e?void 0:e.view)||void 0===t?void 0:t.volume)&&void 0!==i?i:0)}mute(){Gt("[mute]"),this._sourceHandler?this._sourceHandler.mute():xt("Cannot mute without a Source Handler.")}unmute(){Gt("[unmute]"),this._sourceHandler?this._sourceHandler.unmute():xt("Cannot unmute without a Source Handler.")}seekTo(e){Gt("[seekTo]"),this._sourceHandler?this._sourceHandler.seekTo(e):xt("Cannot seek without a Source Handler.")}toggleFullScreen(){Gt("[toggleFullScreen]"),this._sourceHandler?this._sourceHandler.toggleFullScreen():xt("Cannot toggle full screen without a Source Handler.")}getPlayer(){var e;return null===(e=this._playbackView)||void 0===e?void 0:e.view}get options(){return this._options}getOptions(){return this._options}get fileURL(){return this._fileURL}getFileURL(){return this._fileURL}getType(){return"HLS"}}const Kt={baseURL:void 0,fullURL:void 0,hlsjsRef:void 0,hlsElement:void 0,usePlaybackControlsUI:!0,options:{debug:!1,backBufferLength:0}},jt={...Ct,liveSeek:Kt};class zt extends U{trigger(e){super.trigger(e)}on(e,t){super.on(e,t)}off(e,t){super.off(e,t)}}var Jt,Yt;!function(e){e.SEEK_START="Seek.Start",e.SEEK_END="Seek.End"}(Jt||(Jt={})),function(e){e.CHANGE="Slider.Change",e.CHANGE_START="Slider.Change.Start",e.CHANGE_COMPLETE="Slider.Change.Complete"}(Yt||(Yt={}));class qt extends me{constructor(e,t,i){super(e,i),this._slider=t}get slider(){return this._slider}}const{createElement:Xt,addGlobalEventListener:Qt,removeGlobalEventListener:Zt,globalUnassign:ei,getAssignedValue:ti,globalAssign:ii}=ie,ni="ControlSlider",si="r5_liveseek_event_owner";class oi extends U{constructor(e){super(),this._value=0,this._disabled=!1,this._eventStartPosition=0,this.debug=e=>O(ni,e),this.warn=e=>k(ni,e),this.name=[ni,e].join("::"),this.debug("[init]"),this._container=Xt("div"),this._button=this.createButton(),this._track=this.createTrack(),this._progressBar=this.createProgressBar(),this._container.appendChild(this._track),this._container.appendChild(this._progressBar),this._container.appendChild(this._button),this._layout(),this._mouseupHandler=this._mouseup.bind(this),this._mousedownHandler=this._mousedown.bind(this),this._mousemoveHandler=this._mousemove.bind(this),this._touchupHandler=this._touchproxy.bind(this),this._touchdownHandler=this._touchproxy.bind(this),this._touchmoveHandler=this._touchproxy.bind(this),this._updateHandlers(this._disabled)}_touchproxy(e){var t,i,n,s;const o=e;this.debug(`${o.type} touches: ${(null===(t=o.changedTouches)||void 0===t?void 0:t.length)||0}`);try{o.preventDefault()}catch(e){this.warn("Failed to prevent default on touch event.")}if(!o.touches||o.touches.length>1||"touchend"===o.type&&o.touches.length>0)return;let r,a="";const l=o.target||document.body;switch(o.type){case"touchstart":a="mousedown",r=null===(i=o.changedTouches)||void 0===i?void 0:i[0];break;case"touchmove":a="mousemove",r=null===(n=o.changedTouches)||void 0===n?void 0:n[0];break;case"touchend":a="mouseup",r=null===(s=o.changedTouches)||void 0===s?void 0:s[0]}if(r&&a){const e=new MouseEvent(a,{bubbles:!0,cancelable:!0,view:l.ownerDocument.defaultView,screenX:r.screenX,screenY:r.screenY,clientX:r.clientX,clientY:r.clientY,ctrlKey:o.ctrlKey,altKey:o.altKey,shiftKey:o.shiftKey,metaKey:o.metaKey,button:0,relatedTarget:null});l.dispatchEvent(e)}}_mouseup(){this._eventStartPosition=0,ei(si),Zt("mousemove",this._mousemoveHandler),Zt("mouseup",this._mouseupHandler),Zt("touchmove",this._touchmoveHandler),Zt("touchend",this._touchupHandler),this.trigger(new qt(Yt.CHANGE_COMPLETE,this))}_mousemove(e){if(ti(si)!==this.name)return;this.debug(`[mousemove] ${this.name}`);const t=e.clientX-this._eventStartPosition,i=this._button.parentNode.getBoundingClientRect();let n=this._eventStartPosition+t-i.left;n=Math.max(0,n),n=Math.min(n,i.width);const s=n/i.width;this.trigger(new qt(Yt.CHANGE,this,s))}_mousedown(e){this._eventStartPosition=e.clientX,this.trigger(new qt(Yt.CHANGE_START,this)),ii(si,this.name),Qt("mousemove",this._mousemoveHandler),Qt("mouseup",this._mouseupHandler),Qt("touchmove",this._touchmoveHandler),Qt("touchend",this._touchupHandler)}_updateHandlers(e){this._eventStartPosition=0,e?(this._track.removeEventListener("click",this._mousemoveHandler),this._progressBar.removeEventListener("click",this._mousemoveHandler),this._button.removeEventListener("mousedown",this._mousedownHandler),Zt("mousemove",this._mousemoveHandler),Zt("mouseup",this._mouseupHandler),Zt("touchmove",this._touchmoveHandler),Zt("touchend",this._touchupHandler),this._track.classList.add("red5pro-media-slider-disabled"),this._progressBar.classList.add("red5pro-media-slider-disabled"),this._button.classList.add("red5pro-media-slider-disabled")):(this._track.addEventListener("click",this._mousemoveHandler),this._progressBar.addEventListener("click",this._mousemoveHandler),this._button.addEventListener("mousedown",this._mousedownHandler),this._button.addEventListener("touchstart",this._touchdownHandler),this._track.classList.remove("red5pro-media-slider-disabled"),this._progressBar.classList.remove("red5pro-media-slider-disabled"),this._button.classList.remove("red5pro-media-slider-disabled"))}_layout(){const e=this._progressBar.parentNode.clientWidth*this._value;this._progressBar.style.width=e+"px",this._button.style.left=e-.5*this._button.clientWidth+"px"}createButton(){const e=Xt("span");return e.classList.add("red5pro-media-slider-button"),e}createProgressBar(){const e=Xt("span");return e.classList.add("red5pro-media-slider-progress"),e}createTrack(){const e=Xt("span");return e.classList.add("red5pro-media-slider-track"),e}get value(){return this._value}set value(e){this._value=e,this._layout()}get disabled(){return this._disabled}set disabled(e){this._disabled=e,this._updateHandlers(e)}get view(){return this._container}}const{createElement:ri,isTouchEnabled:ai,isPossiblySafari:li}=ie,di=e=>O("PlaybackControls",e);class hi extends zt{constructor(t,i){super(),this._state=e.PlaybackState.IDLE,this._mutedState=!1,this._resumeAfterSeek=!1,this._playbackDuration=0,this._volumeValue=1,this._player=t,this._container=i,this._onPlayPauseClickBound=this._onPlayPauseClick.bind(this),this._decorate(this._container)}_decorate(t){if(!t)return;di("[decorate]");const i=ri("div");let n;i.classList.add("red5pro-media-control-bar"),this._playPauseButton=this._createPlayPauseButton(),this._muteButton=this._createMuteButton(),this._volumeField=this._createVolumeControl(),this._seekTimeField=this._createSeekControl(),this._timeField=this._createPlaybackTime(),this._fullScreenButton=this._createFullScreenToggle(),i.appendChild(this._playPauseButton),i.appendChild(this._timeField),i.appendChild(this._seekTimeField.view),i.appendChild(this._muteButton),i.appendChild(this._volumeField.view),i.appendChild(this._fullScreenButton),t.appendChild(i),this._controlbar=i;const s=()=>{clearTimeout(n),n=setTimeout((()=>{i.classList.remove("red5pro-media-control-bar-show")}),6e3)};ai()?(i.classList.add("red5pro-media-control-bar-show"),t.addEventListener("touchend",(()=>{i.classList.toggle("red5pro-media-control-bar-show"),s()})),s()):(t.addEventListener("mouseover",(()=>{i.classList.add("red5pro-media-control-bar-show")})),t.addEventListener("mouseout",(()=>{i.classList.remove("red5pro-media-control-bar-show")}))),this.setState(e.PlaybackState.IDLE).onFullScreenChange(!1).setSeekTime(0).enable(!1)}_onPlayPauseClick(){return this.getState()===e.PlaybackState.PLAYING?this._player.pause(!0):this.getState()===e.PlaybackState.PAUSED?this._player.resume(!0):this._player.play(!0),this}_createPlayPauseButton(){const e=ri("button");return e.setAttribute("aria-label","Toggle Playback"),e.classList.add("red5pro-media-control-element"),e.classList.add("red5pro-media-element-button"),e.classList.add("red5pro-media-playpause-button"),e}_createMuteButton(){const e=ri("button");return e.setAttribute("aria-label","Toggle Mute Audio"),e.classList.add("red5pro-media-control-element"),e.classList.add("red5pro-media-element-button"),e.classList.add("red5pro-media-muteunmute-button"),e.addEventListener("click",(()=>{this.getMutedState()?(this._player.unmute(),this.setMutedState(!1)):(this._player.mute(),this.setMutedState(!0))})),e}_createVolumeControl(){const e=new oi("volume");return e.view.classList.add("red5pro-media-control-element"),e.view.classList.add("red5pro-media-volume-slider"),e.view.classList.add("red5pro-media-slider"),e.on(Yt.CHANGE,(e=>{const t=Number(e.data);this._player.setVolume(t)})),e}_createSeekControl(){const t=new oi("seek");return t.view.classList.add("red5pro-media-control-element"),t.view.classList.add("red5pro-media-seektime-slider"),t.view.classList.add("red5pro-media-slider"),t.on(Yt.CHANGE_START,(()=>{this.getState()===e.PlaybackState.PLAYING&&(this._resumeAfterSeek=!0,this._player.pause(!0,!0)),this.trigger(new me(Jt.SEEK_START))})),t.on(Yt.CHANGE,(e=>{const t=Number(e.data);this._player.seekTo(t,0===this._playbackDuration?void 0:this._playbackDuration),this.setSeekTime(t*this._playbackDuration,this._playbackDuration)})),t.on(Yt.CHANGE_COMPLETE,(()=>{this._resumeAfterSeek&&this.getState()===e.PlaybackState.PAUSED&&(this._resumeAfterSeek=!1,this._player.resume(!0)),this.trigger(new me(Jt.SEEK_END))})),t}_createPlaybackTime(){const e=ri("span"),t=ri("text");return t.textContent="00:00",e.classList.add("red5pro-media-control-element"),e.classList.add("red5pro-media-time-field"),e.appendChild(t),e}_createFullScreenToggle(){const e=ri("button");return e.setAttribute("aria-label","Toggle Fullscreen"),e.classList.add("red5pro-media-control-element"),e.classList.add("red5pro-media-element-button"),e.classList.add("red5pro-media-fullscreen-button"),e.addEventListener("click",(()=>{this._player.toggleFullScreen()})),e}_formatTime(e){const t=new Date(1e3*e);return`${String(t.getUTCHours()).padStart(2,"0")}:${String(t.getUTCMinutes()).padStart(2,"0")}:${String(t.getUTCSeconds()).padStart(2,"0")}`}onStateChange(t){var i,n,s,o;return t===e.PlaybackState.PLAYING?(null===(i=this._playPauseButton)||void 0===i||i.classList.remove("red5pro-media-play-button"),null===(n=this._playPauseButton)||void 0===n||n.classList.add("red5pro-media-pause-button")):(null===(s=this._playPauseButton)||void 0===s||s.classList.add("red5pro-media-play-button"),null===(o=this._playPauseButton)||void 0===o||o.classList.remove("red5pro-media-pause-button")),this}onMutedStateChange(e){var t,i,n,s;return e?(null===(t=this._muteButton)||void 0===t||t.classList.add("red5pro-media-mute-button"),null===(i=this._muteButton)||void 0===i||i.classList.remove("red5pro-media-unmute-button"),this._volumeField&&(this._volumeField.value=0)):(null===(n=this._muteButton)||void 0===n||n.classList.remove("red5pro-media-mute-button"),null===(s=this._muteButton)||void 0===s||s.classList.add("red5pro-media-unmute-button"),this._volumeField&&(this._volumeField.value=this._volumeValue)),this}onFullScreenChange(e){var t,i,n,s;return e?(null===(t=this._fullScreenButton)||void 0===t||t.classList.add("red5pro-media-exit-fullscreen-button"),null===(i=this._fullScreenButton)||void 0===i||i.classList.remove("red5pro-media-fullscreen-button")):(null===(n=this._fullScreenButton)||void 0===n||n.classList.remove("red5pro-media-exit-fullscreen-button"),null===(s=this._fullScreenButton)||void 0===s||s.classList.add("red5pro-media-fullscreen-button")),this}enable(e){var t,i,n,s;return e?(null===(t=this._playPauseButton)||void 0===t||t.classList.remove("red5pro-media-element-button-disabled"),null===(i=this._playPauseButton)||void 0===i||i.addEventListener("click",this._onPlayPauseClickBound)):(null===(n=this._playPauseButton)||void 0===n||n.classList.add("red5pro-media-element-button-disabled"),null===(s=this._playPauseButton)||void 0===s||s.removeEventListener("click",this._onPlayPauseClickBound)),this}getVolume(){return this._volumeValue}setVolume(e){return this._volumeField&&(this._volumeField.value=e),this._volumeValue=e,0===e?this.setMutedState(!0):this.getMutedState()&&this.setMutedState(!1),this}setSeekTime(e,t=0){return this._seekTimeField&&(this._seekTimeField.value=0===t?0:e/t,0!==this._playbackDuration&&this._playbackDuration<=e&&(this._seekTimeField.value=1)),this._timeField&&(!isFinite(this._playbackDuration)&&li()?this._timeField.innerText="Live Broadcast":this._timeField.innerText=this._formatTime(Math.floor(e))),this}setPlaybackDuration(e){return this._playbackDuration=e,this}getPlaybackDuration(){return this._playbackDuration}getState(){return this._state}setState(e){return di(`[setState]: ${o[e]}`),this._state=e,this.onStateChange(this._state),this}setMutedState(e){return this._mutedState=e,this.onMutedStateChange(this._mutedState),this}getMutedState(){return"muted"in this._player?this._player.muted:this._mutedState}setAsVOD(e){return di(`[setAsVOD]: ${e}`),this._seekTimeField&&(e?this._seekTimeField.disabled=!1:(this._seekTimeField.value=0,this._seekTimeField.disabled=!0)),this}detach(){this.enable(!1),this._controlbar&&this._controlbar.parentNode&&this._controlbar.parentNode.removeChild(this._controlbar),this._controlbar=void 0,this._container=void 0}}var ci,ui;!function(e){e[e.LIVE=0]="LIVE",e[e.VOD=1]="VOD"}(ci||(ci={})),function(e){e.LIVE="LiveSeek.LIVE",e.VOD="LiveSeek.VOD"}(ui||(ui={}));const pi={[ci.LIVE]:ui.LIVE,[ci.VOD]:ui.VOD};var _i;!function(e){e.LIVE_SEEK_UNSUPPORTED="WebRTC.LiveSeek.Unsupported",e.LIVE_SEEK_ERROR="WebRTC.LiveSeek.Error",e.LIVE_SEEK_ENABLED="WebRTC.LiveSeek.Enabled",e.LIVE_SEEK_DISABLED="WebRTC.LiveSeek.Disabled",e.LIVE_SEEK_LOADING="WebRTC.LiveSeek.FragmentLoading",e.LIVE_SEEK_LOADED="WebRTC.LiveSeek.FragmentLoaded",e.LIVE_SEEK_CHANGE="WebRTC.LiveSeek.Change"}(_i||(_i={}));const{createElement:gi,findByQuerySelector:vi,createHLSClient:mi,getHLSClientEventEnum:Ei}=ie,bi="SourceHandlerSeekable",Si=e=>O(bi,e),Ci=e=>H(bi,e),Ti=e=>k(bi,e);class yi extends Ot{constructor(e,t,i,n,s=!0){super(e,`${t}-Seekable`),this._hlsElementGenerated=!1,this._hlsRecoverFlop=!1,this._hlsRecoverAttempts=0,this._isFragLoading=!1,this._wallOffset=NaN,this._lastDurationUpdate=0,this._averageSegmentDuration=6,this._isSeekable=!1,this._isHLSPlaybackActive=!1,this._container=s?this._determineContainer(e):void 0,this._liveSeekConfig=i,this._hlsOptions=n,this._usePlaybackControls=s,this.onHLSDurationChange=this._onHLSDurationChange.bind(this),this.onHLSTimeUpdate=this._onHLSTimeUpdate.bind(this),this.onHLSPlay=this._onHLSPlay.bind(this),this.onHLSPause=this._onHLSPause.bind(this)}_determineContainer(e){if(e.parentNode&&e.parentNode.classList.contains("red5pro-media-container"))return e.classList.add("red5pro-media"),e.parentNode;{const t=e.parentNode,i=gi("div");return i.classList.add("red5pro-media-container"),e.classList.add("red5pro-media"),t.insertBefore(i,e),t.removeChild(e),i.appendChild(e),i}}_generateHLSLivePlayback(e,t,i){const n=`${i}-hls-vod`;let s=vi(`#${n}`);return s||(s=gi("video"),s.id=n,s.classList.add("red5pro-hls-vod"),s.classList.add("red5pro-media-background"),s.setAttribute("playsinline","playsinline"),s.style.width="100%",s.style.height="100%",s.style.display="none",e.insertBefore(s,t),this._hlsElementGenerated=!0),s}_onDurationChange(e){var t;Si("[videoelement:event] durationchange");const i=null!==(t=this._playbackNotificationCenter)&&void 0!==t?t:e.target,n=this.getControls();!this.isSeekable&&n&&n.setPlaybackDuration(i.duration)}_onTimeUpdate(t){var i;const n=null!==(i=this._playbackNotificationCenter)&&void 0!==i?i:t.target,s=this.getControls();if(this.isSeekable){if(!this._isHLSPlaybackActive){const t=this._hlsElement.duration,i=n.currentTime-this._lastDurationUpdate,o=isNaN(t)||0===t?n.currentTime:t+this._averageSegmentDuration+i;s&&s.setSeekTime(o,o),this.trigger(new be(e.SubscriberEventTypes.PLAYBACK_TIME_UPDATE,void 0,{time:o,duration:o,action:"rtc time update (1)"}))}}else super._onTimeUpdate(t)}_onEnded(){this.isHLSPlaybackActive||super._onEnded()}_onHLSDurationChange(t){const i=t.target,n=t.duration||i.duration;isNaN(this._wallOffset)&&(this._wallOffset=n-this._view.currentTime),this._lastDurationUpdate=this._view.currentTime;const s=n+this._averageSegmentDuration;Si(`[HLS:videoelement:duration] ${n}, ${this._averageSegmentDuration}`);const o=this.getControls();o&&o.setPlaybackDuration(s),this._isHLSPlaybackActive?this.trigger(new be(e.SubscriberEventTypes.PLAYBACK_TIME_UPDATE,void 0,{time:i.currentTime,duration:s,action:"hls time update"})):this.trigger(new be(e.SubscriberEventTypes.PLAYBACK_TIME_UPDATE,void 0,{time:s,duration:s,action:"hls time update"}))}_onHLSTimeUpdate(t){const i=t.target,n=this.getControls();n&&n.setSeekTime(i.currentTime,n.getPlaybackDuration()),i.currentTime>=i.duration?this._showHLSLivePlayback(!1,this._hlsElement,this._view,this._container):!isNaN(i.duration)&&this._isHLSPlaybackActive&&this.trigger(new be(e.SubscriberEventTypes.PLAYBACK_TIME_UPDATE,void 0,{time:i.currentTime,duration:i.duration+this._averageSegmentDuration,action:"hls time update"}))}_onHLSPlay(){Si("[HLS:videoelement:event] play");const t=this.getControls();t&&t.setState(e.PlaybackState.PLAYING),this.trigger(new be(e.SubscriberEventTypes.PLAYBACK_STATE_CHANGE,void 0,{code:e.PlaybackState.PLAYING,state:o[e.PlaybackState.PLAYING]}))}_onHLSPause(){Si("[HLS:videoelement:event] pause");const t=this.getControls();t&&t.setState(e.PlaybackState.PAUSED),this.trigger(new be(e.SubscriberEventTypes.PLAYBACK_STATE_CHANGE,void 0,{code:e.PlaybackState.PAUSED,state:o[e.PlaybackState.PAUSED]}))}_addSeekableHandlers(e,t,i){if(t){const i=Ei();t.on(i.ERROR,((i,n)=>{const{type:s,details:o,fatal:r,url:a}=n;if("networkerror"===s.toLowerCase()){if("levelemptyerror"===o.toLowerCase()){this.trigger(new be(_i.LIVE_SEEK_DISABLED,void 0,{hlsElement:e,hlsControl:t})),this.isSeekable=!1,t.destroy();const i=setTimeout((()=>{clearTimeout(i),this.enableLiveSeek(a,this._subscriptionId,this._hlsElement,!1)}),3e3);return}this.trigger(new be(_i.LIVE_SEEK_ERROR,void 0,{hlsElement:e,hlsControl:t,error:n}))}else this.trigger(new be(_i.LIVE_SEEK_ERROR,void 0,{hlsElement:e,hlsControl:t,error:n}));"mediaerror"===s.toLowerCase()&&(this._hlsRecoverFlop&&t.swapAudioCodec(),this._hlsRecoverFlop=!this._hlsRecoverFlop,this._hlsRecoverAttempts=this._hlsRecoverAttempts+1,t.recoverMediaError()),r&&"networkerror"===s.toLowerCase()&&t.startLoad()})),t.on(i.MANIFEST_PARSED,(()=>{try{e.pause()}catch(e){Si(`Could not pause seekable live stream: ${e.message}`)}this.isSeekable=!0,this.trigger(new be(_i.LIVE_SEEK_ENABLED,void 0,{hlsElement:e,hlsControl:t}))})),t.on(i.FRAG_LOADING,((i,n)=>{const{frag:{stats:{loaded:s,total:o}}}=n;this.trigger(new be(_i.LIVE_SEEK_LOADING,void 0,{hlsElement:e,hlsControl:t,progress:s/o*100})),(this._isHLSPlaybackActive||this._isFragLoading)&&(this._isFragLoading=s/o>=1)})),t.on(i.FRAG_LOADED,((i,n)=>{this._isFragLoading=!1;const{frag:{endDTS:s,loader:o}}=n;if(!this._isHLSPlaybackActive&&!s)return;let r=6,a=0;if(o&&o.stats&&o.stats.segments){const e=o.stats.segments;for(let t=0;t{this._isFragLoading=!1;const{frag:{endDTS:s,loader:o}}=n;if(!this._isHLSPlaybackActive&&!s)return;let r=6,a=0;if(o&&o.stats&&o.stats.segments){const e=o.stats.segments;for(let t=0;tn.test(e)));if(!r)return void Ti(`Could not find last segment in manifest: ${e}`);const a=o.find((e=>i.test(e)));if(!a)return void Ti(`Could not find duration line in manifest: ${e}`);const l=a.match(i);if(!l)return void Ti(`Could not find duration in manifest: ${e}`);const d=l[1],h=parseFloat(d),c=r.match(n);if(!c)return void Ti(`Could not find segment length in manifest: ${e}`);const u=c[1];let p=parseInt(u,10);isNaN(p)&&(p=1),p=p>1?p-1:p,this._averageSegmentDuration=h,this.isSeekable=!0,this.trigger(new be(_i.LIVE_SEEK_ENABLED,void 0,{hlsElement:this._hlsElement,hlsControl:void 0})),this.onHLSDurationChange({target:t,duration:h*p}),this._manifestLoadTimeout=setTimeout((()=>{clearTimeout(this._manifestLoadTimeout),this._loadManifest(e,t)}),1e3*h)}catch(e){Ci(`Could not load manifest: ${e.message}.`),this.trigger(new be(_i.LIVE_SEEK_DISABLED,void 0,{hlsElement:t,hlsControl:void 0})),this.isSeekable=!1}}_cleanup(){this._removeSeekableHandlers(this._hlsElement,this._hlsjsRef),this._hlsjsRef&&(this._hlsjsRef.detachMedia(),this._hlsjsRef=void 0),this._hlsElement&&(this._hlsElement.parentNode&&this._hlsElementGenerated&&this._hlsElement.parentNode.removeChild(this._hlsElement),this._hlsElement=void 0),this._playbackControls&&(this._playbackControls.detach(),this._playbackControls=void 0),this._isVOD=!1,this._isSeekable=!1,this._isHLSPlaybackActive=!1,this._isFragLoading=!1,this._hlsRecoverFlop=!1,this._hlsRecoverAttempts=0,this._averageSegmentDuration=6,this._hlsElementGenerated=!1,this._wallOffset=NaN,this._lastDurationUpdate=0,this._manifestLoadTimeout&&(clearTimeout(this._manifestLoadTimeout),this._manifestLoadTimeout=void 0),super._cleanup()}addSource(){Si("[addSource]"),this._view.controls=!0,this._view.classList.add("red5pro-media");this._view.hasAttribute("controls")&&this._view.classList.contains("red5pro-media")&&(this._container=this._determineContainer(this._view));const e=this._view.hasAttribute("muted");this._usePlaybackControls?(this._playbackControls=new hi(this,this._container),this._view.controls=!1,this._playbackControls.setAsVOD(this.isSeekable),this._playbackControls.setMutedState(e)):this._view.controls=!1}enableLiveSeek(e,t,i,n=!1){if(this.getControls()&&this.getControls().setSeekTime(1,1),this._url=e,this._subscriptionId=t,this._hlsElement=i||this._generateHLSLivePlayback(this._container,this._view,t),this._showHLSLivePlayback(this._isHLSPlaybackActive,this._hlsElement,this._view,this._container),n){this._addSeekableHandlers(this._hlsElement,void 0,!1);const t=gi("source");t.src=e,this._hlsElement.appendChild(t),this._loadManifest(e,this._hlsElement)}else{const t=this._hlsOptions,{liveSeek:{hlsjsRef:i}}=this._liveSeekConfig,n=i?new i(t):mi(t);this._addSeekableHandlers(this._hlsElement,n,!0),n.attachMedia(this._hlsElement,e),n.on(Ei().MEDIA_ATTACHED,(()=>{n.loadSource(e)})),this._hlsjsRef=n}}switchLiveSeek(e){this._hlsjsRef&&(this._hlsjsRef.destroy(),this._hlsjsRef=void 0),this.enableLiveSeek(e,this._subscriptionId,this._hlsElement),this.seekTo(1);try{this._view.play()}catch(e){Ti("[videoelement:action] play (FAULT) - "+e.message)}this._url=e}async play(e=!1){Si("[videoelement:action] play");try{return e&&this._hlsElement&&this._hlsElement.paused?(await this._hlsElement.play(),!0):super.play()}catch(e){Ti("[videoelement:action] play (CATCH::FAULT) - "+e.message)}return!1}async pause(e=!1,t=!1){Si("[videoelement:action] pause");try{return e&&t&&this._hlsElement?(this._hlsElement.pause(),super.pause()):e&&this._hlsElement&&!this._hlsElement.paused?(this._hlsElement.pause(),!0):super.pause()}catch(e){Ti("[videoelement:action] pause (CATCH::FAULT) - "+e.message)}return!1}async resume(e=!1){var t,i;Si("[videoelement:action] resume");try{const n=this._isHLSPlaybackActive&&this._hlsElement?this._hlsElement.play():null===(t=this._view)||void 0===t?void 0:t.play();if(e&&this._isHLSPlaybackActive)return await(null===(i=this._view)||void 0===i?void 0:i.play()),!0;n&&n.then((()=>Si("[videoelement:action] play (START)"))).catch((e=>Ti("[videoelement:action] play (CATCH::FAULT) "+(e.message?e.message:e))))}catch(e){Ti("[videoelement:action] resume (CATCH::FAULT) - "+e.message)}return!1}async stop(){Si("[videoelement:action] stop");try{return this._hlsElement&&this._hlsElement.pause(),super.stop()}catch(e){Ti("[videoelement:action] stop (CATCH::FAULT) - "+e.message)}return!1}mute(){this._hlsElement&&(this._hlsElement.muted=this._isHLSPlaybackActive),this._view&&(this._view.muted=!0);const e=this.getControls();e&&e.setMutedState(!0)}unmute(){this._hlsElement&&(this._hlsElement.muted=!this._isHLSPlaybackActive,this._view&&(this._view.muted=this._isHLSPlaybackActive)),this._view&&(this._view.muted=!1);const e=this.getControls();e&&e.setMutedState(!1)}setVolume(e){this.unmute(),this._hlsElement&&this._isHLSPlaybackActive?this._hlsElement.volume=e:this._view?this._view.volume=e:Ci("[videoelement:action] setVolume (CATCH::FAULT) - "+e)}seekTo(e,t=void 0){if(this.isSeekable)if(this.getControls()&&this.getControls().setSeekTime(e,t),this.trigger(new be(_i.LIVE_SEEK_CHANGE,void 0,{seek:e,duration:t})),this._hlsElement&&e<1)try{this._hlsElement.classList.remove("hidden"),this._hlsElement.currentTime=this._hlsElement.duration*e,this._isFragLoading=!0,this._showHLSLivePlayback(!0,this._hlsElement,this._view,this._container),this._view.paused||(Si("[hlsvod:action] play (START) - (seekTo)"),this.play(!0))}catch(e){Ti("[hlsvod:action] play (CATCH::FAULT) - "+e.message)}else this._hlsElement&&e>=1&&(this._isFragLoading=!1,this._showHLSLivePlayback(!1,this._hlsElement,this._view,this._container));else this._view.currentTime=t?e*t:e}toggleFullScreen(e){var t;this._container&&super.toggleFullScreen(null!==(t=this._container)&&void 0!==t?t:e)}getControls(){return this._playbackControls}get isSeekable(){return this._isSeekable}set isSeekable(e){this._isSeekable=e,this.getControls()&&this.getControls().setAsVOD(e)}get isHLSPlaybackActive(){return this._isHLSPlaybackActive}get url(){return this._url}}const{supportsHLS:fi,supportsNonNativeHLS:wi}=ie,Ai="WHEPLiveSeekClient",Pi=e=>H(Ai,e);class Ni extends Vt{constructor(e,t,i){super(e,t,i)}async init(e){const{liveSeek:t}=e;return t||(e.liveSeek=Kt),super.init(e)}_attachSourceHandler(e){var t;if((null===(t=this._playbackView)||void 0===t?void 0:t.view)&&!this._enableLiveSeek(this._playbackView.view))return k(Ai,"LiveSeek is not enabled, using default source handler"),void super._attachSourceHandler(e);this._startSeekableIfSeekableEnabled(this._options)}_enableLiveSeek(e){const{liveSeek:t}=this._options;if(t){const{hlsjsRef:i,usePlaybackControlsUI:n,options:s}=t;if(fi()||wi(i))return this._sourceHandler=new yi(e,this.getType(),this._options,s,n),this._sourceHandler.addSource(),!0;Pi("Could not utilize the 'LiveSeek' request. This feature requires either native HLS playback or hls.js as a depenency."),this.trigger(new be(_i.LIVE_SEEK_UNSUPPORTED,this,{feature:"Live Seek",message:"Live Seek requires integration with the HLS.JS plugin in order work properly. Most likely you are viewing this on a browser that does not support the use of HLS.JS."}))}return!1}_startSeekableIfSeekableEnabled(e){const{liveSeek:t,subscriptionId:i}=e;if(!t)return;const{hlsjsRef:n,hlsElement:s}=t;if(this._sourceHandler)try{if(!fi()&&!wi(n))throw new Error;{const t=ne(e);this._sourceHandler.enableLiveSeek(t,i,s,!wi(n))}}catch(e){Pi("Could not utilize the 'LiveSeek' request. This feature requires either native HLS playback or hls.js as a depenency.")}}_onUnpublish(){super._onUnpublish();const{liveSeek:e}=this._options;e||this.unsubscribe(!0)}_onStreamSwitchComplete(){const e=this._requestedStreamSwitch,{liveSeek:t}=this._options;if(t&&e){const{baseURL:i,fullURL:n}=t,s=e.split("/"),o=s.pop(),r=s.join("/"),a={...this._options,app:r,streamName:o};let l=n;if(n){const e=/.*\/(.*)\.m3u8/.exec(n);if(e&&e.length>1){const t=`${e[1]}.m3u8`;l=n.replace(t,`${o}.m3u8`)}}const d=ne(a,i,l);this._sourceHandler&&this._sourceHandler.switchLiveSeek(d)}super._onStreamSwitchComplete()}}const Li="15.2.0";R(L.ERROR);const Ri=(e,t=!1)=>{Object.prototype.hasOwnProperty.call(L,e.toUpperCase())&&(R(e,t),console&&console.log(`Red5 Pro SDK Version ${Ii()}`))},Ii=()=>Li;O("RED5",`Red5 Pro HTML SDK Version: ${Li}`);var Di={version:Li,LOG_LEVELS:L,getLogger:I,getRecordedLogs:D,setLogLevel:Ri,getVersion:Ii,PlaybackVideoEncoder:e.PlaybackVideoEncoder,PlaybackAudioEncoder:e.PlaybackAudioEncoder,PlaybackState:e.PlaybackState,PlaybackStateReadableMap:o,PublishVideoEncoder:e.PublishVideoEncoder,PublishAudioEncoder:e.PublishAudioEncoder,SubscriberEvent:be,PublisherEvent:Ee,MessageTransportStateEvent:Se,PubNubEvent:Ce,PublisherEventTypes:e.PublisherEventTypes,SubscriberEventTypes:e.SubscriberEventTypes,RTCPublisherEventTypes:e.RTCPublisherEventTypes,RTCSubscriberEventTypes:e.RTCSubscriberEventTypes,MessageTransportStateEventTypes:e.MessageTransportStateEventTypes,PubNubEventTypes:rt,WHIPClient:St,WHEPClient:Vt,HLSSubscriber:Wt,LiveSeekClient:Ni,PubNubClient:_t,defaultWhepSubscriberConfig:Ct,defaultWhipPublisherConfig:ge,defaultStatsConfig:pe,StatsEndpointType:e.StatsEndpointType};e.Event=me,e.EventEmitter=U,e.HLSSubscriber=Wt,e.LOG_LEVELS=L,e.LiveSeekClient=Ni,e.MessageTransportStateEvent=Se,e.PlaybackController=Lt,e.PlaybackControls=zt,e.PlaybackStateReadableMap=o,e.PubNubClient=_t,e.PublisherEvent=Ee,e.SourceHandler=Rt,e.SourceHandlerImpl=Ot,e.SubscriberEvent=be,e.WHEPClient=Vt,e.WHIPClient=St,e.default=Di,e.defaultHLSSubscriberConfig=Tt,e.defaultLiveSeekConfig=jt,e.defaultStatsConfig=pe,e.defaultWhepSubscriberConfig=Ct,e.defaultWhipPublisherConfig=ge,e.getLogger=I,e.getRecordedLogs=D,e.getVersion=Ii,e.setLogLevel=Ri,Object.defineProperty(e,"__esModule",{value:!0})}));
+!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).red5prosdk={})}(this,(function(e){"use strict";var t,i,n,s;e.PlaybackAudioEncoder=void 0,(t=e.PlaybackAudioEncoder||(e.PlaybackAudioEncoder={})).OPUS="OPUS",t.NONE="NONE",e.PlaybackVideoEncoder=void 0,(i=e.PlaybackVideoEncoder||(e.PlaybackVideoEncoder={})).VP8="VP8",i.H264="H264",i.H265="H265",i.NONE="NONE",e.PlaybackState=void 0,(n=e.PlaybackState||(e.PlaybackState={}))[n.UNAVAILABLE=1e3]="UNAVAILABLE",n[n.AVAILABLE=0]="AVAILABLE",n[n.IDLE=1]="IDLE",n[n.PLAYING=2]="PLAYING",n[n.PAUSED=3]="PAUSED",function(e){e.UNAVAILABLE="Playback.UNAVAILABLE",e.AVAILABLE="Playback.AVAILABLE",e.IDLE="Playback.IDLE",e.PLAYING="Playback.PLAYING",e.PAUSED="Playback.PAUSED"}(s||(s={}));const a={[e.PlaybackState.UNAVAILABLE]:s.UNAVAILABLE,[e.PlaybackState.AVAILABLE]:s.AVAILABLE,[e.PlaybackState.IDLE]:s.IDLE,[e.PlaybackState.PLAYING]:s.PLAYING,[e.PlaybackState.PAUSED]:s.PAUSED};var o,r,l;!function(e){e.RTMP="rtmp",e.RTC="rtc"}(o||(o={})),function(e){e.LIVE="live",e.RECORD="record",e.APPEND="append"}(r||(r={})),e.PublishAudioEncoder=void 0,(e.PublishAudioEncoder||(e.PublishAudioEncoder={})).OPUS="OPUS",e.PublishVideoEncoder=void 0,(l=e.PublishVideoEncoder||(e.PublishVideoEncoder={})).VP8="VP8",l.H264="H264",l.H265="H265";var h={trace:10,debug:20,info:30,warn:40,error:50,fatal:60},d={};function c(e){return"string"==typeof e?h[e.toLowerCase()]:e}function u(e,t){return u=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e},u(e,t)}function p(e,t,i){return p=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){}))),!0}catch(e){return!1}}()?Reflect.construct:function(e,t,i){var n=[null];n.push.apply(n,t);var s=new(Function.bind.apply(e,n));return i&&u(s,i.prototype),s},p.apply(null,arguments)}function _(e){if(null==e)return e;if(Array.isArray(e))return e.slice();if("object"==typeof e){var t={};return Object.keys(e).forEach((function(i){t[i]=e[i]})),t}return e}function g(e){return void 0===e?"undefined":null===e?"null":Array.isArray(e)?"[ "+e.map((function(e){return g(e)})).join(", ")+" ]":"object"==typeof e?JSON.stringify(e):"function"==typeof e?"[Function: "+e.name+"]":"boolean"==typeof e||"number"==typeof e?e:"'"+e.toString()+"'"}function v(e){if("string"!=typeof e){for(var t=new Array(arguments.length),i=0;i=a)return e;switch(e){case"%s":return String(s[n++]);case"%d":return Number(s[n++]);case"%j":try{return JSON.stringify(s[n++])}catch(e){return"[Circular]"}default:return e}})),r=s[n];ne||(s=function(s){var a;s[0]instanceof Error?(i={err:t.serializers&&t.serializers.err?t.serializers.err(s[0]):y.err(s[0])},a={err:!0},n=1===s.length?[i.err.message]:Array.prototype.slice.call(s,1)):"object"!=typeof s[0]&&null!==s[0]||Array.isArray(s[0])?(i=null,n=Array.prototype.slice.call(s)):(i=s[0],n=1===s.length&&i.err&&i.err instanceof Error?[i.err.message]:Array.prototype.slice.call(s,1));var o=_(t.fields);o.level=e;var r=i?_(i):null;if(r&&(t.serializers&&t._applySerializers(r,a),Object.keys(r).forEach((function(e){o[e]=r[e]}))),o.levelName=d[e],o.msg=n.length?v.apply(t,n):"",o.time||(o.time=new Date),t.src&&!o.src)try{throw new Error("call-stack-error")}catch(e){var l=e.stack?function(e,t){var i=e.split("\n");i[0]&&i[0].indexOf("call-stack-error")>=0&&i.shift();var n=i[t],s=null;if(n){var a=/^\s*(at|.*@)\s*(.+)?$/.exec(n);s=Array.isArray(a)&&a[2]?a[2]:n}return s}(e.stack,2):"";l||function(e){return m[e]}("src")||E("Unable to determine src line info","src"),o.src=l||""}return o.v=1,o}(n),this._emit(s))}}function T(e){var t=e.stack||e.toString();if(e.cause&&"function"==typeof e.cause){var i=e.cause();i&&(t+="\nCaused by: "+T(i))}return t}S.prototype.trace=C(10),S.prototype.debug=C(20),S.prototype.info=C(30),S.prototype.warn=C(40),S.prototype.error=C(50),S.prototype.fatal=C(60);var y={err:function(e){return e&&e.stack?{message:e.message,name:e.name,stack:T(e),code:e.code,signal:e.signal}:e}};const f={10:"TRACE",20:"DEBUG",30:"INFO",40:"WARN",50:"ERROR",60:"FATAL"};class w{write(e){console.log("%s - [%s] %s: %s",e.time.toISOString(),e.name,f[e.level]||"UNKNOWN",e.msg)}}let A,P;const N=e=>(t,i)=>{var n;A&&"function"==typeof A[e]&&A[e]((n=t,e=>`(${n}) ${e}`)(i))},R={TRACE:"trace",INFO:"info",DEBUG:"debug",WARN:"warn",ERROR:"error",FATAL:"fatal"},L=(e,t=!1,i)=>{const n=[{level:e,stream:new w,type:"raw"}];if(i){const t=i.map((t=>({...t,level:e})));n.push(...t)}t&&(P=[],n.push({level:e,stream:{write:t=>{const i=`[${t.time.toISOString()}] ${e.toUpperCase()}: ${t.msg}`;null==P||P.push(i)}},type:"raw"}));A=function(){return p(S,[].slice.call(arguments))}({level:e,name:"red5pro-sdk",streams:n})},I=()=>(A||L(R.INFO),A),D=()=>P||[];N(R.TRACE),N(R.INFO);const O=N(R.DEBUG),k=N(R.WARN),H=N(R.ERROR);N(R.FATAL);const M="RED5PRO";class U{constructor(){this._callbacks={},this._callbacks[M]=[]}_notify(e,t){let i;const n=e.length;for(i=0;i1&&(s=V.exec(e),n[1]===t&&s&&s.length>1)?s[1]:void 0}}function x(e){const t=G(e,"orientation");if(t)return{orientation:parseInt(t)}}function W(e){const t=G(e,"streamingMode");if(t)return{streamingMode:t}}const K=e=>F.get(e),j=e=>{const t=e.textTracks;t&&(e.addTextTrack("metadata"),t.addEventListener("addtrack",(t=>{const i=t.track;i.mode="hidden",i.addEventListener("cuechange",(t=>{let n,s;for(t&&t.currentTarget?n=t.currentTarget.cues:(n=i.cues,n=n&&n.length>0?n:i.activeCues),n=n||[],s=0;s{e(n)})),s&&a&&a.streamingMode&&a.streamingMode.forEach((e=>{e(s)}))}}}))})))},z="BrowserEnvironment",J=e=>O(z,e),Y=e=>k(z,e);let q=[];const X=()=>{const e=screen.orientation?screen.orientation.angle:void 0,t=void 0===e?window.matchMedia("(orientation: portrait)").matches?0:90:e,i=q.length;J(`[window:onorientationchange]: orientation(${t}).`);for(let e=0;e{const e=document.createElement("video");return e.canPlayType("application/vnd.apple.mpegURL").length>0||e.canPlayType("application/x-mpegURL").length>0||e.canPlayType("audio/mpegurl").length>0||e.canPlayType("audio/x-mpegurl").length>0},te="undefined"!=typeof window&&window.adapter;var ie={gUM:async e=>navigator.mediaDevices.getUserMedia(e),createElement:e=>document.createElement(e),resolveElement:e=>document.getElementById(e),getElementId:e=>e.id,setVideoSource:(e,t,i)=>{if(e.srcObject=t,i)try{const t=e.play();t&&t.then((()=>J("[setVideoSource:action]: play (START)"))).catch((t=>{Y(`[setVideoSource:action]: play (CATCH::FAULT) ${t.message}`);try{e.setAttribute("autoplay","false"),e.pause()}catch(e){Y(`[setVideoSource:action]: pause (CATCH::FAULT) ${e.message}`)}}))}catch(e){Y(`[setVideoSource:action]: play (CATCH::FAULT) ${e.message}`)}},hasAttributeDefined:(e,t)=>e.hasAttribute(t),addOrientationChangeHandler:(e,t=!0)=>{"onorientationchange"in window&&(J("[window:orientation:addOrientationChangeHandler]: add"),q.push(e),t&&X()),1===q.length&&(J("[window:orientation:addOrientationChangeHandler]: add"),window.addEventListener("orientationchange",X))},removeOrientationChangeHandler:e=>{q=q.filter((t=>t!==e)),0===q.length&&window.removeEventListener("orientationchange",X)},toggleFullScreen:e=>{window.screenfull&&window.screenfull.enabled?window.screenfull.toggle(e):document.fullscreenEnabled&&(document.fullscreenElement&&document.fullscreenElement===e?document.exitFullscreen():e.requestFullscreen())},onFullScreenStateChange:e=>{var t;Z.push(e),t=window.screenfull,Q||(Q=!0,window.screenfull?window.screenfull.on("change",(()=>{Z.forEach((e=>e(t.isFullscreen)))})):document.fullscreenEnabled&&document.addEventListener("fullscreenchange",(()=>{Z.forEach((e=>e(null!==document.fullscreenElement)))})))},getOrGenerateFingerprint:()=>{const e=window.localStorage;if(e&&e.getItem("red5_fingerprint"))return e.getItem("red5_fingerprint");let t;try{t=window.crypto.randomUUID()}catch(e){t="10000000-1000-4000-8000-100000000000".replace(/[018]/g,(e=>(Number(e)^crypto.getRandomValues(new Uint8Array(1))[0]&15>>Number(e)/4).toString(16)))}return e.setItem("red5_fingerprint",t),t},getBrowserDetails:()=>{const e=void 0!==window.adapter,{navigator:t,adapter:i}=window,{appVersion:n,platform:s,userAgent:a,vendor:o}=t,r={appVersion:n,platform:s,userAgent:a,vendor:o};return e?{...i.browserDetails,...r}:r},supportsHLS:ee,onOrientationMetadata:(e,t)=>{const i=F.get(e);F.has(e)?Object.prototype.hasOwnProperty.call(i,"orientation")||(F.get(e).orientation=[]):(j(e),F.set(e,{orientation:[]})),F.get(e).orientation.push(t)},onStreamingModeMetadata:(e,t)=>{const i=F.get(e);F.has(e)?Object.prototype.hasOwnProperty.call(i,"streamingMode")||(F.get(e).streamingMode=[]):(j(e),F.set(e,{streamingMode:[]})),F.get(e).streamingMode.push(t)},isTouchEnabled:()=>"ontouchstart"in window,isPossiblySafari:()=>te?"safari"===window.adapter.browserDetails.browser.toLowerCase():ee(),findByQuerySelector:e=>document.querySelector(e),addGlobalEventListener:(e,t,i=document)=>{i.addEventListener(e,t)},removeGlobalEventListener:(e,t,i=document)=>{i.removeEventListener(e,t)},supportsNonNativeHLS:e=>{if(e)try{return e.isSupported()}catch(e){return Y("Could not access Hls.js."),!1}return!!window.Hls&&window.Hls.isSupported()},createHLSClient:(e={})=>new window.Hls(e),getHLSClientEventEnum:()=>window.Hls.Events,globalAssign:(e,t)=>{window[e]=t},globalUnassign:e=>{delete window[e]},getAssignedValue:e=>window[e]};const ne=(e,t,i)=>{const{liveSeek:{baseURL:n,fullURL:s}}=e,{host:a,protocol:o,port:r,app:l,streamName:h}=e;if(i||s)return i||s;const d=a,c="ws"===o?"http":"https",u=5080===r?5080:443,p=l,_=t||n;if(_){const e=_.length-1;return`${"/"===_.charAt(e)?_.substring(0,e):_}/${p}/${h}.m3u8`}return`${c}://${d}:${u}/${p}/${h}.m3u8`},se=e=>{const t=new URL(e),i=t.pathname.split("/").filter((e=>e.length>0)),n="https:"===t.protocol?"https":"http",s=t.hostname;return{protocol:n,port:t.port.length>0?t.port:443,app:i[0],host:s,streamName:i[i.length-1]}},ae=(e,t="whip")=>{var i;const{endpoint:n,proxy:s}=e;if(n)return n;{const{protocol:n,host:a,port:o,app:r,streamName:l}=e,h=n.match(/^http/)?n:"ws"===n?"http":"https";return(null==s?void 0:s.enabled)?`${h}://${a}:${o}/as/${null!==(i=s.version)&&void 0!==i?i:"v1"}/proxy/${t}/${r}/${l}`:`${h}://${a}:${o}/${r}/${t}/endpoint/${l}`}},oe=e=>{const t={audio:!1,video:!1},i={audio:!1,video:!1};return e.getTracks().forEach((e=>{"video"===e.kind?(i.video=e.getSettings(),t.video=e.getConstraints()):"audio"===e.kind&&(i.audio=e.getSettings(),t.audio=e.getConstraints())})),{requested:t,accepted:i}},re=e=>{const t=e.length;return function i(...n){return n.length>=t?e(...n):function(...e){return i(...n,...e)}}},le=re(((e,t)=>{let i=0;const n=t.length,s=[];for(;i{this._responder.onDataChannelError(t,e.error.message)},t.onmessage=e=>{this._onDataChannelMessage(e)},t.onopen=()=>{this._responder.onDataChannelOpen(t)},t.onclose=i=>{this._responder.onDataChannelClose(t),this.trigger(new Se(e.MessageTransportStateEventTypes.CLOSE,this._name,{socket:this,event:i}))}}_isErrorMessage(e){return!("error"!==(null==e?void 0:e.type)||!(null==e?void 0:e.message)&&!(null==e?void 0:e.code))}_isStatusMessage(e){return!("status"!==(null==e?void 0:e.type))}_onDataChannelMessage(e){if(this.handleMessageResponse(e))return!0;const t=this.getJsonFromSocketMessage(e);return t?(O(this._name,`[datachannel-response]: ${JSON.stringify(t,null,2)}`),this._handleMessageContent(t)):(k(this._name,"Determined websocket response not in correct format. Aborting message handle."),!0)}_handleMessageContent(e){const{async:t,data:i,method:n,send:s,type:a,id:o}=e;if(this._isErrorMessage(i)){const e=(null==i?void 0:i.message)||(null==i?void 0:i.code);if(e)return this._responder.onDataChannelError(this._dataChannel,e),!0}if(n)return this._responder.onSendReceived(n,i),!0;if(s){const{senderName:t,dcLabel:i}=e,{data:n,method:a}=s,o={...n,senderName:t,dcLabel:i};return this._responder.onSendReceived(a,o),!0}return"metadata"===a&&i?(this._responder.onMetaData(i),!0):this._isStatusMessage(i)&&"NetConnection.Connect.Closed"===(null==i?void 0:i.code)?(this._responder.onConnectionClosed(),!0):!(!t||!o)&&this._handleAsyncResponse(o,e)}_handleAsyncResponse(e,t){const i=this._asyncTickets.find((t=>t.id===e));if(!i)return!1;const{promise:n}=i,{data:s}=t;if("error"===(null==s?void 0:s.type)){const e=s.message||s.code||"Unknown error";n.reject(new Error(e))}else n.resolve(s);return this._asyncTickets=this._asyncTickets.filter((t=>t.id!==e)),!0}async setUpWithPeerConfiguration(e,t){this.tearDown();(null==e?void 0:e.iceServers)&&e.iceServers.length>0||(e.iceServers=Le);try{O(this._name,`[peerconnection:setUpWithPeerConfiguration]: ${JSON.stringify(e,null,2)}`);const i=new RTCPeerConnection(e);return t&&(this._dataChannel=i.createDataChannel(t.name,{ordered:!0}),this._addDataChannelHandlers(this._dataChannel)),this._addConnectionHandlers(i),this._peerConnection=i,i}catch(e){throw k(this._name,`Could not establish a PeerConnection. ${e.message}`),new Error(e.message)}}tearDown(){if(this._dataChannel){O(this._name,"[teardown:datachannel]"),this._removeDataChannelHandlers(this._dataChannel);try{this._dataChannel.close()}catch(e){k(this._name,`[datachannel.close] error: ${e.message}`)}finally{this._dataChannel=void 0}}if(this._peerConnection){O(this._name,"[teardown:peerconnection]"),this._removeConnectionHandlers(this._peerConnection);try{this._peerConnection.close()}catch(e){k(this._name,`[peerconnection.close] error: ${e.message}`)}finally{this._peerConnection=void 0}}}async setLocalDescription(e){var t;return O(this._name,"[setlocaldescription]"),null===(t=this._peerConnection)||void 0===t?void 0:t.setLocalDescription(e)}async setRemoteDescription(e){var t;return O(this._name,"[setremotedescription]"),null===(t=this._peerConnection)||void 0===t?void 0:t.setRemoteDescription(new RTCSessionDescription(e))}async addIceCandidate(e){var t;return O(this._name,"[addcandidate]"),null===(t=this._peerConnection)||void 0===t?void 0:t.addIceCandidate(e)}async waitToGatherIce(e=5e3){const t=this._peerConnection;return O(this._name,"[waittogatherice]"),new Promise((i=>{if("complete"===t.iceGatheringState)O(this._name,"[waittogatherice] ice gathering state complete."),t.addIceCandidate(null).then((()=>{i(t.localDescription)})).catch((e=>{k(this._name,"Error adding null candidate: "+e.message||e),i(t.localDescription)}));else{O(this._name,"[waittogatherice] waiting...");const n=setTimeout((()=>{clearTimeout(n),t.addIceCandidate(null).then((()=>{i(t.localDescription)})).catch((e=>{k(this._name,"Error adding null candidate: "+e.message||e),i(t.localDescription)}))}),e);t.onicegatheringstatechange=()=>{clearTimeout(n),O(this._name,"[waittogatherice] ice gathering state complete."),"complete"===t.iceGatheringState&&t.addIceCandidate(null).then((()=>{i(t.localDescription)})).catch((e=>{k(this._name,"Error adding null candidate: "+e.message||e),i(t.localDescription)}))}}}))}post(e){if(this._dataChannel){const t="string"==typeof e?e:JSON.stringify(e,null,2);O(this._name,`[datachannel.send] message: ${t}`);try{return this._dataChannel.send(t),Promise.resolve(!0)}catch(e){H(this._name,e.message)}}return Promise.resolve(!1)}get connection(){return this._peerConnection}get dataChannel(){return this._dataChannel}}const De=[{label:"4K(UHD)",width:3840,height:2160},{label:"1080p(FHD)",width:1920,height:1080},{label:"UXGA",width:1600,height:1200},{label:"720p(HD)",width:1280,height:720},{label:"SVGA",width:800,height:600},{label:"VGA",width:640,height:480},{label:"360p(nHD)",width:640,height:360},{label:"CIF",width:352,height:288},{label:"QVGA",width:320,height:240},{label:"QCIF",width:176,height:144},{label:"QQVGA",width:160,height:120}],Oe=e=>"number"==typeof e?e:e.exact||e.ideal||e.max||e.min||e,ke=re(((e,t)=>{var i,n;if("boolean"==typeof e.video)return!0;const s=(null===(i=e.video)||void 0===i?void 0:i.width)?Oe(e.video.width):0,a=(null===(n=e.video)||void 0===n?void 0:n.height)?Oe(e.video.height):0,o=s===t.width&&a===t.height;return o&&O("[gum:isExact]",`Found matching resolution for ${t.width}, ${t.height}.`),o})),He=re(((e,t)=>{const i=le(ke(t))(e);return O("[gum:hasMatchingFormat]","Filtered list: "+JSON.stringify(i,null,2)),i.length>0})),Me=re(((e,t)=>{var i,n;if("boolean"==typeof e.video)return!0;const s=((null===(i=e.video)||void 0===i?void 0:i.width)?Oe(e.video.width):0)*((null===(n=e.video)||void 0===n?void 0:n.height)?Oe(e.video.height):0);return t.width*t.height{const i=Me(t);return le(i)(e)})),Be=async e=>{O("[gum:determineSupportedResolution]","Determine next neighbor based on constraints: "+JSON.stringify(e,null,2));const t=Ue(De)(e),i={...e};return await(async(e,t)=>{let i={...e};if(0==t.length)i.video;else{const n=t.shift();i={...e,video:{...e.video,width:{exact:n.width},height:{exact:n.height}}}}return{media:await ie.gUM(i),constraints:i}})(i,t)},Ve=async e=>{let t;const i=He(De),n=async t=>{if(t){const e="string"==typeof t?t:[t.name,t.message].join(": ");O("[gum:getUserMedia]",`Failure in getUserMedia: ${e}. Attempting other resolution tests...`)}return await Be(e)};if((e=>e.video&&"object"==typeof e.video&&(e.video.width||e.video.height))(e)){if(!i(e))return await n(void 0);{O("[gum:getUserMedia]","Found constraints in list. Checking quick support for faster setup with: "+JSON.stringify(e,null,2));const i=(e=>{var t,i;const n={...e};return"boolean"==typeof e.video||(n.video={...n.video},(null===(t=e.video)||void 0===t?void 0:t.width)&&(n.video.width={exact:Oe(e.video.width)}),(null===(i=e.video)||void 0===i?void 0:i.height)&&(n.video.height={exact:Oe(e.video.height)})),n})(e);try{return t=await ie.gUM(i),{media:t,constraints:i}}catch(e){return await n(e)}}}else try{return t=await ie.gUM(e),{media:t,constraints:e}}catch(e){return await n(e)}},Fe=(e,t,i)=>{const n="a=end-of-candidates",s=/^a=candidate:/,a=/^a=ice-ufrag:/,o=/^a=ice-pwd:/,r=/^m=(audio|video|application)\ /,l=e.split("\r\n");let h,d="",c="";const u=[];l.forEach((e=>{!h&&r.exec(e)?h=e:a.exec(e)?d=e:o.exec(e)?c=e:s.exec(e)&&(t&&-1!=e.indexOf(t)?u.push(e):t||u.push(e))})),i&&u[u.length-1]!==n&&u.push(n);return[d,c,h,"a=mid:0"].concat(u).join("\r\n")},$e="RTCPeerConnectionPublisher";class Ge extends Ie{constructor(e){super(e,$e)}_removeConnectionHandlers(e){e.onconnectionstatechange=null,e.oniceconnectionstatechange=null,e.onsignalingstatechange=null,e.onicecandidate=null,e.ontrack=null}_addConnectionHandlers(e){let t;e.onsignalingstatechange=()=>{const t=e.signalingState;O($e,`[peer.onsignalingstatechange] - State: ${t}`)},e.onconnectionstatechange=()=>{const{connectionState:t}=e;"connected"===t?(O(this._name,"[peerconnection:open]"),this._responder.onPeerConnectionOpen()):"failed"!==t&&"disconnected"!==t||(k(this._name,"[peerconnection:error]"),"failed"===t&&this._responder.onPeerConnectionFail())},e.oniceconnectionstatechange=i=>{const{iceConnectionState:n}=e;O(this._name,`[peer.oniceconnectionstatechange] - State: ${n}`),"failed"===n?(t&&clearTimeout(t),this._responder.onPeerConnectionClose(i)):"disconnected"===n?t=setTimeout((()=>{O(this._name,"[peer.oniceconnectionstatechange] - Reconnect timeout reached. Closing PeerConnection."),clearTimeout(t),this._responder.onPeerConnectionClose(i)}),3e3):t&&(O(this._name,"[peer.oniceconnectionstatechange] - Clearing timeout for reconnect."),clearTimeout(t))},e.onicecandidate=e=>{const{candidate:t}=e;O(this._name,`[peer.onicecandidate] - Peer Candidate: ${null==t?void 0:t.candidate}`),t&&this._responder.onIceCandidate(t)},e.ontrack=e=>{O(this._name,"[peer:ontrack]"),this._responder.onPeerConnectionTrackAdd(e.track)}}_onDataChannelMessage(e){const t=e;if(super._onDataChannelMessage(e))return!0;const i=this.getJsonFromSocketMessage(t);if(null===i)return k(this._name,"Determined websocket response not in correct format. Aborting message handle."),!0;O(this._name,"[datachannel-response]: "+JSON.stringify(i,null,2));const{data:n}=i;return n&&"status"===n.type?"NetStream.Play.UnpublishNotify"===n.code?(this._responder.onUnpublish(),!0):"NetConnection.Publish.InsufficientBW"===n.code?(this._responder.onInsufficientBandwidth(n),!0):"NetConnection.Publish.SufficientBW"===n.code?(this._responder.onSufficientBandwidth(n),!0):"NetConnection.Publish.RecoveringBW"===n.code?(this._responder.onRecoveringBandwidth(n),!0):"Application.Statistics.Endpoint"===n.code?(this._responder.onStatisticsEndpointChange(n.statistics),!0):(O($e,`[datachannel.message] status :: ${n.code}`),this._responder.onPublisherStatus(n),!0):(this._responder.onDataChannelMessage(this._dataChannel,t),!1)}addTrack(e){this._peerConnection?this._peerConnection.addTrack(e):k($e,"PeerConnection not initialized. Cannot add track.")}async postUnpublish(e){const t=this.post({unpublish:e});return O($e,`[peerconnection:unpublish] complete: ${t}`),t}async createOfferWithoutSetLocal(e=null){var t;O($e,`[createoffer:withoutlocal]:: bandwidth request: ${JSON.stringify(e,null,2)}`);try{const i=await(null===(t=this._peerConnection)||void 0===t?void 0:t.createOffer());if(e){const t=((e,t)=>{const i=t.indexOf("m=audio");let n,s,a,o=t.indexOf("m=video"),r=t.indexOf("m=application");return i>-1&&e.audio&&(n=t.indexOf("\r\n",i),s=t.slice(0,n),a=t.slice(n+2,t.length),o=(t=[s,"b=AS:"+e.audio,a].join("\r\n")).indexOf("m=video"),r=t.indexOf("m=application")),o>-1&&e.video&&(n=t.indexOf("\r\n",o),s=t.slice(0,n),a=t.slice(n+2,t.length),r=(t=[s,"b=AS:"+e.video,a].join("\r\n")).indexOf("m=application")),r>-1&&e.dataChannel&&(n=t.indexOf("\r\n",r),s=t.slice(0,n),a=t.slice(n+2,t.length),t=[s,"b=AS:"+e.dataChannel,a].join("\r\n")),t})(e,i.sdp);i.sdp=t}return this._responder.onSDPSuccess(),i}catch(e){throw O($e,"[createoffer:error]"),this._responder.onSDPError(e),e}}async updateBandwidthRequest(e=null){var t;O($e,`[updatebandwidthrequest]:: bandwidth request: ${JSON.stringify(e,null,2)}`);try{const i=null===(t=this._peerConnection)||void 0===t?void 0:t.getSenders();if(e&&(null==i?void 0:i.length)&&i.length>0){const t=(e,t,i)=>new Promise(((n,s)=>{try{O($e,`[updatebandwidthrequest:${i}]:: bandwidth(${t.encodings[0].maxBitrate})`),e.setParameters(t).then(n).catch(s)}catch(e){s(e)}})),n=[];null==i||i.forEach((async i=>{var s,a;if("video"===(null===(s=i.track)||void 0===s?void 0:s.kind)&&e.video){const e=i.getParameters();e.encodings||(e.encodings=[{}]),e.encodings[0].maxBitrate=75e4,e.encodings[0].maxFramerate=60,e.encodings[0].priority="high",n.push(t(i,e,"video"))}else if("audio"===(null===(a=i.track)||void 0===a?void 0:a.kind)&&e.audio){const e=i.getParameters();e.encodings||(e.encodings=[{}]),e.encodings[0].maxBitrate=128e3,n.push(t(i,e,"audio"))}})),await Promise.all(n).catch((e=>{H($e,`[updatebandwidthrequest:error]:: ${e.message}`)}))}return!0}catch(e){H($e,`[updatebandwidthrequest:error]:: ${e.message}`)}return!1}}class xe extends Error{constructor(e){super(e),this.name="InvalidNameError"}}const We="WhipWhepSignalingHelper",Ke=new Map;Ke.set(400,"Invalid offer SDP."),Ke.set(401,"Not authorized."),Ke.set(404,"Scope resolver failed for the publish name and / or scope."),Ke.set(405,"Remember to update the URL passed into the WHIP or WHEP client."),Ke.set(406,"Scope connection rejected."),Ke.set(409,"Session already initialized."),Ke.set(412,"Invalid request body."),Ke.set(417,"Session lookup or creation failure.");const je=new Map;je.set(400,"Offer already sent, double POST assumed."),je.set(401,"Not authorized."),je.set(404,"Scope resolver failed for the playback name and / or scope."),je.set(406,"Playback failed due to an exception during creation."),je.set(409,"Stream is not available to playback.");const ze=["transcode"];var Je;!function(e){e.ICE_SERVER="ice-server",e.STATISTICS="statistics"}(Je||(Je={}));const Ye=e=>e&&(e=>{const t=/[?&](.*)=([^]*)/.exec(e);return t&&t.length>0})(e)?"&":"?",qe=e=>e.split(";").map((e=>e.trim())).map((e=>"<"===e.charAt(0)?["url",e.substring(1,e.length-1)]:e.split("="))).reduce(((e,t)=>e.set(t[0].replaceAll('"',""),t[1].replaceAll('"',""))),new Map);class Xe{constructor(e,t=!1,i=!0){O(We,`[whipwhep] ${e}`),this._url=e,this._origin=void 0,this._forceHost=i,this._resource=void 0,this._enableSignalingChannel=t}async getOptions(e={}){let t=`${this._url}${Ye(this._url)}signal=${this._enableSignalingChannel}`;e&&Object.keys(e).forEach((i=>{t+=`&${i}=${e[i]}`})),O(We,`[whipwhep-options] ${t}`);try{const e=await fetch(t,{method:"OPTIONS",mode:"cors"}),{status:i,headers:n}=e;if(200===i||204===i){const e=/^(L|l)ink/,t=/^(S|s)ession-(H|h)ost/,i=[];let s;return n.forEach(((n,a)=>{if(t.exec(a)&&(this._origin=n),e.exec(a))if(n.indexOf(`rel="${Je.ICE_SERVER}"`)>-1){const e=qe(n),t=e.get("url"),{protocol:s,host:a}=(e=>{const t=e.split(":");return t.length>1?{protocol:t[0],host:t[1]}:{protocol:void 0,host:e}})(t),o=e.get("username"),r=e.get("credential");s&&a&&o&&r?i.push({username:o,credential:r,urls:t}):t&&i.push({urls:t})}else if(n.indexOf(`rel="${Je.STATISTICS}"`)>-1){const e=qe(n).get("url");e&&(s=e)}})),O(We,`[whipwhep-links]: ${JSON.stringify(i)}`),O(We,`[whipwhep-origin]: ${this._origin}`),{links:i.length>0?i:void 0,origin:this._origin,statisticsEndpoint:s}}throw new Error(`Failed to get options: ${i}`)}catch(e){throw H(We,e.message),e}}async postSDPOffer(e,t={},i=!0){let n=`${this._url}${Ye(this._url)}signal=${this._enableSignalingChannel}`;t&&Object.keys(t).forEach((e=>{-1===ze.indexOf(e)&&(n+=`&${e}=${t[e]}`)})),this._forceHost&&this._origin&&!(null==t?void 0:t.host)&&(n+=`&host=${this._origin}`),O(We,`[whipwhep:post-offer] ${n}: `+JSON.stringify(e,null,2));try{const t={method:"POST",mode:"cors",headers:{"Content-Type":"application/sdp"}};e&&e.length>0&&(t.body=e);const s=await fetch(n,t),{status:a,headers:o}=s;if(o&&o.forEach(((e,t)=>{O(We,`[header] ${t}: ${e}`)})),a>=200&&a<300){const e=await s.text(),t=o.get("Location")||o.get("location");if(t){if(t.match(/^(http|https)/))this._resource=t;else{O(We,`[whipwhep-response] Location provided as relative path: ${t}`);const e=new URL(this._url);e.pathname=t.split("?")[0],this._resource=e.toString().replace(/\/endpoint\//,"/resource/")}return O(We,`[whipwhep-response] ${this._resource}: ${e}`),{sdp:e,location:this._resource}}return k(We,"Location not provided in header response to Offer."),this._resource=new URL(this._url).toString().replace(/\/endpoint\//,"/resource/"),{sdp:e,location:this._resource}}if(i&&Ke.get(a)){if(O(We,Ke.get(a)),404===a||409===a)throw new xe(Ke.get(a));throw new Error(Ke.get(a))}if(!i&&je.get(a)){if(O(We,je.get(a)),404===a||409===a)throw new xe(je.get(a));throw new Error(je.get(a))}{const e=await s.text();throw Error(e)}}catch(e){throw H(We,e.message),e}}async postSDPAnswer(e,t={}){O(We,`[whipwhep:post-answer] ${this._resource}: `+JSON.stringify(e,null,2));let i=this._resource,n=Ye(i);t&&Object.keys(t).forEach((e=>{-1===ze.indexOf(e)&&(n=Ye(i),i+=`${n}${e}=${t[e]}`)})),this._forceHost&&this._origin&&!(null==t?void 0:t.host)&&(n=i.indexOf("?")>-1?"&":"?",i+=`${n}host=${this._origin}`);try{const t=await fetch(i,{method:"PATCH",mode:"cors",headers:{"Content-Type":"application/sdp"},body:e}),{status:n}=t;if(n>=200&&n<300)return{success:!0,code:n};if(je.get(n))throw O(We,je.get(n)),new Error(je.get(n));{const e=await t.text();throw Error(e)}}catch(e){throw H(We,e.message),e}}async trickle(e,t={}){O(We,`[whipwhep-trickle] ${this._resource}: `+JSON.stringify(e,null,2));let i=this._resource,n=Ye(i);t&&Object.keys(t).forEach((e=>{-1===ze.indexOf(e)&&(n=Ye(i),i+=`${n}${e}=${t[e]}`)})),this._forceHost&&this._origin&&!(null==t?void 0:t.host)&&(n=Ye(i),i+=`${n}host=${this._origin}`);try{const t=await fetch(i,{method:"PATCH",mode:"cors",headers:{"Content-Type":"application/trickle-ice-sdpfrag"},body:e}),{status:n}=t;if(n>=200&&n<300){const e=await t.text();return O(We,`[whipwhep-response] ${this._resource}: ${e}`),{candidate:e}}if(405===n)throw O(We,"Remember to update the URL passed into the WHIP or WHEP client"),new Error("Remember to update the URL passed into the WHIP or WHEP client");{const e=await t.text();throw Error(e)}}catch(e){throw H(We,e.message),e}}async tearDown(e={},t=!1){if(!this._resource)return;let i=this._resource,n=Ye(i);e&&Object.keys(e).forEach((t=>{-1===ze.indexOf(t)&&(n=Ye(i),i+=`${n}${t}=${e[t]}`)})),this._forceHost&&this._origin&&!(null==e?void 0:e.host)&&(n=Ye(i),i+=`${n}host=${this._origin}`),O(We,"[whipwhep-teardown]");try{await fetch(i,{method:"DELETE",mode:"cors"})}catch(e){if(H(We,e.message),!t)throw e}this._url=void 0,this._origin=void 0,this._resource=void 0,this._forceHost=!1,this._enableSignalingChannel=!1}async post(){return O(We,"[whipwhep:post] transport called."),Promise.resolve(!1)}async postAsync(){return O(We,"[whipwhep:postAsync] transport called."),Promise.resolve(null)}getUrl(){return this._url}}const Qe="R5ProPublishView";class Ze{constructor(e="red5pro-publisher"){try{this._targetElement=ie.resolveElement(e)}catch(e){throw H(Qe,`Could not instantiate a new instance of PublishView. Reason: ${e.message}`),e}}preview(e){const t=this.isAutoplay;O(Qe,`[preview]: autoplay(${t})`),ie.setVideoSource(this._targetElement,e,t)}unpreview(){ie.setVideoSource(this._targetElement,null,this.isAutoplay)}get isAutoplay(){return ie.hasAttributeDefined(this._targetElement,"autoplay")}get view(){return this._targetElement}}var et,tt;!function(e){e.INBOUND="inbound-rtp",e.OUTBOUND="outbound-rtp",e.CODEC="codec",e.MEDIA_SOURCE="media-source",e.CANDIDATE_PAIR="candidate-pair",e.CERTIFICATE="certificate",e.DATA_CHANNEL="data-channel",e.LOCAL_CANDIDATE="local-candidate",e.REMOTE_CANDIDATE="remote-candidate",e.PEER_CONNECTION="peer-connection",e.REMOTE_INBOUND="remote-inbound-rtp",e.REMOTE_OUTBOUND="remote-outbound-rtp",e.TRANSPORT="transport"}(et||(et={})),function(e){e.STALE_STATS="STALE_STATS",e.STATE_REGRESSION="STATE_REGRESSION",e.EXCESSIVE_RTT="EXCESSIVE_RTT",e.ICE_TIMEOUT="ICE_TIMEOUT"}(tt||(tt={}));class it{constructor(e,t,i,n){this._name="RTCStatsMonitor",this._queue=[],this._startTime=0,this._stopped=!1,this._interval=0,this._candidatePairHealth=new Map,this._name=e,this._renegotiationPolicy=n,this._config={...pe,...t},this._client=i,this._identifier={name:this._name,created:(new Date).getTime(),fingerprint:ie.getOrGenerateFingerprint(),device:ie.getBrowserDetails(),client:t}}_emptyStatsReportQueue(){for(var e;this._queue.length>0;){const t=this._queue.shift(),i=null===(e=this._client)||void 0===e?void 0:e.getMessageTransport();i?i.post(t):k(this._name,"Failed to post stats data to message transport. Message transport is not available.")}}_getStats(){const{_connection:e}=this;if(e)try{e.getStats(null).then((e=>{e.forEach((e=>{this._handleStatsReport(e)}))})).catch((e=>{H(this._name,`Failed to get stats report. ${e.message||e}`)}))}catch(e){H(this._name,`Failed to get stats report. ${e.message||e}`)}}_handleStatsReport(e){console.log(`[${this._name}]: ${JSON.stringify(e,null,2)}`)}_appendClientDetails(e){this._identifier.client={...this._identifier.client,...e}}async start(e){this._startTime=(new Date).getTime(),this._stopped=!1,this._connection=e,this.postAction("started"),this._getStats(),this._interval=setInterval((()=>{this._stopped||this._getStats()}),this._config.interval)}stop(){this._stopped=!0,clearInterval(this._interval),this.postAction("ended")}async post(t){const i={...this._identifier,type:"stats-report",timestamp:(new Date).getTime(),data:t},{endpoint:n,additionalHeaders:s}=this._config;if(n===e.StatsEndpointType.DEV_NULL)return;if(this._client&&this._client.onStatsReport&&(null===n||n===e.StatsEndpointType.EVENT_TRANSPORT))return void this._client.onStatsReport(this._connection,i);let a={"Content-Type":"application/json"};if(s&&(a={...a,...s}),n&&n.match(/^(http|https):\/\//))try{const e=await fetch(n,{method:"POST",headers:a,body:JSON.stringify(i)});e.status>=200&&e.status<300?O(this._name,`Posted stats data to endpoint: ${n}.`):H(this._name,`Failed to post stats data to endpoint: ${n}. ${e.status}`)}catch(e){H(this._name,`Failed to post stats data to endpoint: ${n}. ${e.message||e}`)}else if(this._client&&this._client.getMessageTransport()&&(void 0===n||n===e.StatsEndpointType.DATA_CHANNEL))try{let t=!1;const n=this._client.getMessageTransport();n&&(t=await n.post(i)),!t&&this._client&&(this._queue.push(i),this._client.on(e.MessageTransportStateEventTypes.CHANGE,(()=>{this._client&&this._client.off(e.MessageTransportStateEventTypes.CHANGE),this._emptyStatsReportQueue()})),k(this._name,"Failed to post stats data to message transport. Message transport is not available. Pushed to Queue."))}catch(e){H(this._name,`Failed to post stats data to message transport. ${e.message||e}`)}}async postAction(e,t=void 0){return this.post({action:{type:e,data:t,timestamp:(new Date).getTime()}})}async postEvent(e,t){return this.post({event:{type:e,data:t||void 0,timestamp:(new Date).getTime()}})}updateEndpoint(e,t=!0){const{endpoint:i}=this._config;t?this._config.endpoint=e:t||i||(this._config.endpoint=e)}_checkCandidatePairHealth(e){var t;const{id:i,state:n,currentRoundTripTime:s,totalRoundTripTime:a}=e,o="connected"===this._client.getPeerConnection().iceConnectionState,r=(new Date).getTime();this._candidatePairHealth.has(i)||this._candidatePairHealth.set(i,{id:i,staleSampleCount:0,stateTransitionTime:r,inProgressStartTime:"in-progress"===n?r:void 0});const l=this._candidatePairHealth.get(i);if(void 0!==l.previousRTT&&void 0!==l.previousTotalRTT&&void 0!==s&&void 0!==a&&(s===l.previousRTT&&a===l.previousTotalRTT?(l.staleSampleCount++,l.staleSampleCount>=3&&l.lastIssueReported!==tt.STALE_STATS&&(this._client.emit(Ne.CONNECTION_HEALTH_STALE_STATS,{candidatePairId:i,frozenRTT:s,frozenTotalRTT:a,staleDurationSeconds:l.staleSampleCount,message:"RTT values frozen - connection may be dead"}),l.lastIssueReported=tt.STALE_STATS)):(l.staleSampleCount=0,l.lastIssueReported===tt.STALE_STATS&&(l.lastIssueReported=void 0))),"succeeded"!==l.previousState||"succeeded"===n||o||(this._client.emit(Ne.CONNECTION_HEALTH_STATE_REGRESSION,{candidatePairId:i,previousState:l.previousState,currentState:n,message:`ICE candidate pair regressed from '${l.previousState}' to '${n}' - connection lost`}),l.lastIssueReported=tt.STATE_REGRESSION,l.stateTransitionTime=r),void 0!==s&&s>1&&l.lastIssueReported!==tt.EXCESSIVE_RTT?(this._client.emit(Ne.CONNECTION_HEALTH_EXCESSIVE_RTT,{candidatePairId:i,currentRTT:s,message:`Excessive RTT detected: ${(1e3*s).toFixed(0)}ms - possible network issues`}),l.lastIssueReported=tt.EXCESSIVE_RTT):void 0!==s&&s<=1&&l.lastIssueReported===tt.EXCESSIVE_RTT&&(l.lastIssueReported=void 0),"in-progress"===n){l.inProgressStartTime||(l.inProgressStartTime=r);const e=r-l.inProgressStartTime;e>((null===(t=this._renegotiationPolicy)||void 0===t?void 0:t.iceTimeoutInterval)||5e3)&&l.lastIssueReported!==tt.ICE_TIMEOUT&&(this._client.emit(Ne.CONNECTION_HEALTH_ICE_TIMEOUT,{candidatePairId:i,durationSeconds:Math.floor(e/1e3),message:`ICE negotiation timeout - candidate pair stuck in 'in-progress' for ${Math.floor(e/1e3)}s`}),l.lastIssueReported=tt.ICE_TIMEOUT)}else l.inProgressStartTime=void 0,l.lastIssueReported===tt.ICE_TIMEOUT&&(l.lastIssueReported=void 0);l.previousState=n,l.previousRTT=s,l.previousTotalRTT=a,n!==l.previousState&&(l.stateTransitionTime=r)}dispose(){O(this._name,"[dispose]"),this.stop(),this._candidatePairHealth.clear(),this._connection=void 0,this._client=void 0}}const nt=/(\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b) \d+ typ srflx/,st=e=>{const t=e.match(nt);return t&&t.length>1?t[1]:null},at=[e.PublisherEventTypes.PUBLISH_START,e.PublisherEventTypes.PUBLISH_FAIL,e.PublisherEventTypes.PUBLISH_INSUFFICIENT_BANDWIDTH,e.PublisherEventTypes.PUBLISH_SUFFICIENT_BANDWIDTH,e.PublisherEventTypes.PUBLISH_RECOVERING_BANDWIDTH,e.PublisherEventTypes.STATISTICS_ENDPOINT_CHANGE];class ot extends it{constructor(t,i){if(super("RTCPublisherStats",t,i),this.estimatedAudioBitrate=0,this.estimatedVideoBitrate=0,this.lastAudioReport=null,this.lastVideoReport=null,this._eventHandler=t=>{const{type:i,data:n}=t;if(at.indexOf(i)>-1){if(i===e.PublisherEventTypes.STATISTICS_ENDPOINT_CHANGE){const{statisticsEndpoint:e}=n;this.updateEndpoint(e,!1)}this.postEvent(i)}},this._candidateCreateHandler=({data:{candidate:e}})=>{const{candidate:t}=e,i=st(t);i&&(this._identifier.publicIP=i)},this._hostEndpointChangedHandler=({data:{endpoint:e,iceServers:t}})=>{this._appendClientDetails({node:e,iceServers:t})},this._client.on("*",this._eventHandler),this._client.on(e.RTCPublisherEventTypes.CANDIDATE_CREATE,this._candidateCreateHandler),this._client.on(e.RTCPublisherEventTypes.HOST_ENDPOINT_CHANGED,this._hostEndpointChangedHandler),this._client.getPeerConnection())this.start(this._client.getPeerConnection());else{const t=({data:i})=>{this._client.off(e.RTCPublisherEventTypes.PEER_CONNECTION_AVAILABLE,t),this.start(i)};this._client.on(e.RTCPublisherEventTypes.PEER_CONNECTION_AVAILABLE,t)}}_handleStatsReport(e){const{type:t}=e,{include:i}=this._config,n=i&&i.length>0;if(n&&i.indexOf(t)>=-1)this.post(e);else if(!n)if(t===et.CODEC){const{id:i,clockRate:n,mimeType:s,payloadType:a}=e;this.post({id:i,type:t,clockRate:n,mimeType:s,payloadType:a})}else if(t===et.CANDIDATE_PAIR){const{availableOutgoingBitrate:i,currentRoundTripTime:n,totalRoundTripTime:s,state:a}=e;this._checkCandidatePairHealth(e),this.post({type:t,availableOutgoingBitrate:i,currentRoundTripTime:n,totalRoundTripTime:s,state:a})}else if(t===et.MEDIA_SOURCE){const{kind:i}=e;if("audio"===i)this.post({type:t,kind:i});else if("video"===i){const{framesPerSecond:n,height:s,width:a}=e;this.post({type:t,kind:i,framesPerSecond:n,height:s,width:a})}}else if([et.OUTBOUND,"outboundrtp"].indexOf(t)>-1){const{timestamp:i,kind:n,codecId:s,mediaType:a,active:o,bytesSent:r,packetsSent:l,totalPacketsSendDelay:h}=e,d={type:t,kind:n,codecId:s,mediaType:a,active:o,bytesSent:r,packetsSent:l,totalPacketsSendDelay:h};if("audio"===n){if(this.lastAudioReport){const{bytesSent:e,timestamp:t}=this.lastAudioReport,n=8*(r-e)/(i-t);this.estimatedAudioBitrate=n}this.post({...d,estimatedBitrate:Math.floor(this.estimatedAudioBitrate)}),this.lastAudioReport=e}else if("video"===n){const{firCount:t,pliCount:n,frameWidth:s,frameHeight:a,framesEncoded:o,framesPerSecond:l,framesSent:h,keyFramesEncoded:c,qualityLimitationReason:u,qualityLimitationDurations:p}=e;let _={...d,firCount:t,pliCount:n,frameWidth:s,frameHeight:a,framesEncoded:o,framesPerSecond:l,framesSent:h,keyFramesEncoded:c,qualityLimitationReason:"none"!==u?u:void 0,qualityLimitationDurations:"none"!==u?p:void 0};if(this.lastVideoReport){const{bytesSent:e,timestamp:t}=this.lastVideoReport,n=8*(r-e)/(i-t);this.estimatedVideoBitrate=n}this.post({..._,estimatedBitrate:Math.floor(this.estimatedVideoBitrate)}),this.lastVideoReport=e}}}dispose(){this._client.off("*",this._eventHandler),this._client.off(e.RTCPublisherEventTypes.CANDIDATE_CREATE,this._candidateCreateHandler),this._client.off(e.RTCPublisherEventTypes.HOST_ENDPOINT_CHANGED,this._hostEndpointChangedHandler),super.dispose()}}const rt={pubnub:window.PubNub,userId:`user-${Math.floor(65536*Math.random()).toString(16)}`,publishKey:void 0,subscribeKey:void 0,authToken:void 0,cloudEndpoint:void 0,backendUrl:void 0,backendURL:void 0,expiryMinutes:120,channelId:"red5",logLevel:"trace"};var lt;!function(e){e.CONNECTED="PubNub.Connected",e.DISCONNECTED="PubNub.Disconnected",e.SUBSCRIBE_SUCCESS="PubNub.Subscribe.Success",e.SUBSCRIBE_FAILURE="PubNub.Subscribe.Failure",e.UNSUBSCRIBE_SUCCESS="PubNub.Unsubscribe.Success",e.UNSUBSCRIBE_FAILURE="PubNub.Unsubscribe.Failure",e.MESSAGE_RECEIVED="PubNub.Message.Received",e.MESSAGE_SEND_SUCCESS="PubNub.Message.Send.Success",e.MESSAGE_SEND_FAILURE="PubNub.Message.Send.Failure",e.AUTH_TOKEN_GENERATED="PubNub.AuthToken.Generated",e.AUTH_TOKEN_GENERATION_ERROR="PubNub.AuthToken.Generation.Error",e.STATUS="PubNub.Status",e.ERROR="PubNub.Error"}(lt||(lt={}));const ht="PubNubService";class dt{constructor(){}_decodeToken(e){const t=e.split(".")[1].replace(/-/g,"+").replace(/_/g,"/"),i=decodeURIComponent(atob(t).split("").map((e=>"%"+("00"+e.charCodeAt(0).toString(16)).slice(-2))).join(""));return JSON.parse(i)}async getAuthTokenFromBackendService(e){var t;const{userId:i,backendUrl:n,backendURL:s,channelId:a="red5",expiryMinutes:o=120}=e;if(!n&&!s)throw new Error("Backend URL is required. Please provide a backend URL in the pubnub configuration.");const r={userId:i,channelId:a,read:!0,write:!0,ttlMinutes:o};try{const e=await fetch(n||s,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)});if(!e.ok)throw new Error("Failed to generate auth token. Please try again later.");const t=await e.json(),{token:i}=t;return i}catch(e){throw new Error(null!==(t=e.message)&&void 0!==t?t:"Failed to generate auth token. Please try again later.")}}async getAuthTokenFromCloud(e){var t;const{userId:i,cloudEndpoint:n,publishKey:s,subscribeKey:a,channelId:o="red5",expiryMinutes:r=120}=e;if(!n)throw new Error("Cloud endpoint is required. Please provide a cloud endpoint in the pubnub configuration.");try{const e=n.match(/^https?:\/\//)?n:`https://${n}`,t=await fetch(`${e}/config-meetings/api/generate-token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({userId:i,channelId:o,expirationMinutes:r})});if(!t.ok)throw new Error("Failed to generate auth token. Please try again later.");const h=await t.json(),{success:d,token:c}=h;if(!d)throw new Error("Failed to generate auth token. Please try again later.");const u=this._decodeToken(c);if(!u)throw new Error("Failed to decode auth token. Please try again later.");l=`[${ht}] :: Decoded auth token: ${JSON.stringify(u)}`,O(ht,l);const{uid:p,roomId:_,pubnubPublishKey:g,pubnubSubscribeKey:v,pubnubToken:m}=u;if(p!==i||_!==o)throw new Error("Invalid auth token. Please try again later.");if(g!==s||v!==a)throw new Error("Invalid auth token. Please try again later.");return m}catch(e){throw new Error(null!==(t=e.message)&&void 0!==t?t:"Failed to generate auth token. Please try again later.")}var l}}const ct="PubNubClient",ut={receivePresenceEvents:!0,withPresence:!1},pt=e=>O(ct,e),_t=e=>k(ct,e),gt=e=>H(ct,e);class vt extends U{constructor(){super(),this._subscriptions={}}async _getAuthFromCloud(e){const t=new dt;return await t.getAuthTokenFromCloud(e)}async _getAuthFromBackend(e){const t=new dt;return await t.getAuthTokenFromBackendService(e)}async init(e){var t,i,n,s,a,o,r;if(this._config={...rt,...e},(null===(t=this._config)||void 0===t?void 0:t.cloudEndpoint)||(null===(i=this._config)||void 0===i?void 0:i.backendUrl)||(null===(n=this._config)||void 0===n?void 0:n.backendURL)){let e;try{if((null===(s=this._config)||void 0===s?void 0:s.cloudEndpoint)?e=await this._getAuthFromCloud(this._config):((null===(a=this._config)||void 0===a?void 0:a.backendUrl)||(null===(o=this._config)||void 0===o?void 0:o.backendURL))&&(e=await this._getAuthFromBackend(this._config)),!e)throw new Error("Failed to get auth token.");this._config.authToken=e,this.trigger(new Ce(lt.AUTH_TOKEN_GENERATED,this,{authToken:e}))}catch(e){return gt(null!==(r=e.message)&&void 0!==r?r:"Failed to get auth token."),this.trigger(new Ce(lt.AUTH_TOKEN_GENERATION_ERROR,this,{error:e.message})),this}}const{pubnub:l,publishKey:h,subscribeKey:d,authToken:c,userId:u,logLevel:p}=this._config;if(!l){const e="PubNub library is not initialized. Please provide a PubNub library reference in the configuration.";throw this.trigger(new Ce(lt.ERROR,this,{error:e})),gt(e),new Error(e)}return pt(`Initializing PubNub client with options: ${JSON.stringify(this._config)}`),this._pubnub=new l({userId:u,publishKey:h,subscribeKey:d,logLevel:p}),this._pubnub.setToken(c),this._pubnub.addListener({message:e=>{var t;pt(`Message received on channel ${e.channel}: ${e.message}`),this.trigger(new Ce(lt.MESSAGE_RECEIVED,this,{...e,userId:null===(t=this._config)||void 0===t?void 0:t.userId}))},presence:e=>{pt(`Presence event on channel ${e.channel}: ${JSON.stringify(e)}`)},status:e=>{const{category:t,operation:i}=e;pt(`Status event ${t}`),this.trigger(new Ce(lt.STATUS,this,e)),"PNConnectedCategory"===t?(this.trigger(new Ce(lt.CONNECTED,this,e)),"PNSubscribeOperation"===i&&this.trigger(new Ce(lt.SUBSCRIBE_SUCCESS,this,e))):"PNDisconnectedCategory"===t?this.trigger(new Ce(lt.DISCONNECTED,this,e)):"PNReconnectedCategory"===t||("PNAcknowledgmentCategory"===t?"PNUnsubscribeOperation"===i&&this.trigger(new Ce(lt.UNSUBSCRIBE_SUCCESS,this,e)):("PNBadRequestCategory"===t||"PNAccessDeniedCategory"===t)&&this.trigger(new Ce(lt.ERROR,this,e)))}}),this}async publishMessage(e,t){var i,n;if(!this._pubnub)return gt("PubNub client not initialized."),!1;try{const n=await this._pubnub.publish({channel:e,message:t});this.trigger(new Ce(lt.MESSAGE_SEND_SUCCESS,this,{...n,channel:e,message:t,userId:null===(i=this._config)||void 0===i?void 0:i.userId}))}catch(i){return gt(null!==(n=i.message)&&void 0!==n?n:`Failed to publish message to channel ${e}.`),this.trigger(new Ce(lt.MESSAGE_SEND_FAILURE,this,{channel:e,message:t})),!1}return!0}async subscribe(e,t){var i;if(!this._pubnub)return gt("PubNub client not initialized."),!1;if(this._subscriptions[e])return!0;try{const i=this._pubnub.channel(e),n=await i.subscription({...ut,...t});if(!n)throw new Error(`Failed to subscribe to channel ${e}.`);n.subscribe(),this._subscriptions[e]=n}catch(t){return gt(null!==(i=t.message)&&void 0!==i?i:`Failed to subscribe to channel ${e}.`),this.trigger(new Ce(lt.SUBSCRIBE_FAILURE,this,{channel:e})),!1}return!0}async unsubscribe(e){var t;if(!this._pubnub)return!0;if(!this._subscriptions[e])return _t(`Subscription ${e} not found.`),!1;try{await this._subscriptions[e].unsubscribe()}catch(i){gt(null!==(t=i.message)&&void 0!==t?t:`Failed to unsubscribe from channel ${e}.`),this.trigger(new Ce(lt.UNSUBSCRIBE_FAILURE,this,{channel:e}))}return delete this._subscriptions[e],!0}async destroy(){var e;if(this._pubnub)try{await this._pubnub.destroy()}catch(t){_t(null!==(e=t.message)&&void 0!==e?e:"Failed to destroy PubNub client.")}return this._subscriptions={},this._pubnub=void 0,this._config=void 0,!0}getOptions(){var e;return null!==(e=this._config)&&void 0!==e?e:{}}get config(){return this._config}get pubnub(){return this._pubnub}}const mt="WHIPClient",Et=ge,bt=e=>O(mt,e),St=e=>H(mt,e),Ct=e=>k(mt,e);class Tt extends U{constructor(e,t,i){super();const n=e?se(e):Et,s=i||Et,a={...s,...n,endpoint:e,mediaElementId:t?t.id:s.mediaElementId};e&&this.internalInit(a),this._onOrientationChange=this._onOrientationChange.bind(this)}async internalInit(e){await this.init(e),await this.publish()}async generateMediaStream(t){var i,n;const{onGetUserMedia:s}=t;if(s){bt("Requesting gUM from user-defined configuration:onGetUserMedia.");const t=await s();return this.trigger(new Ee(e.RTCPublisherEventTypes.CONSTRAINTS_ACCEPTED,this,oe(t))),t}{const{mediaConstraints:s}=t;let a;bt(`Requesting gUM using mediaConstraints: ${JSON.stringify(s,null,2)}`);let o=s;const r=await Ve(o);return r&&r.media||(a=await ie.gUM(o)),a=null!==(i=null==r?void 0:r.media)&&void 0!==i?i:a,o=null!==(n=null==r?void 0:r.constraints)&&void 0!==n?n:s,bt(`Constraints accepted: ${JSON.stringify(o,null,2)}`),this.trigger(new Ee(e.RTCPublisherEventTypes.CONSTRAINTS_ACCEPTED,this,{constraints:o,...oe(a)})),a}}async getAndPreviewStreamIfAvailable(){var t;let i=this._mediaStream;if(!i){try{i=null!=i?i:await this.generateMediaStream(this._options)}catch(i){const n=null!==(t=i.message)&&void 0!==t?t:"Could not generate media stream.";throw this.trigger(new Ee(e.RTCPublisherEventTypes.CONSTRAINTS_REJECTED,this,{constraints:this._options.mediaConstraints})),new Error(n)}if(!i)throw new Error("Could not generate media stream.")}return this.trigger(new Ee(e.RTCPublisherEventTypes.MEDIA_STREAM_AVAILABLE,this,i)),this.preview(i),i}establishStatsMonitor(e){return new ot(e,{onStatsReport:this._onStatsReport.bind(this),getPeerConnection:this.getPeerConnection.bind(this),getMessageTransport:this.getMessageTransport.bind(this),on:this.on.bind(this),off:this.off.bind(this),trigger:this.trigger.bind(this),emit:this.emit.bind(this)})}postStatsMonitorEvent(e,t){this._statsMonitor&&this._statsMonitor.postEvent(e,t)}reorderCodecPreferences(e,t,i){e.getTransceivers().forEach((e=>{if(e.sender&&e.sender.track){const{kind:n}=e.sender.track;if(t&&"video"===n&&e.setCodecPreferences)try{const{codecs:i}=RTCRtpSender.getCapabilities("video"),n=i.findIndex((e=>e.mimeType===`video/${t}`));if(n>-1){const t=i.slice(0),s=i[n];t.splice(n,1),t.unshift(s),e.setCodecPreferences(t)}}catch(e){Ct(`[videoEncoding] Could not set codec preferences for ${t}. ${e.message||e}`)}else if(i&&"audio"===n&&e.setCodecPreferences)try{const{codecs:t}=RTCRtpSender.getCapabilities("audio"),n=t.findIndex((e=>e.mimeType===`audio/${i}`));if(n>-1){const i=t[n];t.splice(n,1),t.unshift(i),e.setCodecPreferences(t)}}catch(e){Ct(`[audioEncoding] Could not set codec preferences for ${i}. ${e.message||e}`)}}}))}async postOffer(t){var i;try{const{sdp:n}=t;let{videoEncoding:s}=this._options;const{mungeOffer:a,streamMode:o,keyFramerate:r,iceTransport:l,connectionParams:h,mediaConstraints:d,forceVP8:c,audioEncoding:u,offerSDPResolution:p}=this._options;c&&!s&&(s=e.PublishVideoEncoder.VP8);let _=n;a&&(bt(`[MUNGE:before] offer: ${_}`),_=a(_),bt(`[MUNGE:after] offer: ${_}`)),p&&(bt(`[MUNGE] Setting resolution on offer: ${_}`),_=((e,t)=>{if(!t)return e;const{width:i,height:n}=t;if(!i||!n)return e;const s=`a=framesize:${i}-${n}`,a=e.split("\r\n");let o=a.length;const r=/^m=video/;for(;--o>-1;)if(r.exec(a[o])){for(;++o-1){a.splice(o+1,0,s);break}break}return a.join("\r\n")})(_,((e,t)=>{let i;if(e)try{const t=e.getVideoTracks()&&e.getVideoTracks()[0];if(t){const e=t.getSettings();i={width:e.width,height:e.height}}}catch(e){k("[determineMediaResolution]",`Could not determine resolution from MediaStream. ${e.message||e}`)}if(!i)try{const e=t.video,{width:n,height:s}=e;if(n&&s)if("number"==typeof n&&"number"==typeof s)i={width:n,height:s};else{i={width:n.exact||n.min||n.max||n.ideal||640,height:s.exact||s.min||s.max||s.ideal||480}}}catch(e){k("[determineMediaResolution]",`Could not determine resolution from MediaConstraints. ${e.message||e}`)}return i&&O("[determineMediaResolution]",`constraints: ${JSON.stringify(i,null,2)}`),i})(this._mediaStream,d)),bt(`[MUNGE:after] offer: ${_}`));const g={...h,mode:o,transport:l,keyFramerate:r};return s&&(g.videoEncoding=s),u&&(g.audioEncoding=u),await(null===(i=this._whipWhepService)||void 0===i?void 0:i.postSDPOffer(_,g))}catch(t){throw St(t.message||t),t instanceof xe?this.trigger(new Ee(e.PublisherEventTypes.PUBLISH_INVALID_NAME,this)):(this.trigger(new Ee(e.PublisherEventTypes.CONNECT_FAILURE,this,t)),this.unpublish()),t}}async postCandidateFragments(e){var t;const{connectionParams:i}=this._options,n=Fe(e,void 0,!0);return await(null===(t=this._whipWhepService)||void 0===t?void 0:t.trickle(n,i))}async initPubNub(e){var t;try{const t=new vt;this._pubnubClient=t,this._pubnubClient.on("*",(e=>{this.trigger(e)})),await t.init(e)}catch(e){return e(null!==(t=e.message)&&void 0!==t?t:"Failed to initialize PubNub."),!1}return!0}async deinitPubNub(){var e,t;try{await(null===(e=this._pubnubClient)||void 0===e?void 0:e.destroy()),this._pubnubClient=void 0}catch(e){return e(null!==(t=e.message)&&void 0!==t?t:"Failed to deinitialize PubNub."),!1}return!0}async init(e){var t,i;this._options={...Et,...e};const n=ae(this._options),{includeDataChannel:s,disableProxy:a}=this._options;return this._whipWhepService=new Xe(n,s,a),this._messageTransport=this._whipWhepService,(null===(t=this._options)||void 0===t?void 0:t.stats)&&this.monitorStats(this._options.stats),this._mediaStream=await this.getAndPreviewStreamIfAvailable(),(null===(i=this._options)||void 0===i?void 0:i.pubnub)&&await this.initPubNub(this._options.pubnub),this}async initWithStream(e,t){return this._mediaStream=t,this.init(e)}async publish(t){var i,n,s,a,o;t&&(this._options.streamName=t);const{forceVP8:r,audioEncoding:l,rtcConfiguration:h,dataChannelConfiguration:d,includeDataChannel:c,signalingSocketOnly:u,enableChannelSignaling:p,connectionParams:_,bandwidth:g,mungeAnswer:v}=this._options;let{videoEncoding:m}=this._options;r&&(m=e.PublishVideoEncoder.VP8,this._options.videoEncoding=m),this._mediaStream||(this._mediaStream=await this.getAndPreviewStreamIfAvailable());try{const t=null!=_?_:{};if(_){const{transcode:e}=_;e&&(t.transcode=e)}const o=await(null===(i=this._whipWhepService)||void 0===i?void 0:i.getOptions(t)),r=!!(null===(n=this._options)||void 0===n?void 0:n.rtcConfiguration)&&Array.isArray(this._options.rtcConfiguration.iceServers)&&this._options.rtcConfiguration.iceServers.length>0;(null==o?void 0:o.links)&&!r&&(this._options.rtcConfiguration={...h,iceServers:o.links}),(null==o?void 0:o.origin)&&this.trigger(new Ee(e.RTCPublisherEventTypes.HOST_ENDPOINT_CHANGED,this,{endpoint:o.origin})),(null==o?void 0:o.statisticsEndpoint)&&this._onStatisticsEndpointChange(o.statisticsEndpoint);const E=c||p||u?d:void 0;this._peerConnectionHelper=new Ge({onDataChannelError:this._onDataChannelError.bind(this),onSendReceived:this._onSendReceived.bind(this),onMetaData:this._onMetaData.bind(this),onConnectionClosed:this._onConnectionClosed.bind(this),onDataChannelOpen:this._onDataChannelOpen.bind(this),onDataChannelClose:this._onDataChannelClose.bind(this),onDataChannelMessage:this._onDataChannelMessage.bind(this),onPeerConnectionOpen:this._onPeerConnectionOpen.bind(this),onPeerConnectionFail:this._onPeerConnectionFail.bind(this),onPeerConnectionClose:this._onPeerConnectionClose.bind(this),onIceCandidate:this._onIceCandidate.bind(this),onSDPSuccess:this._onSDPSuccess.bind(this),onSDPError:this._onSDPError.bind(this),onStatisticsEndpointChange:this._onStatisticsEndpointChange.bind(this),onPublisherStatus:this._onPublisherStatus.bind(this),onPeerConnectionTrackAdd:this._onPeerConnectionTrackAdd.bind(this),onInsufficientBandwidth:this._onInsufficientBandwidth.bind(this),onSufficientBandwidth:this._onSufficientBandwidth.bind(this),onRecoveringBandwidth:this._onRecoveringBandwidth.bind(this),onUnpublish:this._onUnpublish.bind(this)}),await this._peerConnectionHelper.setUpWithPeerConfiguration(this._options.rtcConfiguration,E),this.trigger(new Ee(e.RTCPublisherEventTypes.PEER_CONNECTION_AVAILABLE,this,this.getPeerConnection())),this._mediaStream&&this._mediaStream.getTracks().forEach((e=>{var t;null===(t=this.getPeerConnection())||void 0===t||t.addTransceiver(e,{direction:"sendonly"})})),this.reorderCodecPreferences(this.getPeerConnection(),m,l);const b=await(null===(s=this._peerConnectionHelper)||void 0===s?void 0:s.createOfferWithoutSetLocal(g));await this._peerConnectionHelper.setLocalDescription(b),this.trigger(new Ee(e.RTCPublisherEventTypes.OFFER_START,this,b));const{sdp:S}=await this.postOffer(b);let C=S;v&&(bt(`[MUNGE:before] answer: ${C}`),C=v(C),bt(`[MUNGE:after] answer: ${C}`)),await this._peerConnectionHelper.setRemoteDescription({type:"answer",sdp:C}),this.trigger(new Ee(e.RTCPublisherEventTypes.OFFER_END,this,C));const T=await this._peerConnectionHelper.waitToGatherIce(),{sdp:y}=T;return await this.postCandidateFragments(y),this.trigger(new Ee(e.RTCPublisherEventTypes.ICE_TRICKLE_COMPLETE,this)),ie.addOrientationChangeHandler(this._onOrientationChange),(null===(a=this._options)||void 0===a?void 0:a.includeDataChannel)||this.trigger(new Ee(e.PublisherEventTypes.PUBLISH_START,this)),this}catch(t){throw St(null!==(o=t.message)&&void 0!==o?o:"Could not publish."),this.trigger(new Ee(e.PublisherEventTypes.CONNECT_FAILURE,this,t)),this.unpublish(!0),t}}async unpublish(t=!1){var i;bt("[unpublish]"),this._peerConnectionHelper&&await this._peerConnectionHelper.tearDown(),this._whipWhepService&&await this._whipWhepService.tearDown(null,t),(null===(i=this._options)||void 0===i?void 0:i.clearMediaOnUnpublish)&&this.unpreview(),this._pubnubClient&&await this.deinitPubNub(),this.unmonitorStats(),this._pubnubClient=void 0,this._mediaStream=void 0,this._peerConnectionHelper=void 0,this._whipWhepService=void 0,this._messageTransport=void 0,this._publishView=void 0,this.trigger(new Ee(e.PublisherEventTypes.UNPUBLISH_SUCCESS,this)),ie.removeOrientationChangeHandler(this._onOrientationChange)}preview(e){const{mediaElementId:t}=this._options;t&&(bt("[preview]"),this._publishView=new Ze(t),this._publishView.preview(e))}unpreview(){this._mediaStream&&this._mediaStream.getTracks().forEach((e=>{e.stop()})),this._publishView&&(bt("[unpreview]"),this._publishView.unpreview()),this._publishView=void 0}monitorStats(e){bt("[monitorStats]");const{host:t,endpoint:i,app:n,streamName:s,connectionParams:a}=this._options,o=null!=e?e:pe;return this._statisticsConfiguration={...o,host:t,hostEndpoint:i,app:n,streamName:s,connectionParams:a},this._statsMonitor?Ct("Cannot monitor stats without a Peer Connection. Please call `init` before calling `monitorStats`."):this._statsMonitor=this.establishStatsMonitor(this._statisticsConfiguration),this}unmonitorStats(){return this._statsMonitor&&this._statsMonitor.dispose(),this._statsMonitor=void 0,this._statisticsConfiguration=void 0,this}muteAudio(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteAudio:!0}})}unmuteAudio(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteAudio:!1}})}muteVideo(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteVideo:!0}})}unmuteVideo(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteVideo:!1}})}async send(e,t){var i;let n=t;try{n="string"==typeof t?JSON.parse(t):t}catch(e){Ct(`Could not parse data as JSON. Sending as message. Error: ${e.message||e}`),n={message:t}}return null===(i=this.getMessageTransport())||void 0===i?void 0:i.post({send:{method:e,data:n}})}async sendPubNub(e,t){return this._pubnubClient?await this._pubnubClient.publishMessage(e,t):(St("PubNub client not initialized."),!1)}async subscribePubNub(e,t){return this._pubnubClient?await this._pubnubClient.subscribe(e,t):(St("PubNub client not initialized."),!1)}async unsubscribePubNub(e){return this._pubnubClient?await this._pubnubClient.unsubscribe(e):(St("PubNub client not initialized."),!1)}async callServer(e,t){var i;try{if(!this.getMessageTransport())throw new Error("Message transport not available");return null===(i=this.getMessageTransport())||void 0===i?void 0:i.postAsync({callAdapter:{method:e,arguments:t}})}catch(e){St(e.message||e)}}sendLog(e,t){var i;try{const n=Object.keys(R).find((t=>t.toLowerCase()===e.toLowerCase()))?e:R.DEBUG,s="string"==typeof t?t:JSON.stringify(t);null===(i=this.getMessageTransport())||void 0===i||i.post({log:n.toUpperCase(),message:s})}catch(e){const t=e.message||e;St("Could not send log to server. Message parameter expected to be String or JSON-serializable object."),St(t)}}get options(){return this._options}getOptions(){return this._options}getPeerConnection(){var e;return null===(e=this._peerConnectionHelper)||void 0===e?void 0:e.connection}getDataChannel(){var e;return null===(e=this._peerConnectionHelper)||void 0===e?void 0:e.dataChannel}getMediaStream(){return this._mediaStream}getMessageTransport(){return this._messageTransport}getPubNubClient(){return this._pubnubClient}_onDataChannelError(t,i){St(`Data channel error: ${i}`),this.trigger(new Ee(e.RTCPublisherEventTypes.DATA_CHANNEL_ERROR,this,{dataChannel:t,error:i}))}_onSendReceived(t,i){bt(`Send received: ${t} ${JSON.stringify(i)}`),"onMetaData"===t?this._onMetaData(i):this.trigger(new Ee(e.PublisherEventTypes.PUBLISH_SEND_INVOKE,this,{methodName:t,data:i}))}_onMetaData(t){bt(`Metadata received: ${JSON.stringify(t)}`),this.trigger(new Ee(e.PublisherEventTypes.PUBLISH_METADATA,this,t))}_onConnectionClosed(){bt("Connection closed"),this.unpublish(),this.trigger(new Ee(e.PublisherEventTypes.CONNECTION_CLOSED,this))}_onDataChannelOpen(t){bt(`Data channel opened: ${t.label}`),this.trigger(new Ee(e.RTCPublisherEventTypes.DATA_CHANNEL_OPEN,this,{dataChannel:t})),this.trigger(new Ee(e.RTCPublisherEventTypes.DATA_CHANNEL_AVAILABLE,this,{name:t.label,dataChannel:t})),this._messageTransport=this._peerConnectionHelper,this.trigger(new Se(e.MessageTransportStateEventTypes.CHANGE,this,{controller:this,transport:this._messageTransport})),this.trigger(new Ee(e.PublisherEventTypes.PUBLISH_START,this))}_onDataChannelClose(t){bt(`Data channel closed: ${t.label}`),this.trigger(new Ee(e.RTCPublisherEventTypes.DATA_CHANNEL_CLOSE,this,{dataChannel:t}))}_onDataChannelMessage(t,i){bt(`Data channel message: ${i.data}`),this.trigger(new Ee(e.RTCPublisherEventTypes.DATA_CHANNEL_MESSAGE,this,{dataChannel:t,message:i}))}_onPeerConnectionTrackAdd(t){bt(`Peer connection track added: ${t.id}`),this.trigger(new Ee(e.RTCPublisherEventTypes.TRACK_ADDED,this,{track:t}))}_onPeerConnectionOpen(){bt("Peer connection opened"),this.trigger(new Ee(e.RTCPublisherEventTypes.PEER_CONNECTION_OPEN,this,this.getPeerConnection()))}_onPeerConnectionFail(){St("Peer connection failed"),this.trigger(new Ee(e.PublisherEventTypes.PUBLISH_FAIL,this))}_onPeerConnectionClose(t){bt(`Peer connection closed: ${t.type}`),this._peerConnectionHelper&&this._peerConnectionHelper.tearDown(),this.trigger(new Ee(e.PublisherEventTypes.CONNECTION_CLOSED,this,t))}_onIceCandidate(t){bt(`ICE candidate: ${JSON.stringify(t,null,2)}`),this.trigger(new Ee(e.RTCPublisherEventTypes.CANDIDATE_CREATE,this,{candidate:t}))}_onUnpublish(){bt("Unpublish received")}_onPublisherStatus(t){bt("[publisherstatus] - "+JSON.stringify(t,null,2)),t.code&&"NetStream.Publish.IsAvailable"===t.code?this.trigger(new Ee(e.PublisherEventTypes.PUBLISH_AVAILABLE,this,t)):this.trigger(new Ee(e.PublisherEventTypes.PUBLISH_STATUS,this,t))}_onInsufficientBandwidth(t){this.trigger(new Ee(e.PublisherEventTypes.PUBLISH_INSUFFICIENT_BANDWIDTH,this,t))}_onSufficientBandwidth(t){this.trigger(new Ee(e.PublisherEventTypes.PUBLISH_SUFFICIENT_BANDWIDTH,this,t))}_onRecoveringBandwidth(t){this.trigger(new Ee(e.PublisherEventTypes.PUBLISH_RECOVERING_BANDWIDTH,this,t))}_onSDPSuccess(e=void 0){const t=e?": "+JSON.stringify(e,null,2):"";bt(`[onsdpsuccess]:: ${t}`)}_onSDPError(t=void 0){this.trigger(new Ee(e.PublisherEventTypes.PUBLISH_FAIL,this));const i=t?": "+JSON.stringify(t,null,2):"";St(`[onsdperror]:: ${i}`)}_onOrientationChange(e){const t=this.getMessageTransport();t&&t.post({send:{method:"onMetaData",data:{deviceOrientation:e}}})}_onStatisticsEndpointChange(t){bt(`Statistics endpoint changed: ${t}`),this._statsMonitor&&this._statsMonitor.updateEndpoint(t),this.trigger(new Ee(e.PublisherEventTypes.STATISTICS_ENDPOINT_CHANGE,this,{statisticsEndpoint:t}))}_onStatsReport(t,i){this.trigger(new Ee(e.RTCPublisherEventTypes.STATS_REPORT,this,{connection:t,report:i}))}on(e,t){super.on(e,t)}off(e,t){super.off(e,t)}trigger(e){super.trigger(e)}emit(e,t){this.trigger(new Ee(e,this,t))}getType(){return"RTC"}}const yt={...{protocol:"https",port:443,app:"live",autoLayoutOrientation:!0,mediaElementId:"red5pro-subscriber",rtcConfiguration:{iceCandidatePoolSize:2,bundlePolicy:"max-bundle"},iceTransport:he.UDP,muteOnAutoplayRestriction:!0,maintainConnectionOnSubscribeErrors:!1,dataChannelConfiguration:{name:"red5pro"},signalingSocketOnly:!1,includeDataChannel:!0,maintainStreamVariant:!1,buffer:0,stats:void 0,pubnub:void 0,renegotiationPolicy:void 0},signalingSocketOnly:!1,enableChannelSignaling:!1,includeDataChannel:!0,disableProxy:!0,trickleIce:!0,postEmptyOffer:!1,mungeOffer:void 0,mungeAnswer:void 0},ft={protocol:"https",port:443,app:"live",mediaElementId:"red5pro-subscriber",muteOnAutoplayRestriction:!0},wt={endpoint:e.StatsEndpointType.DEV_NULL,interval:3e3},At="R5ProPlaybackView";class Pt{constructor(e="red5pro-subscriber"){try{this._targetElement=ie.resolveElement(e)}catch(e){throw H(At,`Could not instantiate a new instance of Red5ProSubscriber. Reason: ${e.message||e}`),e}}attachStream(e){const t=this.isAutoplay;O(At,"[attachstream]"),ie.setVideoSource(this._targetElement,e,t)}detachStream(){O(At,"[detachstream]"),ie.setVideoSource(this._targetElement,null,this.isAutoplay)}get isAutoplay(){return ie.hasAttributeDefined(this._targetElement,"autoplay")}get view(){return this._targetElement}}const Nt="RTCPeerConnectionSubscriber";class Rt extends Ie{constructor(e){super(e,Nt)}_removeConnectionHandlers(e){e.onconnectionstatechange=null,e.oniceconnectionstatechange=null,e.onicegatheringstatechange=null,e.onsignalingstatechange=null,e.onicecandidate=null,e.ontrack=null,e.onnegotiationneeded=null}_addConnectionHandlers(e){let t;e.onsignalingstatechange=()=>{const t=e.signalingState;O(Nt,`[peer.onsignalingstatechange] - State: ${t}`)},e.onconnectionstatechange=()=>{const{connectionState:t}=e;"connected"===t?(O(this._name,"[peerconnection:open]"),this._responder.onPeerConnectionOpen()):"failed"===t||"disconnected"===t?(k(this._name,`[peerconnection:error]:: ${t}`),"failed"===t&&this._responder.onPeerConnectionFail()):O(this._name,`[peerconnection:state]:: ${t}`)},e.oniceconnectionstatechange=i=>{const{iceConnectionState:n}=e;O(this._name,`[peer.oniceconnectionstatechange] - State: ${n}`),"failed"===n?(t&&clearTimeout(t),this._responder.onPeerConnectionFail(),this._responder.onPeerConnectionClose(i)):"disconnected"===n?t=setTimeout((()=>{O(this._name,"[peer.oniceconnectionstatechange] - Reconnect timeout reached."),clearTimeout(t),this._responder.onPeerConnectionClose(i)}),3e3):t&&(O(this._name,"[peer.oniceconnectionstatechange] - Clearing timeout for reconnect."),clearTimeout(t))},e.onicecandidate=e=>{const{candidate:t}=e;O(this._name,`[peer.onicecandidate] - Peer Candidate: ${null==t?void 0:t.candidate}`),t&&this._responder.onIceCandidate(t)},e.onnegotiationneeded=()=>{O(this._name,"[peer.onnegotiationneeded]")},e.onicegatheringstatechange=()=>{const{iceGatheringState:t}=e;O(this._name,`[peer.onicegatheringstatechange] - State: ${t}`)}}_onDataChannelMessage(e){const t=e;if(super._onDataChannelMessage(e))return!0;const i=this.getJsonFromSocketMessage(t);if(null===i)return k(this._name,"Determined websocket response not in correct format. Aborting message handle."),!0;O(this._name,"[datachannel-response]: "+JSON.stringify(i,null,2));const{data:n}=i;if(n&&"status"===n.type)return"NetStream.Play.UnpublishNotify"===n.code?(this._responder.onUnpublish(),this._responder.onConnectionClosed(),!0):"Application.Statistics.Endpoint"===n.code?(this._responder.onStatisticsEndpointChange(n.statistics),!0):(O(Nt,`[datachannel.message] status :: ${n.code}`),this._responder.onSubscriberStatus(n),!0);if(n&&n.status&&"NetStream.Play.UnpublishNotify"===n.status)return this._responder.onUnpublish(),this._responder.onConnectionClosed(),!0;if(n&&"result"===n.type){const{message:e}=n;if("Stream switch: Success"===e)try{return this._responder.onStreamSwitchComplete(),!0}catch(e){}}return this._responder.onDataChannelMessage(this._dataChannel,t),!1}}var Lt;!function(e){e.EMPTY="Empty",e.VIDEO="Video",e.AUDIO="Audio",e.FULL="Video/Audio"}(Lt||(Lt={}));class It extends U{trigger(e){super.trigger(e)}on(e,t){super.on(e,t)}off(e,t){super.off(e,t)}}class Dt extends It{}const Ot=[e.SubscriberEventTypes.SUBSCRIBE_START,e.SubscriberEventTypes.SUBSCRIBE_STOP,e.SubscriberEventTypes.SUBSCRIBE_FAIL,e.SubscriberEventTypes.SUBSCRIBE_PUBLISHER_CONGESTION,e.SubscriberEventTypes.SUBSCRIBE_PUBLISHER_RECOVERY,e.SubscriberEventTypes.PLAY_UNPUBLISH,e.SubscriberEventTypes.STREAMING_MODE_CHANGE,e.SubscriberEventTypes.PLAYBACK_STATE_CHANGE,e.SubscriberEventTypes.STATISTICS_ENDPOINT_CHANGE];class kt extends it{constructor(t,i,n){if(super("RTCSubscriberStats",t,i,n),this.estimatedAudioBitrate=0,this.estimatedVideoBitrate=0,this.lastAudioReport=null,this.lastVideoReport=null,this._eventHandler=t=>{const{type:i,data:n}=t;if(Ot.indexOf(i)>-1)if(i===e.SubscriberEventTypes.STREAMING_MODE_CHANGE){const{streamingMode:e,previousStreamingMode:t}=n;this.postEvent(i,{data:{streamingMode:e,previousStreamingMode:t}})}else if(i===e.SubscriberEventTypes.PLAYBACK_STATE_CHANGE){const{code:t}=n;let i;t===e.PlaybackState.AVAILABLE&&(i={timeToFirstFrameMS:(new Date).getTime()-this._startTime}),this.postEvent(a[t],i)}else{if(i===e.SubscriberEventTypes.STATISTICS_ENDPOINT_CHANGE){const{statisticsEndpoint:e}=n;this.updateEndpoint(e,!1)}this.postEvent(i)}},this._candidateCreateHandler=({data:{candidate:e}})=>{const{candidate:t}=e,i=st(t);i&&(this._identifier.publicIP=i)},this._hostEndpointChangedHandler=({data:{endpoint:e,iceServers:t}})=>{this._appendClientDetails({node:e,iceServers:t})},this._client.on("*",this._eventHandler),this._client.on(e.RTCSubscriberEventTypes.CANDIDATE_CREATE,this._candidateCreateHandler),this._client.on(e.RTCSubscriberEventTypes.HOST_ENDPOINT_CHANGED,this._hostEndpointChangedHandler),this._client.getPeerConnection())this.start(this._client.getPeerConnection());else{const t=({data:i})=>{this._client.off(e.RTCSubscriberEventTypes.PEER_CONNECTION_AVAILABLE,t),this.start(i)};this._client.on(e.RTCSubscriberEventTypes.PEER_CONNECTION_AVAILABLE,t)}}_handleStatsReport(e){const{type:t}=e,{include:i}=this._config,n=i&&i.length>0;if(n&&i.indexOf(t)>=-1)this.post(e);else if(!n)if(t===et.CODEC){const{id:i,clockRate:n,mimeType:s,payloadType:a}=e;this.post({id:i,type:t,clockRate:n,mimeType:s,payloadType:a})}else if(t===et.CANDIDATE_PAIR){const{availableOutgoingBitrate:i,currentRoundTripTime:n,totalRoundTripTime:s,state:a}=e;this._checkCandidatePairHealth(e),this.post({type:t,availableOutgoingBitrate:i,currentRoundTripTime:n,totalRoundTripTime:s,state:a})}else if([et.INBOUND,"inboundrtp"].indexOf(t)>-1){const{timestamp:i,kind:n,codecId:s,jitter:a,packetsLost:o,packetsReceived:r,bytesReceived:l}=e,h={type:t,kind:n,codecId:s,jitter:a,packetsLost:o,packetsReceived:r,bytesReceived:l};if("audio"===n){const{packetsDiscarded:t}=e;if(this.lastAudioReport){const{bytesReceived:e,timestamp:t}=this.lastAudioReport,n=8*(l-e)/(i-t);this.estimatedAudioBitrate=n}this.post({...h,packetsDiscarded:t,estimatedBitrate:Math.floor(this.estimatedAudioBitrate)}),this.lastAudioReport=e}else if("video"===n){const{firCount:t,frameWidth:n,frameHeight:s,framesDecoded:a,framesDropped:o,framesPerSecond:r,framesReceived:d,freezeCount:c,keyFramesDecoded:u,nackCount:p,pauseCount:_,pliCount:g,totalFreezesDuration:v,totalPausesDuration:m}=e,E={...h,firCount:t,frameWidth:n,frameHeight:s,framesDecoded:a,framesDropped:o,framesPerSecond:r,framesReceived:d,freezeCount:c,keyFramesDecoded:u,nackCount:p,pauseCount:_,pliCount:g,totalFreezesDuration:v,totalPausesDuration:m};if(this.lastVideoReport){const{bytesReceived:e,timestamp:t}=this.lastVideoReport,n=8*(l-e)/(i-t);this.estimatedVideoBitrate=n}this.post({...E,estimatedBitrate:Math.floor(this.estimatedVideoBitrate)}),this.lastVideoReport=e}}}dispose(){this._client.off("*",this._eventHandler),this._client.off(e.RTCSubscriberEventTypes.CANDIDATE_CREATE,this._candidateCreateHandler),this._client.off(e.RTCSubscriberEventTypes.HOST_ENDPOINT_CHANGED,this._hostEndpointChangedHandler),super.dispose()}}class Ht extends Dt{constructor(e,t){super(),this._isVOD=!1,this._name=`SourceHandler-${t}`,this._view=e,this._playbackNotificationCenter=this._view,this.onCanPlay=this._onCanPlay.bind(this),this.onDurationChange=this._onDurationChange.bind(this),this.onEnded=this._onEnded.bind(this),this.onTimeUpdate=this._onTimeUpdate.bind(this),this.onPlay=this._onPlay.bind(this),this.onPause=this._onPause.bind(this),this.onVolumeChange=this._onVolumeChange.bind(this),this.onLoadedData=this._onLoadedData.bind(this),this.onLoadedMetadata=this._onLoadedMetadata.bind(this),this.onResize=this._onResize.bind(this),this.onLoadStart=this._onLoadStart.bind(this),this.onSuspend=this._onSuspend.bind(this),this.onStalled=this._onStalled.bind(this),this.onWaiting=this._onWaiting.bind(this),this.onError=this._onError.bind(this),this.onEncrypted=this._onEncrypted.bind(this),this._addPlaybackNotificationCenterHandlers(this._playbackNotificationCenter),ie.onFullScreenStateChange(this._handleFullScreenChange.bind(this))}_addPlaybackNotificationCenterHandlers(e){e.addEventListener("canplay",this.onCanPlay),e.addEventListener("durationchange",this.onDurationChange),e.addEventListener("ended",this.onEnded),e.addEventListener("timeupdate",this.onTimeUpdate),e.addEventListener("play",this.onPlay),e.addEventListener("pause",this.onPause),e.addEventListener("volumechange",this.onVolumeChange),e.addEventListener("loadeddata",this.onLoadedData),e.addEventListener("loadedmetadata",this.onLoadedMetadata),e.addEventListener("resize",this.onResize),e.addEventListener("loadstart",this.onLoadStart),e.addEventListener("suspend",this.onSuspend),e.addEventListener("stalled",this.onStalled),e.addEventListener("waiting",this.onWaiting),e.addEventListener("error",this.onError),e.addEventListener("encrypted",this.onEncrypted)}_removePlaybackNotificationCenterHandlers(e){e.removeEventListener("canplay",this.onCanPlay),e.removeEventListener("durationchange",this.onDurationChange),e.removeEventListener("ended",this.onEnded),e.removeEventListener("timeupdate",this.onTimeUpdate),e.removeEventListener("play",this.onPlay),e.removeEventListener("pause",this.onPause),e.removeEventListener("volumechange",this.onVolumeChange),e.removeEventListener("loadeddata",this.onLoadedData),e.removeEventListener("loadedmetadata",this.onLoadedMetadata),e.removeEventListener("resize",this.onResize),e.removeEventListener("loadstart",this.onLoadStart),e.removeEventListener("suspend",this.onSuspend),e.removeEventListener("stalled",this.onStalled),e.removeEventListener("waiting",this.onWaiting),e.removeEventListener("error",this.onError)}_handleFullScreenChange(t){var i,n;t?null===(i=this._view)||void 0===i||i.classList.add("red5pro-media-container-full-screen"):null===(n=this._view)||void 0===n||n.classList.remove("red5pro-media-container-full-screen"),this.trigger(new be(e.SubscriberEventTypes.FULL_SCREEN_STATE_CHANGE,void 0,t))}_cleanup(){this._playbackNotificationCenter&&this._removePlaybackNotificationCenterHandlers(this._playbackNotificationCenter),this._playbackNotificationCenter=void 0,this._view=void 0}_onCanPlay(t){var i;O(this._name,"[videoelement:event] canplay");const n=null!==(i=this._playbackNotificationCenter)&&void 0!==i?i:t.target,a=this.getControls();a&&a.enable(!0),this.trigger(new be(e.SubscriberEventTypes.PLAYBACK_STATE_CHANGE,void 0,{code:e.PlaybackState.AVAILABLE,state:s.AVAILABLE})),this.trigger(new be(e.SubscriberEventTypes.VOLUME_CHANGE,void 0,{volume:n.volume}))}_onDurationChange(e){var t;O(this._name,"[videoelement:event] durationchange");const i=null!==(t=this._playbackNotificationCenter)&&void 0!==t?t:e.target,n=this.getControls();n&&n.setPlaybackDuration(i.duration),!isNaN(i.duration)&&Number.isFinite(i.duration)&&(this._isVOD=!0)}_onEnded(){O(this._name,"[videoelement:event] ended");const t=this.getControls();t&&t.setState(e.PlaybackState.IDLE),this.trigger(new be(e.SubscriberEventTypes.PLAYBACK_STATE_CHANGE,void 0,{code:e.PlaybackState.IDLE,state:s.IDLE}))}_onTimeUpdate(t){var i;const n=null!==(i=this._playbackNotificationCenter)&&void 0!==i?i:t.target,s=this.getControls();s&&s.setSeekTime(n.currentTime,this.isVOD()?n.duration:void 0),this.trigger(new be(e.SubscriberEventTypes.PLAYBACK_TIME_UPDATE,void 0,{time:n.currentTime,duration:n.duration}))}_onPlay(){O(this._name,"[videoelement:event] play");const t=this.getControls();t&&t.setState(e.PlaybackState.PLAYING),this.trigger(new be(e.SubscriberEventTypes.PLAYBACK_STATE_CHANGE,void 0,{code:e.PlaybackState.PLAYING,state:s.PLAYING}))}_onPause(){O(this._name,"[videoelement:event] pause");const t=this.getControls();t&&t.setState(e.PlaybackState.PAUSED),this.trigger(new be(e.SubscriberEventTypes.PLAYBACK_STATE_CHANGE,void 0,{code:e.PlaybackState.PAUSED,state:s.PAUSED}))}_onVolumeChange(t){var i;O(this._name,"[videoelement:event] volumechange");const n=null!==(i=this._playbackNotificationCenter)&&void 0!==i?i:t.target,s=this.getControls();s&&s.getVolume()!==n.volume&&s.setVolume(n.volume),this.trigger(new be(e.SubscriberEventTypes.VOLUME_CHANGE,void 0,{volume:n.volume}))}_onLoadedData(t){var i,n,s;O(this._name,"[videoelement:event] loadeddata");const a=null!==(i=this._view)&&void 0!==i?i:t.target;this.trigger(new be(e.SubscriberEventTypes.VIDEO_DIMENSIONS_CHANGE,void 0,{width:null!==(n=a.videoWidth)&&void 0!==n?n:0,height:null!==(s=a.videoHeight)&&void 0!==s?s:0}))}_onLoadedMetadata(t){var i,n;O(this._name,"[videoelement:event] loadedmetadata");const s=null!==(i=this._view)&&void 0!==i?i:t.target;this.trigger(new be(e.SubscriberEventTypes.LOADED_METADATA,void 0,{duration:null!==(n=s.duration)&&void 0!==n?n:0}))}_onResize(t){var i,n,s;O(this._name,"[videoelement:event] resize");const a=null!==(i=this._view)&&void 0!==i?i:t.target;this.trigger(new be(e.SubscriberEventTypes.VIDEO_DIMENSIONS_CHANGE,void 0,{width:null!==(n=a.videoWidth)&&void 0!==n?n:0,height:null!==(s=a.videoHeight)&&void 0!==s?s:0}))}_onLoadStart(){O(this._name,"[videoelement:event] loadstart")}_onSuspend(){O(this._name,"[videoelement:event] suspend")}_onStalled(){O(this._name,"[videoelement:event] stalled")}_onWaiting(){O(this._name,"[videoelement:event] waiting")}_onEncrypted(){O(this._name,"[videoelement:event] encrypted")}_onError(t){O(this._name,"[videoelement:event] error"),this.trigger(new be(e.SubscriberEventTypes.CONNECT_FAILURE,void 0,{error:t.message}))}async attemptAutoplay(t=!1){try{await this.play(),this.isMuted()&&this.trigger(new be(e.SubscriberEventTypes.AUTO_PLAYBACK_MUTED,void 0,{element:this._view}))}catch(i){t?(this.mute(),this.attemptAutoplay(t)):this.trigger(new be(e.SubscriberEventTypes.AUTO_PLAYBACK_FAILURE,void 0,{error:i.message?i.message:i,element:this._view}))}}async play(){var e,t;if(O(this._name,"[videoelement:action] play"),!(null===(e=this._view)||void 0===e?void 0:e.paused))return O(this._name,"[videoelement:action] play (ALREADY PLAYING)"),!0;try{return await(null===(t=this._view)||void 0===t?void 0:t.play()),!0}catch(e){throw H(this._name,"[videoelement:action] play (FAULT) - "+e.message),e}}async pause(){var e;O(this._name,"[videoelement:action] pause");try{return await(null===(e=this._view)||void 0===e?void 0:e.pause()),!0}catch(e){k(this._name,"[videoelement:action] pause (CATCH::FAULT) - "+e.message)}return!1}async resume(){var e;O(this._name,"[videoelement:action] resume");try{return await(null===(e=this._view)||void 0===e?void 0:e.play()),!0}catch(e){k(this._name,"[videoelement:action] resume (CATCH::FAULT) - "+e.message)}return!1}async stop(){var e;O(this._name,"[videoelement:action] stop");try{return await(null===(e=this._view)||void 0===e?void 0:e.pause()),!0}catch(e){k(this._name,"[videoelement:action] stop (CATCH::FAULT) - "+e.message)}return!1}mute(){this._view&&(this._view.muted=!0);const e=this.getControls();e&&e.setMutedState(!0)}unmute(){this._view&&(this._view.muted=!1);const e=this.getControls();e&&e.setMutedState(!1)}setVolume(e){this.unmute(),this._view&&(this._view.volume=e)}getVolume(){var e,t;return null!==(t=null===(e=this._view)||void 0===e?void 0:e.volume)&&void 0!==t?t:0}seekTo(e,t=void 0){this._view&&(this._view.currentTime=t?e*t:e)}toggleFullScreen(e){try{(e||this._view)&&ie.toggleFullScreen(null!=e?e:this._view)}catch(e){}}async unpublish(){var e;try{await this.stop(),null===(e=this._view)||void 0===e||e.dispatchEvent(new Event("ended"))}catch(e){}}disconnect(){this._cleanup()}isVOD(){return this._isVOD}isMuted(){var e,t;return null!==(t=null===(e=this._view)||void 0===e?void 0:e.muted)&&void 0!==t&&t}getControls(){}}const Mt="WHEPClient",Ut=yt,Bt=e=>O(Mt,e),Vt=e=>H(Mt,e),Ft=e=>k(Mt,e);class $t extends It{constructor(e,t,i){super(),this._videoMuted=!0,this._audioMuted=!0;const n=e?se(e):Ut,s=i||Ut,a={...s,...n,endpoint:e,mediaElementId:t?t.id:s.mediaElementId};this._videoUnmuteHandler=this._onVideoUnmute.bind(this),this._audioUnmuteHandler=this._onAudioUnmute.bind(this),e&&this.internalInit(a)}async internalInit(e){await this.init(e),await this.subscribe()}async _runMuteCheck(){var e,t,i;if(this.getPeerConnection())try{let n=this._videoMuted,s=this._audioMuted;const a=await(null===(e=this.getPeerConnection())||void 0===e?void 0:e.getStats());if(null==a||a.forEach((e=>{const{type:t,kind:i,bytesReceived:a}=e;"inbound-rtp"!==t&&"inboundrtp"!==t||("video"===i?n=a<=0:"audio"===i&&(s=a<=0))})),n===this._videoMuted&&s===this._audioMuted)return;this._videoMuted=n,this._audioMuted=s;const o={data:{streamingMode:(t=!this._videoMuted,i=!this._audioMuted,t&&i?Lt.FULL:t?Lt.VIDEO:i?Lt.AUDIO:Lt.EMPTY),method:"onMetaData"},type:"metadata",method:"onMetaData",eventTimestamp:(new Date).getTime()};this._onMetaData(o)}catch(e){Vt(e.message||e)}}_onVideoUnmute(e){const t=e.target;null==t||t.removeEventListener("unmute",this._videoUnmuteHandler);const i=setTimeout((async()=>{clearTimeout(i),this._runMuteCheck()}),1e3)}_onAudioUnmute(e){const t=e.target;null==t||t.removeEventListener("unmute",this._audioUnmuteHandler);const i=setTimeout((async()=>{clearTimeout(i),this._runMuteCheck()}),1e3)}_attachSourceHandler(e){this._sourceHandler=new Ht(e,this.getType())}_glomTrigger(e){e.on("*",(e=>{const{type:t,data:i}=e;this.trigger(new be(t,this,i))}))}_playIfAutoplaySet(e,t){var i;if(e&&t){const{muteOnAutoplayRestriction:n}=e;ie.hasAttributeDefined(t,"autoplay")&&(null===(i=this._sourceHandler)||void 0===i||i.attemptAutoplay(n))}}addMediaStreamToPlayback(e,t){var i;!this._playbackView&&e&&(this._playbackView=new Pt(e)),null===(i=this._playbackView)||void 0===i||i.attachStream(t)}async requestOffer(t){var i;Bt("[requestoffer]");const{iceTransport:n,maintainStreamVariant:s,videoEncoding:a,audioEncoding:o,connectionParams:r,mungeOffer:l}=this._options;t.addTransceiver("video",{direction:"recvonly"}),t.addTransceiver("audio",{direction:"recvonly"});const h={transport:n,doNotSwitch:s};a&&a!==e.PlaybackVideoEncoder.NONE&&(h.videoEncoding=a),o&&o!==e.PlaybackAudioEncoder.NONE&&(h.audioEncoding=o);const d=null!=r?r:{},c=await t.createOffer(),u=await(null===(i=this._whipWhepService)||void 0===i?void 0:i.postSDPOffer(c.sdp,{...d,...h},!1));if(!u)throw Vt("Failed to get offer from WHEP"),new Error("Failed to get offer from WHEP");const{sdp:p}=u;let _=p;return l&&(Bt(`[MUNGE:before] offer: ${_}`),_=l(_),Bt(`[MUNGE:after] offer: ${_}`)),_}async requestAnswer(e){const{mungeAnswer:t}=this._options;let i=(await e.createAnswer()).sdp;return t&&(Bt(`[MUNGE:before] answer: ${i}`),i=t(i),Bt(`[MUNGE:after] answer: ${i}`)),i}async sendAnswer(e){var t;const{connectionParams:i}=this._options;return await(null===(t=this._whipWhepService)||void 0===t?void 0:t.postSDPAnswer(e,i))}async postCandidateFragments(e){var t;const{connectionParams:i}=this._options,n=Fe(e,void 0,!0);return await(null===(t=this._whipWhepService)||void 0===t?void 0:t.trickle(n,i))}async initPubNub(e){var t;try{const t=new vt;this._pubnubClient=t,this._pubnubClient.on("*",(e=>{this.trigger(e)})),await t.init(e)}catch(e){return e(null!==(t=e.message)&&void 0!==t?t:"Failed to initialize PubNub."),!1}return!0}async deinitPubNub(){var e,t;try{await(null===(e=this._pubnubClient)||void 0===e?void 0:e.destroy()),this._pubnubClient=void 0}catch(e){return e(null!==(t=e.message)&&void 0!==t?t:"Failed to deinitialize PubNub."),!1}return!0}_evaluateRenegotiationPolicy(t){const{renegotiationPolicy:i}=this._options;if(i){const{type:n}=i,s=n.toLowerCase();Bt(`[evaluateRenegotiationPolicy] - Type: ${t}, Renegotiation Policy: ${i.type}`),(t===Ne.CONNECTION_HEALTH_STATE_REGRESSION&&"regression"===s||t===Ne.CONNECTION_HEALTH_ICE_TIMEOUT&&"timeout"===s||t===e.SubscriberEventTypes.CONNECTION_CLOSED&&"disconnect"===s)&&this._reconnect()}}async _reconnect(){var t,i;Bt("[reconnect]"),this.trigger(new be(e.SubscriberEventTypes.RECONNECT_START,this));try{await this.unsubscribe(!0),await this.init(this._options),await this.subscribe()}catch(n){Vt(null!==(t=n.message)&&void 0!==t?t:"Could not reconnect."),this.trigger(new be(e.SubscriberEventTypes.RECONNECT_FAILURE,this,{error:null!==(i=n.message)&&void 0!==i?i:"Could not reconnect."}))}}async init(e){var t,i,n;this._options={...Ut,...e},this._options.subscriptionId=this._options.subscriptionId||`subscriber-${Math.floor(65536*Math.random()).toString(16)}`;const s=ae(this._options,"whep"),{includeDataChannel:a,disableProxy:o}=this._options;return this._whipWhepService=new Xe(`${s}?requestId=${this._options.subscriptionId}`,a,o),this._messageTransport=this._whipWhepService,((null===(t=this._options)||void 0===t?void 0:t.stats)||(null===(i=this._options)||void 0===i?void 0:i.renegotiationPolicy))&&(!this._options.stats&&this._options.renegotiationPolicy&&(this._options.stats=wt),this.monitorStats(this._options.stats,this._options.renegotiationPolicy)),(null===(n=this._options)||void 0===n?void 0:n.pubnub)&&await this.initPubNub(this._options.pubnub),this}async subscribe(){var t,i,n,s,a,o,r,l,h;const{connectionParams:d,rtcConfiguration:c,includeDataChannel:u,signalingSocketOnly:p,enableChannelSignaling:_,dataChannelConfiguration:g}=this._options;try{const h=d||{},m=await(null===(t=this._whipWhepService)||void 0===t?void 0:t.getOptions(h));this.trigger(new be(e.SubscriberEventTypes.CONNECT_SUCCESS,this,null===(i=this._whipWhepService)||void 0===i?void 0:i.getUrl()));const E=!!(null===(n=this._options)||void 0===n?void 0:n.rtcConfiguration)&&Array.isArray(this._options.rtcConfiguration.iceServers)&&this._options.rtcConfiguration.iceServers.length>0;(null==m?void 0:m.links)&&!E&&(this._options.rtcConfiguration={...c,iceServers:m.links}),(null==m?void 0:m.origin)&&this.trigger(new be(e.RTCSubscriberEventTypes.HOST_ENDPOINT_CHANGED,this,{endpoint:m.origin})),(null==m?void 0:m.statisticsEndpoint)&&this._onStatisticsEndpointChange(m.statisticsEndpoint);const b=u||_||p?g:void 0;this._peerConnectionHelper=new Rt({onUnpublish:this._onUnpublish.bind(this),onStreamUnavailable:this._onStreamUnavailable.bind(this),onSubscriberStatus:this._onSubscriberStatus.bind(this),onStreamSwitchComplete:this._onStreamSwitchComplete.bind(this),onDataChannelError:this._onDataChannelError.bind(this),onSendReceived:this._onSendReceived.bind(this),onMetaData:this._onMetaData.bind(this),onConnectionClosed:this._onConnectionClosed.bind(this),onDataChannelOpen:this._onDataChannelOpen.bind(this),onDataChannelClose:this._onDataChannelClose.bind(this),onDataChannelMessage:this._onDataChannelMessage.bind(this),onPeerConnectionOpen:this._onPeerConnectionOpen.bind(this),onPeerConnectionFail:this._onPeerConnectionFail.bind(this),onPeerConnectionClose:this._onPeerConnectionClose.bind(this),onIceCandidate:this._onIceCandidate.bind(this),onSDPSuccess:this._onSDPSuccess.bind(this),onSDPError:this._onSDPError.bind(this),onStatisticsEndpointChange:this._onStatisticsEndpointChange.bind(this)}),await this._peerConnectionHelper.setUpWithPeerConfiguration(this._options.rtcConfiguration,b),null===(s=this.getPeerConnection())||void 0===s||s.addEventListener("track",(t=>{const{buffer:i}=this._options;Bt("[peerconnection.ontrack]");const{streams:n,track:s,receiver:a,transceiver:o}=t;a.jitterBufferDelayHint=i,this.trigger(new be(e.RTCSubscriberEventTypes.TRACK_ADDED,this,{streams:n,track:s,receiver:a,transceiver:o})),this._mediaStream=n&&n.length>0?n[0]:void 0,"video"===s.kind?(this._videoMuted=s.muted,s.muted&&s.addEventListener("unmute",this._videoUnmuteHandler)):"audio"===s.kind&&(this._audioMuted=s.muted,s.muted&&s.addEventListener("unmute",this._audioUnmuteHandler)),this._runMuteCheck()})),this.trigger(new be(e.RTCSubscriberEventTypes.PEER_CONNECTION_AVAILABLE,this,this.getPeerConnection())),this.trigger(new be(e.RTCSubscriberEventTypes.OFFER_START,this));const S=await this.requestOffer(this.getPeerConnection()),C=new RTCSessionDescription({type:"offer",sdp:S});await(null===(a=this.getPeerConnection())||void 0===a?void 0:a.setRemoteDescription(C)),this.trigger(new be(e.RTCSubscriberEventTypes.OFFER_END,this)),this.trigger(new be(e.RTCSubscriberEventTypes.ANSWER_START,this));const T=await this.requestAnswer(this.getPeerConnection()),y=(v=T).includes("stereo=1")?v:v.replace("useinbandfec=1","useinbandfec=1;stereo=1;sprop-stereo=1"),f=new RTCSessionDescription({type:"answer",sdp:y});await(null===(o=this.getPeerConnection())||void 0===o?void 0:o.setLocalDescription(f)),await this.sendAnswer(y),this.trigger(new be(e.RTCSubscriberEventTypes.ANSWER_END,this));const w=await this._peerConnectionHelper.waitToGatherIce(),{sdp:A}=w;return await this.postCandidateFragments(A),this.trigger(new be(e.RTCSubscriberEventTypes.ICE_TRICKLE_COMPLETE,this)),this._mediaStream&&(this.trigger(new be(e.RTCSubscriberEventTypes.ON_ADD_STREAM,this,this._mediaStream)),this.addMediaStreamToPlayback(this._options.mediaElementId,this._mediaStream)),(null===(r=this._playbackView)||void 0===r?void 0:r.view)&&this._attachSourceHandler(this._playbackView.view),this._sourceHandler&&this._glomTrigger(this._sourceHandler),this._playIfAutoplaySet(this._options,null===(l=this._playbackView)||void 0===l?void 0:l.view),this}catch(t){throw Vt(null!==(h=t.message)&&void 0!==h?h:"Could not subscribe."),t instanceof xe?this._onStreamUnavailable(t):this.trigger(new be(e.SubscriberEventTypes.CONNECT_FAILURE,this,t)),this._options.maintainConnectionOnSubscribeErrors||this.unsubscribe(!0),t}var v}async unsubscribe(t=!1){var i;Bt("[unsubscribe]"),this._peerConnectionHelper&&await this._peerConnectionHelper.tearDown(),this._whipWhepService&&await this._whipWhepService.tearDown(null,t),this._sourceHandler&&this._sourceHandler.disconnect(),this._pubnubClient&&await this.deinitPubNub(),this.unmonitorStats(),null===(i=this._playbackView)||void 0===i||i.detachStream(),this._playbackView=void 0,this._pubnubClient=void 0,this._whipWhepService=void 0,this._messageTransport=void 0,this._peerConnectionHelper=void 0,this._sourceHandler=void 0,this._mediaStream=void 0,this.trigger(new be(e.SubscriberEventTypes.SUBSCRIBE_STOP,this))}async send(e,t){var i;let n=t;try{n="string"==typeof t?JSON.parse(t):t}catch(e){Ft(`Could not parse data as JSON. Sending as message. Error: ${e.message||e}`),n={message:t}}return null===(i=this.getMessageTransport())||void 0===i?void 0:i.post({send:{method:e,data:n}})}async sendPubNub(e,t){return this._pubnubClient?await this._pubnubClient.publishMessage(e,t):(Vt("PubNub client not initialized."),!1)}async subscribePubNub(e,t){return this._pubnubClient?await this._pubnubClient.subscribe(e,t):(Vt("PubNub client not initialized."),!1)}async unsubscribePubNub(e){return this._pubnubClient?await this._pubnubClient.unsubscribe(e):(Vt("PubNub client not initialized."),!1)}async callServer(e,t){var i;const n="switchStreams"===e,{app:s,streamName:a}=this._options;if(n){const{path:i}=t[0];this._requestedStreamSwitch=i,Bt(`[callServer:switch]:: ${e}, ${s}/${a} -> ${i}`)}return null===(i=this.getMessageTransport())||void 0===i?void 0:i.postAsync({callAdapter:{method:e,arguments:t}})}sendLog(e,t){var i;try{const n=Object.keys(R).find((t=>t.toLowerCase()===e.toLowerCase()))?e:R.DEBUG,s="string"==typeof t?t:JSON.stringify(t);null===(i=this.getMessageTransport())||void 0===i||i.post({log:n.toUpperCase(),message:s})}catch(e){const t=e.message||e;Vt("Could not send log to server. Message parameter expected to be String or JSON-serializable object."),Vt(t)}}enableStandby(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteAudio:!0,muteVideo:!0}})}disableStandby(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteAudio:!1,muteVideo:!1}})}muteAudio(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteAudio:!0}})}unmuteAudio(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteAudio:!1}})}muteVideo(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteVideo:!0}})}unmuteVideo(){var e;null===(e=this.getMessageTransport())||void 0===e||e.post({mute:{muteVideo:!1}})}get options(){return this._options}getOptions(){return this._options}getPeerConnection(){var e;return null===(e=this._peerConnectionHelper)||void 0===e?void 0:e.connection}getDataChannel(){var e;return null===(e=this._peerConnectionHelper)||void 0===e?void 0:e.dataChannel}getMediaStream(){return this._mediaStream}getMessageTransport(){return this._messageTransport}getPubNubClient(){return this._pubnubClient}getPlayer(){var e;return null===(e=this._playbackView)||void 0===e?void 0:e.view}play(){Bt("[play]"),this._sourceHandler?this._sourceHandler.play():Ft("Cannot play without a Source Handler.")}pause(){Bt("[pause]"),this._sourceHandler?this._sourceHandler.pause():Ft("Cannot pause without a Source Handler.")}resume(){Bt("[resume]"),this._sourceHandler?this._sourceHandler.resume():Ft("Cannot resume without a Source Handler.")}stop(){Bt("[stop]"),this._sourceHandler?this._sourceHandler.stop():Ft("Cannot stop without a Source Handler.")}setVolume(e){Bt("[setVolume]"),this._sourceHandler?this._sourceHandler.setVolume(e):Ft("Cannot set volume without a Source Handler.")}getVolume(){var e,t,i;return Bt("[getVolume]"),this._sourceHandler?this._sourceHandler.getVolume():(Ft("Cannot get volume without a Source Handler."),null!==(i=null===(t=null===(e=this._playbackView)||void 0===e?void 0:e.view)||void 0===t?void 0:t.volume)&&void 0!==i?i:0)}mute(){Bt("[mute]"),this._sourceHandler?this._sourceHandler.mute():Ft("Cannot mute without a Source Handler.")}unmute(){Bt("[unmute]"),this._sourceHandler?this._sourceHandler.unmute():Ft("Cannot unmute without a Source Handler.")}seekTo(e){Bt("[seekTo]"),this._sourceHandler?this._sourceHandler.seekTo(e):Ft("Cannot seek without a Source Handler.")}toggleFullScreen(){Bt("[toggleFullScreen]"),this._sourceHandler?this._sourceHandler.toggleFullScreen():Ft("Cannot toggle full screen without a Source Handler.")}monitorStats(e,t){Bt(`[monitorStats]:: Stats: ${e?JSON.stringify(e):"undefined"}`),Bt(`[monitorStats]:: Renegotiation Policy: ${t?JSON.stringify(t):"undefined"}`);const{host:i,endpoint:n,app:s,streamName:a,subscriptionId:o,connectionParams:r}=this._options,l=null!=e?e:pe;return this._statisticsConfiguration={...l,host:i,app:s,hostEndpoint:n,streamName:a,subscriptionId:o,connectionParams:r},this._statsMonitor?Ft("Cannot monitor stats without a Peer Connection. Please call `init` before calling `monitorStats`."):this._statsMonitor=new kt(this._statisticsConfiguration,{onStatsReport:this._onStatsReport.bind(this),getPeerConnection:this.getPeerConnection.bind(this),getMessageTransport:this.getMessageTransport.bind(this),on:this.on.bind(this),off:this.off.bind(this),trigger:this.trigger.bind(this),emit:this.emit.bind(this)},t),this}unmonitorStats(){return this._statsMonitor&&this._statsMonitor.dispose(),this._statsMonitor=void 0,this._statisticsConfiguration=void 0,this}_onUnpublish(){Bt("[unpublish]"),this.trigger(new be(e.SubscriberEventTypes.PLAY_UNPUBLISH,this)),this._sourceHandler&&this._sourceHandler.unpublish()}_onStreamUnavailable(t){Bt(`Stream ${this._options.streamName} does not exist.`),Bt("[onstreamunavailable]: "+JSON.stringify(t,null,2)),this.trigger(new be(e.SubscriberEventTypes.SUBSCRIBE_INVALID_NAME,this))}_onDataChannelError(t,i){Vt(`Data channel error: ${i}`),this.trigger(new be(e.RTCSubscriberEventTypes.DATA_CHANNEL_ERROR,this,{dataChannel:t,error:i}))}_onSendReceived(t,i){Bt(`Send received: ${t} ${JSON.stringify(i)}`),"onMetaData"===t?this._onMetaData(i):this.trigger(new be(e.SubscriberEventTypes.SUBSCRIBE_SEND_INVOKE,this,{methodName:t,data:i}))}_onStreamSwitchComplete(){Bt("[streamswitch::complete]");const t=this._requestedStreamSwitch;this.trigger(new be(e.RTCSubscriberEventTypes.SUBSCRIBE_STREAM_SWITCH,this,{path:t})),this._requestedStreamSwitch=void 0}_onMetaData(t){const{orientation:i,streamingMode:n}=t,s=this._streamingMode;void 0!==i&&i!==this._orientation&&(this._orientation=i,this.trigger(new be(e.SubscriberEventTypes.ORIENTATION_CHANGE,this,{orientation:parseInt(i,10),viewElement:this._playbackView?this._playbackView.view:void 0}))),n&&void 0!==n&&n!==s&&(this._streamingMode=n,this.trigger(new be(e.SubscriberEventTypes.STREAMING_MODE_CHANGE,this,{streamingMode:n,previousStreamingMode:s,viewElement:this._playbackView?this._playbackView.view:void 0}))),this.trigger(new be(e.SubscriberEventTypes.SUBSCRIBE_METADATA,this,t))}_onConnectionClosed(){Bt("Connection closed"),this.unsubscribe(!0),this.trigger(new be(e.SubscriberEventTypes.CONNECTION_CLOSED,this))}_onDataChannelOpen(t){Bt(`Data channel opened: ${t.label}`),this.trigger(new be(e.RTCSubscriberEventTypes.DATA_CHANNEL_OPEN,this,{dataChannel:t})),this.trigger(new be(e.RTCSubscriberEventTypes.DATA_CHANNEL_AVAILABLE,this,{name:t.label,dataChannel:t})),this._messageTransport=this._peerConnectionHelper,this.trigger(new Se(e.MessageTransportStateEventTypes.CHANGE,this,{controller:this,transport:this._messageTransport})),this.trigger(new be(e.SubscriberEventTypes.SUBSCRIBE_START,this))}_onDataChannelClose(t){Bt(`Data channel closed: ${t.label}`),this.trigger(new be(e.RTCSubscriberEventTypes.DATA_CHANNEL_CLOSE,this,{dataChannel:t}))}_onDataChannelMessage(t,i){Bt(`Data channel message: ${i.data}`),this.trigger(new be(e.RTCSubscriberEventTypes.DATA_CHANNEL_MESSAGE,this,{dataChannel:t,message:i}))}_onPeerConnectionOpen(){var t;Bt("Peer connection opened"),this.trigger(new be(e.RTCSubscriberEventTypes.PEER_CONNECTION_OPEN,this,this.getPeerConnection())),(null===(t=this._options)||void 0===t?void 0:t.includeDataChannel)||this.trigger(new be(e.SubscriberEventTypes.SUBSCRIBE_START,this))}_onPeerConnectionFail(){Vt("Peer connection failed"),this.trigger(new be(e.SubscriberEventTypes.SUBSCRIBE_FAIL,this))}_onPeerConnectionClose(t){Bt(`Peer connection closed: ${t.type}`),this._evaluateRenegotiationPolicy(e.SubscriberEventTypes.CONNECTION_CLOSED)}_onIceCandidate(t){Bt(`ICE candidate: ${t.candidate}`),this.trigger(new be(e.RTCSubscriberEventTypes.CANDIDATE_CREATE,this,{candidate:t}))}_onPeerConnectionTrackAdd(e){Bt(`Peer connection track added: ${e.id}`)}_onSubscriberStatus(e){Bt(`Subscriber status: ${JSON.stringify(e)}`)}_onSDPSuccess(){Bt("SDP success")}_onSDPError(e){Vt(`SDP error: ${e}`)}_onStatisticsEndpointChange(t){Bt(`Statistics endpoint changed: ${t}`),this._statsMonitor&&this._statsMonitor.updateEndpoint(t),this.trigger(new be(e.SubscriberEventTypes.STATISTICS_ENDPOINT_CHANGE,this,{statisticsEndpoint:t}))}_onStatsReport(t,i){this.trigger(new be(e.RTCSubscriberEventTypes.STATS_REPORT,this,{connection:t,report:i}))}on(e,t){super.on(e,t)}off(e,t){super.off(e,t)}trigger(e){super.trigger(e)}emit(e,t){this.trigger(new be(e,this,t)),this._evaluateRenegotiationPolicy(e)}getType(){return"RTC"}}const Gt={stream:3,datachannel:4},xt=[e.MessageChannelEventTypes.OPEN,e.MessageChannelEventTypes.CLOSE,e.MessageChannelEventTypes.ERROR,e.MessageChannelEventTypes.FAIL,e.PublisherEventTypes.STATISTICS_ENDPOINT_CHANGE];class Wt extends it{constructor(t,i){if(super("MessageChannelStats",t,i),this.estimatedAudioBitrate=0,this.estimatedVideoBitrate=0,this.lastAudioReport=null,this.lastVideoReport=null,this._eventHandler=t=>{const{type:i,data:n}=t;if(xt.indexOf(i)>-1){if(i===e.PublisherEventTypes.STATISTICS_ENDPOINT_CHANGE){const{statisticsEndpoint:e}=n;this.updateEndpoint(e,!1)}this.postEvent(i)}else xt.indexOf(i)>-1&&this.postEvent(i)},this._candidateCreateHandler=({data:{candidate:e}})=>{const{candidate:t}=e,i=st(t);i&&(this._identifier.publicIP=i)},this._hostEndpointChangedHandler=({data:{endpoint:e,iceServers:t}})=>{this._appendClientDetails({node:e,iceServers:t})},this._client.on("*",this._eventHandler),this._client.on(e.RTCPublisherEventTypes.CANDIDATE_CREATE,this._candidateCreateHandler),this._client.on(e.RTCPublisherEventTypes.HOST_ENDPOINT_CHANGED,this._hostEndpointChangedHandler),this._client.getPeerConnection())this.start(this._client.getPeerConnection());else{const t=({data:i})=>{this._client.off(e.RTCPublisherEventTypes.PEER_CONNECTION_AVAILABLE,t),this.start(i)};this._client.on(e.RTCPublisherEventTypes.PEER_CONNECTION_AVAILABLE,t)}}_handleStatsReport(e){const{type:t}=e,{include:i}=this._config,n=i&&i.length>0;if(n&&i.indexOf(t)>=-1)this.post(e);else if(!n)if(t===et.CODEC){const{id:i,clockRate:n,mimeType:s,payloadType:a}=e;this.post({id:i,type:t,clockRate:n,mimeType:s,payloadType:a})}else if(t===et.CANDIDATE_PAIR){const{availableOutgoingBitrate:i,currentRoundTripTime:n,totalRoundTripTime:s,state:a}=e;this._checkCandidatePairHealth(e),this.post({type:t,availableOutgoingBitrate:i,currentRoundTripTime:n,totalRoundTripTime:s,state:a});const{timestamp:o,kind:r,codecId:l,mediaType:h,active:d,bytesSent:c,packetsSent:u,totalPacketsSendDelay:p}=e,_={type:t,kind:r,codecId:l,mediaType:h,active:d,bytesSent:c,packetsSent:u,timestamp:o,totalPacketsSendDelay:p};this.post(_)}else if(t===et.DATA_CHANNEL){const{id:t,timestamp:i,type:n,label:s,state:a,messagesSent:o,messagesReceived:r,bytesSent:l,bytesReceived:h}=e;this.post({id:t,timestamp:i,type:n,label:s,state:a,messagesSent:o,messagesReceived:r,bytesSent:l,bytesReceived:h})}}dispose(){this._client.off("*",this._eventHandler),this._client.off(e.RTCPublisherEventTypes.CANDIDATE_CREATE,this._candidateCreateHandler),this._client.off(e.RTCPublisherEventTypes.HOST_ENDPOINT_CHANGED,this._hostEndpointChangedHandler),super.dispose()}}const Kt="DataChannelClient",jt=e=>O(Kt,e),zt=e=>H(Kt,e);class Jt extends Tt{constructor(e,t){super(e,void 0,t),this._inactivePingIntervalMS=3e4,this._inactivePingTimeout=null}async internalInit(e){await this.init(e),await this.open()}establishStatsMonitor(e){return new Wt(e,{onStatsReport:this._onStatsReport.bind(this),getPeerConnection:this.getPeerConnection.bind(this),getMessageTransport:this.getMessageTransport.bind(this),on:this.on.bind(this),off:this.off.bind(this),trigger:this.trigger.bind(this),emit:this.emit.bind(this)})}async init(e){const{connectionParams:t}=e;e={...e,mediaConstraints:{audio:!1,video:!1},mediaElementId:void 0,includeDataChannel:!0,connectionParams:{...null!=t?t:{},capabilities:Gt.datachannel}};const i=await super.init(e);return jt(`Initialized MessageChannel with options: ${JSON.stringify(e,null,2)}`),i}async getAndPreviewStreamIfAvailable(){}_startInactivePing(){this._stopInactivePing(),this._inactivePingTimeout=setTimeout((()=>{const e=(new Date).toISOString();super.send("ping",{timestamp:e}),this._startInactivePing()}),this._inactivePingIntervalMS)}_stopInactivePing(){this._inactivePingTimeout&&(clearTimeout(this._inactivePingTimeout),this._inactivePingTimeout=null)}async open(e=1e4){return this._inactivePingIntervalMS=e,await super.publish()}async close(){return this._stopInactivePing(),this.postStatsMonitorEvent(e.MessageChannelEventTypes.CLOSE),await super.unpublish()}async publish(){return await this.open()}async unpublish(){return await this.close()}async send(e,t){let i=t;try{i="string"==typeof t?JSON.parse(t):t}catch(e){i={data:t}}return await this.sendMessage({...i,methodName:e})}async sendMessage(t){const i=this.getDataChannel(),{streamName:n}=this.options?this.options:{},s=n||"unknown";if(i){let n=t;try{n="string"==typeof t?JSON.parse(t):t}catch(e){n={message:t}}const a={...n,sender_id:s,send_timestamp:(new Date).toISOString()};try{return i.send(JSON.stringify(a)),jt(`Sent message: ${JSON.stringify(a)}`),this.trigger(new Te(e.MessageChannelEventTypes.SEND,this,a)),this._startInactivePing(),!0}catch(t){zt(`Error sending message: ${t.message||t}`),this.trigger(new Te(e.MessageChannelEventTypes.ERROR,this,{error:t.message||t}))}}return!1}async sendData(t){const i=this.getDataChannel();if(i)try{return i.send(t),this.trigger(new Te(e.MessageChannelEventTypes.SEND,this,t)),this._startInactivePing(),!0}catch(t){zt(`Error sending data: ${t.message||t}`),this.trigger(new Te(e.MessageChannelEventTypes.ERROR,this,{error:t.message||t}))}return!1}_onDataChannelOpen(e){super._onDataChannelOpen(e),this._startInactivePing()}_onDataChannelMessage(t,i){const{data:n}=i;jt(`Incoming Data channel message: ${n}`),this.trigger(new Te(e.MessageChannelEventTypes.RECEIVE,this,{dataChannel:t,message:i}))}_onDataChannelClose(t){this._stopInactivePing(),super._onDataChannelClose(t),this.trigger(new Te(e.MessageChannelEventTypes.CLOSE,this))}_onPeerConnectionFail(){zt("Peer connection failed"),this.trigger(new Te(e.MessageChannelEventTypes.FAIL,this))}_onSDPError(t=void 0){this.trigger(new Te(e.MessageChannelEventTypes.ERROR,this));const i=t?": "+JSON.stringify(t,null,2):"";zt(`[onsdperror]:: ${i}`)}trigger(t){if(t.type===e.PublisherEventTypes.PUBLISH_START)super.trigger(new Te(e.MessageChannelEventTypes.OPEN,this));else if(t.type===e.PublisherEventTypes.UNPUBLISH_SUCCESS)super.trigger(new Te(e.MessageChannelEventTypes.CLOSE,this));else{const{type:e,data:i}=t;super.trigger(new Te(e,this,i))}}getType(){return"DATA_CHANNEL"}}class Yt extends Ht{constructor(e,t){super(e,t),this._playingStarted=!1,this.onOrientation=this._onOrientationMetadata.bind(this),this.onStreamingMode=this._onStreamingModeMetadata.bind(this),ie.onOrientationMetadata(this._view,this.onOrientation),ie.onStreamingModeMetadata(this._view,this.onStreamingMode),this.onPlaying=this._onPlaying.bind(this),this.onSourceError=this._onSourceError.bind(this),this._view.addEventListener("playing",this.onPlaying)}addSource(e){this._source=ie.createElement("source"),this._source.type="application/x-mpegURL",this._source.src=e,this._view.firstChild?this._view.insertBefore(this._source,this._view.firstChild):this._view.appendChild(this._source),this._source.addEventListener("error",this.onSourceError)}_onPlaying(){this._playingStarted||this.trigger(new be(e.SubscriberEventTypes.SUBSCRIBE_START,this._view)),this._playingStarted=!0}_onSourceError(t){O(this._name,"[source:event] error"),this.trigger(new be(e.SubscriberEventTypes.CONNECT_FAILURE,void 0,t))}_onOrientationMetadata(t){const{orientation:i}=t,n=parseInt(i,10);i&&this._orientation!==n&&(O(this._name,"Metadata received: "+JSON.stringify(t,null,2)),this._orientation=n,this.trigger(new be(e.SubscriberEventTypes.ORIENTATION_CHANGE,{orientation:this._orientation,viewElement:this._view})),this.trigger(new be(e.SubscriberEventTypes.SUBSCRIBE_METADATA,void 0,t)))}_onStreamingModeMetadata(t){const{streamingMode:i}=t,n=this._streamingMode;i&&n!==i&&(O(this._name,"Metadata received: "+JSON.stringify(t,null,2)),this._streamingMode=i,this.trigger(new be(e.SubscriberEventTypes.STREAMING_MODE_CHANGE,void 0,{streamingMode:this._streamingMode,previousStreamingMode:n,viewElement:this._view})),this.trigger(new be(e.SubscriberEventTypes.SUBSCRIBE_METADATA,void 0,t)))}_cleanup(){this._view&&this._view.removeEventListener("playing",this.onPlaying),this._source&&(this._source.removeEventListener("error",this.onSourceError),this._view.removeChild(this._source),this._source=void 0),super._cleanup()}}const qt="HLSSubscriber",Xt=e=>O(qt,e),Qt=e=>k(qt,e);class Zt extends It{constructor(){super()}_glomTrigger(e){e.on("*",(e=>{const{type:t,data:i}=e;this.trigger(new be(t,this,i))}))}_playIfAutoplaySet(e,t){var i;if(e&&t){const{muteOnAutoplayRestriction:n}=e;ie.hasAttributeDefined(t,"autoplay")&&(null===(i=this._sourceHandler)||void 0===i||i.attemptAutoplay(n))}}async init(e){if(!ie.supportsHLS())throw new Error("Native HLS playback is not supported on this browser.");return this._options={...ft,...e},this}async subscribe(){var t;try{const i=/^http(|s).*\.m3u8/g,{endpoint:n,mediaElementId:s}=this._options;return this._fileURL=n&&n.match(i)?n:(e=>{const{host:t,protocol:i,port:n,app:s,streamName:a,connectionParams:o}=e,r="ws"===i||"http"===i?"http":"https",l=`${r}://${t}:${n||("http"===r?5080:443)}/${s}/${a}.m3u8`;if(o)return`${l}?${Object.entries(o).map((([e,t])=>`${e}=${t}`)).join("&")}`;return l})(this._options),!this._playbackView&&s&&(this._playbackView=new Pt(s),this._sourceHandler=new Yt(this._playbackView.view,this.getType()),this._sourceHandler.addSource(this._fileURL),this._glomTrigger(this._sourceHandler)),this.trigger(new be(e.SubscriberEventTypes.CONNECT_SUCCESS,this,this._fileURL)),this._playIfAutoplaySet(this._options,null===(t=this._playbackView)||void 0===t?void 0:t.view),this}catch(t){throw t(t.message),this.trigger(new be(e.SubscriberEventTypes.CONNECT_FAILURE,this,t.message)),t}}async unsubscribe(){var t;return this._sourceHandler&&this._sourceHandler.disconnect(),null===(t=this._playbackView)||void 0===t||t.detachStream(),this._playbackView=void 0,this._sourceHandler=void 0,this.trigger(new be(e.SubscriberEventTypes.SUBSCRIBE_STOP,this)),this}play(){Xt("[play]"),this._sourceHandler?this._sourceHandler.play():Qt("Cannot play without a Source Handler.")}pause(){Xt("[pause]"),this._sourceHandler?this._sourceHandler.pause():Qt("Cannot pause without a Source Handler.")}resume(){Xt("[resume]"),this._sourceHandler?this._sourceHandler.resume():Qt("Cannot resume without a Source Handler.")}stop(){Xt("[stop]"),this._sourceHandler?this._sourceHandler.stop():Qt("Cannot stop without a Source Handler.")}setVolume(e){Xt("[setVolume]"),this._sourceHandler?this._sourceHandler.setVolume(e):Qt("Cannot set volume without a Source Handler.")}getVolume(){var e,t,i;return Xt("[getVolume]"),this._sourceHandler?this._sourceHandler.getVolume():(Qt("Cannot get volume without a Source Handler."),null!==(i=null===(t=null===(e=this._playbackView)||void 0===e?void 0:e.view)||void 0===t?void 0:t.volume)&&void 0!==i?i:0)}mute(){Xt("[mute]"),this._sourceHandler?this._sourceHandler.mute():Qt("Cannot mute without a Source Handler.")}unmute(){Xt("[unmute]"),this._sourceHandler?this._sourceHandler.unmute():Qt("Cannot unmute without a Source Handler.")}seekTo(e){Xt("[seekTo]"),this._sourceHandler?this._sourceHandler.seekTo(e):Qt("Cannot seek without a Source Handler.")}toggleFullScreen(){Xt("[toggleFullScreen]"),this._sourceHandler?this._sourceHandler.toggleFullScreen():Qt("Cannot toggle full screen without a Source Handler.")}getPlayer(){var e;return null===(e=this._playbackView)||void 0===e?void 0:e.view}get options(){return this._options}getOptions(){return this._options}get fileURL(){return this._fileURL}getFileURL(){return this._fileURL}getType(){return"HLS"}}const ei={baseURL:void 0,fullURL:void 0,hlsjsRef:void 0,hlsElement:void 0,usePlaybackControlsUI:!0,options:{debug:!1,backBufferLength:0}},ti={...yt,liveSeek:ei};class ii extends U{trigger(e){super.trigger(e)}on(e,t){super.on(e,t)}off(e,t){super.off(e,t)}}var ni,si;!function(e){e.SEEK_START="Seek.Start",e.SEEK_END="Seek.End"}(ni||(ni={})),function(e){e.CHANGE="Slider.Change",e.CHANGE_START="Slider.Change.Start",e.CHANGE_COMPLETE="Slider.Change.Complete"}(si||(si={}));class ai extends me{constructor(e,t,i){super(e,i),this._slider=t}get slider(){return this._slider}}const{createElement:oi,addGlobalEventListener:ri,removeGlobalEventListener:li,globalUnassign:hi,getAssignedValue:di,globalAssign:ci}=ie,ui="ControlSlider",pi="r5_liveseek_event_owner";class _i extends U{constructor(e){super(),this._value=0,this._disabled=!1,this._eventStartPosition=0,this.debug=e=>O(ui,e),this.warn=e=>k(ui,e),this.name=[ui,e].join("::"),this.debug("[init]"),this._container=oi("div"),this._button=this.createButton(),this._track=this.createTrack(),this._progressBar=this.createProgressBar(),this._container.appendChild(this._track),this._container.appendChild(this._progressBar),this._container.appendChild(this._button),this._layout(),this._mouseupHandler=this._mouseup.bind(this),this._mousedownHandler=this._mousedown.bind(this),this._mousemoveHandler=this._mousemove.bind(this),this._touchupHandler=this._touchproxy.bind(this),this._touchdownHandler=this._touchproxy.bind(this),this._touchmoveHandler=this._touchproxy.bind(this),this._updateHandlers(this._disabled)}_touchproxy(e){var t,i,n,s;const a=e;this.debug(`${a.type} touches: ${(null===(t=a.changedTouches)||void 0===t?void 0:t.length)||0}`);try{a.preventDefault()}catch(e){this.warn("Failed to prevent default on touch event.")}if(!a.touches||a.touches.length>1||"touchend"===a.type&&a.touches.length>0)return;let o,r="";const l=a.target||document.body;switch(a.type){case"touchstart":r="mousedown",o=null===(i=a.changedTouches)||void 0===i?void 0:i[0];break;case"touchmove":r="mousemove",o=null===(n=a.changedTouches)||void 0===n?void 0:n[0];break;case"touchend":r="mouseup",o=null===(s=a.changedTouches)||void 0===s?void 0:s[0]}if(o&&r){const e=new MouseEvent(r,{bubbles:!0,cancelable:!0,view:l.ownerDocument.defaultView,screenX:o.screenX,screenY:o.screenY,clientX:o.clientX,clientY:o.clientY,ctrlKey:a.ctrlKey,altKey:a.altKey,shiftKey:a.shiftKey,metaKey:a.metaKey,button:0,relatedTarget:null});l.dispatchEvent(e)}}_mouseup(){this._eventStartPosition=0,hi(pi),li("mousemove",this._mousemoveHandler),li("mouseup",this._mouseupHandler),li("touchmove",this._touchmoveHandler),li("touchend",this._touchupHandler),this.trigger(new ai(si.CHANGE_COMPLETE,this))}_mousemove(e){if(di(pi)!==this.name)return;this.debug(`[mousemove] ${this.name}`);const t=e.clientX-this._eventStartPosition,i=this._button.parentNode.getBoundingClientRect();let n=this._eventStartPosition+t-i.left;n=Math.max(0,n),n=Math.min(n,i.width);const s=n/i.width;this.trigger(new ai(si.CHANGE,this,s))}_mousedown(e){this._eventStartPosition=e.clientX,this.trigger(new ai(si.CHANGE_START,this)),ci(pi,this.name),ri("mousemove",this._mousemoveHandler),ri("mouseup",this._mouseupHandler),ri("touchmove",this._touchmoveHandler),ri("touchend",this._touchupHandler)}_updateHandlers(e){this._eventStartPosition=0,e?(this._track.removeEventListener("click",this._mousemoveHandler),this._progressBar.removeEventListener("click",this._mousemoveHandler),this._button.removeEventListener("mousedown",this._mousedownHandler),li("mousemove",this._mousemoveHandler),li("mouseup",this._mouseupHandler),li("touchmove",this._touchmoveHandler),li("touchend",this._touchupHandler),this._track.classList.add("red5pro-media-slider-disabled"),this._progressBar.classList.add("red5pro-media-slider-disabled"),this._button.classList.add("red5pro-media-slider-disabled")):(this._track.addEventListener("click",this._mousemoveHandler),this._progressBar.addEventListener("click",this._mousemoveHandler),this._button.addEventListener("mousedown",this._mousedownHandler),this._button.addEventListener("touchstart",this._touchdownHandler),this._track.classList.remove("red5pro-media-slider-disabled"),this._progressBar.classList.remove("red5pro-media-slider-disabled"),this._button.classList.remove("red5pro-media-slider-disabled"))}_layout(){const e=this._progressBar.parentNode.clientWidth*this._value;this._progressBar.style.width=e+"px",this._button.style.left=e-.5*this._button.clientWidth+"px"}createButton(){const e=oi("span");return e.classList.add("red5pro-media-slider-button"),e}createProgressBar(){const e=oi("span");return e.classList.add("red5pro-media-slider-progress"),e}createTrack(){const e=oi("span");return e.classList.add("red5pro-media-slider-track"),e}get value(){return this._value}set value(e){this._value=e,this._layout()}get disabled(){return this._disabled}set disabled(e){this._disabled=e,this._updateHandlers(e)}get view(){return this._container}}const{createElement:gi,isTouchEnabled:vi,isPossiblySafari:mi}=ie,Ei=e=>O("PlaybackControls",e);class bi extends ii{constructor(t,i){super(),this._state=e.PlaybackState.IDLE,this._mutedState=!1,this._resumeAfterSeek=!1,this._playbackDuration=0,this._volumeValue=1,this._player=t,this._container=i,this._onPlayPauseClickBound=this._onPlayPauseClick.bind(this),this._decorate(this._container)}_decorate(t){if(!t)return;Ei("[decorate]");const i=gi("div");let n;i.classList.add("red5pro-media-control-bar"),this._playPauseButton=this._createPlayPauseButton(),this._muteButton=this._createMuteButton(),this._volumeField=this._createVolumeControl(),this._seekTimeField=this._createSeekControl(),this._timeField=this._createPlaybackTime(),this._fullScreenButton=this._createFullScreenToggle(),i.appendChild(this._playPauseButton),i.appendChild(this._timeField),i.appendChild(this._seekTimeField.view),i.appendChild(this._muteButton),i.appendChild(this._volumeField.view),i.appendChild(this._fullScreenButton),t.appendChild(i),this._controlbar=i;const s=()=>{clearTimeout(n),n=setTimeout((()=>{i.classList.remove("red5pro-media-control-bar-show")}),6e3)};vi()?(i.classList.add("red5pro-media-control-bar-show"),t.addEventListener("touchend",(()=>{i.classList.toggle("red5pro-media-control-bar-show"),s()})),s()):(t.addEventListener("mouseover",(()=>{i.classList.add("red5pro-media-control-bar-show")})),t.addEventListener("mouseout",(()=>{i.classList.remove("red5pro-media-control-bar-show")}))),this.setState(e.PlaybackState.IDLE).onFullScreenChange(!1).setSeekTime(0).enable(!1)}_onPlayPauseClick(){return this.getState()===e.PlaybackState.PLAYING?this._player.pause(!0):this.getState()===e.PlaybackState.PAUSED?this._player.resume(!0):this._player.play(!0),this}_createPlayPauseButton(){const e=gi("button");return e.setAttribute("aria-label","Toggle Playback"),e.classList.add("red5pro-media-control-element"),e.classList.add("red5pro-media-element-button"),e.classList.add("red5pro-media-playpause-button"),e}_createMuteButton(){const e=gi("button");return e.setAttribute("aria-label","Toggle Mute Audio"),e.classList.add("red5pro-media-control-element"),e.classList.add("red5pro-media-element-button"),e.classList.add("red5pro-media-muteunmute-button"),e.addEventListener("click",(()=>{this.getMutedState()?(this._player.unmute(),this.setMutedState(!1)):(this._player.mute(),this.setMutedState(!0))})),e}_createVolumeControl(){const e=new _i("volume");return e.view.classList.add("red5pro-media-control-element"),e.view.classList.add("red5pro-media-volume-slider"),e.view.classList.add("red5pro-media-slider"),e.on(si.CHANGE,(e=>{const t=Number(e.data);this._player.setVolume(t)})),e}_createSeekControl(){const t=new _i("seek");return t.view.classList.add("red5pro-media-control-element"),t.view.classList.add("red5pro-media-seektime-slider"),t.view.classList.add("red5pro-media-slider"),t.on(si.CHANGE_START,(()=>{this.getState()===e.PlaybackState.PLAYING&&(this._resumeAfterSeek=!0,this._player.pause(!0,!0)),this.trigger(new me(ni.SEEK_START))})),t.on(si.CHANGE,(e=>{const t=Number(e.data);this._player.seekTo(t,0===this._playbackDuration?void 0:this._playbackDuration),this.setSeekTime(t*this._playbackDuration,this._playbackDuration)})),t.on(si.CHANGE_COMPLETE,(()=>{this._resumeAfterSeek&&this.getState()===e.PlaybackState.PAUSED&&(this._resumeAfterSeek=!1,this._player.resume(!0)),this.trigger(new me(ni.SEEK_END))})),t}_createPlaybackTime(){const e=gi("span"),t=gi("text");return t.textContent="00:00",e.classList.add("red5pro-media-control-element"),e.classList.add("red5pro-media-time-field"),e.appendChild(t),e}_createFullScreenToggle(){const e=gi("button");return e.setAttribute("aria-label","Toggle Fullscreen"),e.classList.add("red5pro-media-control-element"),e.classList.add("red5pro-media-element-button"),e.classList.add("red5pro-media-fullscreen-button"),e.addEventListener("click",(()=>{this._player.toggleFullScreen()})),e}_formatTime(e){const t=new Date(1e3*e);return`${String(t.getUTCHours()).padStart(2,"0")}:${String(t.getUTCMinutes()).padStart(2,"0")}:${String(t.getUTCSeconds()).padStart(2,"0")}`}onStateChange(t){var i,n,s,a;return t===e.PlaybackState.PLAYING?(null===(i=this._playPauseButton)||void 0===i||i.classList.remove("red5pro-media-play-button"),null===(n=this._playPauseButton)||void 0===n||n.classList.add("red5pro-media-pause-button")):(null===(s=this._playPauseButton)||void 0===s||s.classList.add("red5pro-media-play-button"),null===(a=this._playPauseButton)||void 0===a||a.classList.remove("red5pro-media-pause-button")),this}onMutedStateChange(e){var t,i,n,s;return e?(null===(t=this._muteButton)||void 0===t||t.classList.add("red5pro-media-mute-button"),null===(i=this._muteButton)||void 0===i||i.classList.remove("red5pro-media-unmute-button"),this._volumeField&&(this._volumeField.value=0)):(null===(n=this._muteButton)||void 0===n||n.classList.remove("red5pro-media-mute-button"),null===(s=this._muteButton)||void 0===s||s.classList.add("red5pro-media-unmute-button"),this._volumeField&&(this._volumeField.value=this._volumeValue)),this}onFullScreenChange(e){var t,i,n,s;return e?(null===(t=this._fullScreenButton)||void 0===t||t.classList.add("red5pro-media-exit-fullscreen-button"),null===(i=this._fullScreenButton)||void 0===i||i.classList.remove("red5pro-media-fullscreen-button")):(null===(n=this._fullScreenButton)||void 0===n||n.classList.remove("red5pro-media-exit-fullscreen-button"),null===(s=this._fullScreenButton)||void 0===s||s.classList.add("red5pro-media-fullscreen-button")),this}enable(e){var t,i,n,s;return e?(null===(t=this._playPauseButton)||void 0===t||t.classList.remove("red5pro-media-element-button-disabled"),null===(i=this._playPauseButton)||void 0===i||i.addEventListener("click",this._onPlayPauseClickBound)):(null===(n=this._playPauseButton)||void 0===n||n.classList.add("red5pro-media-element-button-disabled"),null===(s=this._playPauseButton)||void 0===s||s.removeEventListener("click",this._onPlayPauseClickBound)),this}getVolume(){return this._volumeValue}setVolume(e){return this._volumeField&&(this._volumeField.value=e),this._volumeValue=e,0===e?this.setMutedState(!0):this.getMutedState()&&this.setMutedState(!1),this}setSeekTime(e,t=0){return this._seekTimeField&&(this._seekTimeField.value=0===t?0:e/t,0!==this._playbackDuration&&this._playbackDuration<=e&&(this._seekTimeField.value=1)),this._timeField&&(!isFinite(this._playbackDuration)&&mi()?this._timeField.innerText="Live Broadcast":this._timeField.innerText=this._formatTime(Math.floor(e))),this}setPlaybackDuration(e){return this._playbackDuration=e,this}getPlaybackDuration(){return this._playbackDuration}getState(){return this._state}setState(e){return Ei(`[setState]: ${a[e]}`),this._state=e,this.onStateChange(this._state),this}setMutedState(e){return this._mutedState=e,this.onMutedStateChange(this._mutedState),this}getMutedState(){return"muted"in this._player?this._player.muted:this._mutedState}setAsVOD(e){return Ei(`[setAsVOD]: ${e}`),this._seekTimeField&&(e?this._seekTimeField.disabled=!1:(this._seekTimeField.value=0,this._seekTimeField.disabled=!0)),this}detach(){this.enable(!1),this._controlbar&&this._controlbar.parentNode&&this._controlbar.parentNode.removeChild(this._controlbar),this._controlbar=void 0,this._container=void 0}}var Si,Ci;!function(e){e[e.LIVE=0]="LIVE",e[e.VOD=1]="VOD"}(Si||(Si={})),function(e){e.LIVE="LiveSeek.LIVE",e.VOD="LiveSeek.VOD"}(Ci||(Ci={}));const Ti={[Si.LIVE]:Ci.LIVE,[Si.VOD]:Ci.VOD};var yi;!function(e){e.LIVE_SEEK_UNSUPPORTED="WebRTC.LiveSeek.Unsupported",e.LIVE_SEEK_ERROR="WebRTC.LiveSeek.Error",e.LIVE_SEEK_ENABLED="WebRTC.LiveSeek.Enabled",e.LIVE_SEEK_DISABLED="WebRTC.LiveSeek.Disabled",e.LIVE_SEEK_LOADING="WebRTC.LiveSeek.FragmentLoading",e.LIVE_SEEK_LOADED="WebRTC.LiveSeek.FragmentLoaded",e.LIVE_SEEK_CHANGE="WebRTC.LiveSeek.Change"}(yi||(yi={}));const{createElement:fi,findByQuerySelector:wi,createHLSClient:Ai,getHLSClientEventEnum:Pi}=ie,Ni="SourceHandlerSeekable",Ri=e=>O(Ni,e),Li=e=>H(Ni,e),Ii=e=>k(Ni,e);class Di extends Ht{constructor(e,t,i,n,s=!0){super(e,`${t}-Seekable`),this._hlsElementGenerated=!1,this._hlsRecoverFlop=!1,this._hlsRecoverAttempts=0,this._isFragLoading=!1,this._wallOffset=NaN,this._lastDurationUpdate=0,this._averageSegmentDuration=6,this._isSeekable=!1,this._isHLSPlaybackActive=!1,this._container=s?this._determineContainer(e):void 0,this._liveSeekConfig=i,this._hlsOptions=n,this._usePlaybackControls=s,this.onHLSDurationChange=this._onHLSDurationChange.bind(this),this.onHLSTimeUpdate=this._onHLSTimeUpdate.bind(this),this.onHLSPlay=this._onHLSPlay.bind(this),this.onHLSPause=this._onHLSPause.bind(this)}_determineContainer(e){if(e.parentNode&&e.parentNode.classList.contains("red5pro-media-container"))return e.classList.add("red5pro-media"),e.parentNode;{const t=e.parentNode,i=fi("div");return i.classList.add("red5pro-media-container"),e.classList.add("red5pro-media"),t.insertBefore(i,e),t.removeChild(e),i.appendChild(e),i}}_generateHLSLivePlayback(e,t,i){const n=`${i}-hls-vod`;let s=wi(`#${n}`);return s||(s=fi("video"),s.id=n,s.classList.add("red5pro-hls-vod"),s.classList.add("red5pro-media-background"),s.setAttribute("playsinline","playsinline"),s.style.width="100%",s.style.height="100%",s.style.display="none",e.insertBefore(s,t),this._hlsElementGenerated=!0),s}_onDurationChange(e){var t;Ri("[videoelement:event] durationchange");const i=null!==(t=this._playbackNotificationCenter)&&void 0!==t?t:e.target,n=this.getControls();!this.isSeekable&&n&&n.setPlaybackDuration(i.duration)}_onTimeUpdate(t){var i;const n=null!==(i=this._playbackNotificationCenter)&&void 0!==i?i:t.target,s=this.getControls();if(this.isSeekable){if(!this._isHLSPlaybackActive){const t=this._hlsElement.duration,i=n.currentTime-this._lastDurationUpdate,a=isNaN(t)||0===t?n.currentTime:t+this._averageSegmentDuration+i;s&&s.setSeekTime(a,a),this.trigger(new be(e.SubscriberEventTypes.PLAYBACK_TIME_UPDATE,void 0,{time:a,duration:a,action:"rtc time update (1)"}))}}else super._onTimeUpdate(t)}_onEnded(){this.isHLSPlaybackActive||super._onEnded()}_onHLSDurationChange(t){const i=t.target,n=t.duration||i.duration;isNaN(this._wallOffset)&&(this._wallOffset=n-this._view.currentTime),this._lastDurationUpdate=this._view.currentTime;const s=n+this._averageSegmentDuration;Ri(`[HLS:videoelement:duration] ${n}, ${this._averageSegmentDuration}`);const a=this.getControls();a&&a.setPlaybackDuration(s),this._isHLSPlaybackActive?this.trigger(new be(e.SubscriberEventTypes.PLAYBACK_TIME_UPDATE,void 0,{time:i.currentTime,duration:s,action:"hls time update"})):this.trigger(new be(e.SubscriberEventTypes.PLAYBACK_TIME_UPDATE,void 0,{time:s,duration:s,action:"hls time update"}))}_onHLSTimeUpdate(t){const i=t.target,n=this.getControls();n&&n.setSeekTime(i.currentTime,n.getPlaybackDuration()),i.currentTime>=i.duration?this._showHLSLivePlayback(!1,this._hlsElement,this._view,this._container):!isNaN(i.duration)&&this._isHLSPlaybackActive&&this.trigger(new be(e.SubscriberEventTypes.PLAYBACK_TIME_UPDATE,void 0,{time:i.currentTime,duration:i.duration+this._averageSegmentDuration,action:"hls time update"}))}_onHLSPlay(){Ri("[HLS:videoelement:event] play");const t=this.getControls();t&&t.setState(e.PlaybackState.PLAYING),this.trigger(new be(e.SubscriberEventTypes.PLAYBACK_STATE_CHANGE,void 0,{code:e.PlaybackState.PLAYING,state:a[e.PlaybackState.PLAYING]}))}_onHLSPause(){Ri("[HLS:videoelement:event] pause");const t=this.getControls();t&&t.setState(e.PlaybackState.PAUSED),this.trigger(new be(e.SubscriberEventTypes.PLAYBACK_STATE_CHANGE,void 0,{code:e.PlaybackState.PAUSED,state:a[e.PlaybackState.PAUSED]}))}_addSeekableHandlers(e,t,i){if(t){const i=Pi();t.on(i.ERROR,((i,n)=>{const{type:s,details:a,fatal:o,url:r}=n;if("networkerror"===s.toLowerCase()){if("levelemptyerror"===a.toLowerCase()){this.trigger(new be(yi.LIVE_SEEK_DISABLED,void 0,{hlsElement:e,hlsControl:t})),this.isSeekable=!1,t.destroy();const i=setTimeout((()=>{clearTimeout(i),this.enableLiveSeek(r,this._subscriptionId,this._hlsElement,!1)}),3e3);return}this.trigger(new be(yi.LIVE_SEEK_ERROR,void 0,{hlsElement:e,hlsControl:t,error:n}))}else this.trigger(new be(yi.LIVE_SEEK_ERROR,void 0,{hlsElement:e,hlsControl:t,error:n}));"mediaerror"===s.toLowerCase()&&(this._hlsRecoverFlop&&t.swapAudioCodec(),this._hlsRecoverFlop=!this._hlsRecoverFlop,this._hlsRecoverAttempts=this._hlsRecoverAttempts+1,t.recoverMediaError()),o&&"networkerror"===s.toLowerCase()&&t.startLoad()})),t.on(i.MANIFEST_PARSED,(()=>{try{e.pause()}catch(e){Ri(`Could not pause seekable live stream: ${e.message}`)}this.isSeekable=!0,this.trigger(new be(yi.LIVE_SEEK_ENABLED,void 0,{hlsElement:e,hlsControl:t}))})),t.on(i.FRAG_LOADING,((i,n)=>{const{frag:{stats:{loaded:s,total:a}}}=n;this.trigger(new be(yi.LIVE_SEEK_LOADING,void 0,{hlsElement:e,hlsControl:t,progress:s/a*100})),(this._isHLSPlaybackActive||this._isFragLoading)&&(this._isFragLoading=s/a>=1)})),t.on(i.FRAG_LOADED,((i,n)=>{this._isFragLoading=!1;const{frag:{endDTS:s,loader:a}}=n;if(!this._isHLSPlaybackActive&&!s)return;let o=6,r=0;if(a&&a.stats&&a.stats.segments){const e=a.stats.segments;for(let t=0;t{this._isFragLoading=!1;const{frag:{endDTS:s,loader:a}}=n;if(!this._isHLSPlaybackActive&&!s)return;let o=6,r=0;if(a&&a.stats&&a.stats.segments){const e=a.stats.segments;for(let t=0;tn.test(e)));if(!o)return void Ii(`Could not find last segment in manifest: ${e}`);const r=a.find((e=>i.test(e)));if(!r)return void Ii(`Could not find duration line in manifest: ${e}`);const l=r.match(i);if(!l)return void Ii(`Could not find duration in manifest: ${e}`);const h=l[1],d=parseFloat(h),c=o.match(n);if(!c)return void Ii(`Could not find segment length in manifest: ${e}`);const u=c[1];let p=parseInt(u,10);isNaN(p)&&(p=1),p=p>1?p-1:p,this._averageSegmentDuration=d,this.isSeekable=!0,this.trigger(new be(yi.LIVE_SEEK_ENABLED,void 0,{hlsElement:this._hlsElement,hlsControl:void 0})),this.onHLSDurationChange({target:t,duration:d*p}),this._manifestLoadTimeout=setTimeout((()=>{clearTimeout(this._manifestLoadTimeout),this._loadManifest(e,t)}),1e3*d)}catch(e){Li(`Could not load manifest: ${e.message}.`),this.trigger(new be(yi.LIVE_SEEK_DISABLED,void 0,{hlsElement:t,hlsControl:void 0})),this.isSeekable=!1}}_cleanup(){this._removeSeekableHandlers(this._hlsElement,this._hlsjsRef),this._hlsjsRef&&(this._hlsjsRef.detachMedia(),this._hlsjsRef=void 0),this._hlsElement&&(this._hlsElement.parentNode&&this._hlsElementGenerated&&this._hlsElement.parentNode.removeChild(this._hlsElement),this._hlsElement=void 0),this._playbackControls&&(this._playbackControls.detach(),this._playbackControls=void 0),this._isVOD=!1,this._isSeekable=!1,this._isHLSPlaybackActive=!1,this._isFragLoading=!1,this._hlsRecoverFlop=!1,this._hlsRecoverAttempts=0,this._averageSegmentDuration=6,this._hlsElementGenerated=!1,this._wallOffset=NaN,this._lastDurationUpdate=0,this._manifestLoadTimeout&&(clearTimeout(this._manifestLoadTimeout),this._manifestLoadTimeout=void 0),super._cleanup()}addSource(){Ri("[addSource]"),this._view.controls=!0,this._view.classList.add("red5pro-media");this._view.hasAttribute("controls")&&this._view.classList.contains("red5pro-media")&&(this._container=this._determineContainer(this._view));const e=this._view.hasAttribute("muted");this._usePlaybackControls?(this._playbackControls=new bi(this,this._container),this._view.controls=!1,this._playbackControls.setAsVOD(this.isSeekable),this._playbackControls.setMutedState(e)):this._view.controls=!1}enableLiveSeek(e,t,i,n=!1){if(this.getControls()&&this.getControls().setSeekTime(1,1),this._url=e,this._subscriptionId=t,this._hlsElement=i||this._generateHLSLivePlayback(this._container,this._view,t),this._showHLSLivePlayback(this._isHLSPlaybackActive,this._hlsElement,this._view,this._container),n){this._addSeekableHandlers(this._hlsElement,void 0,!1);const t=fi("source");t.src=e,this._hlsElement.appendChild(t),this._loadManifest(e,this._hlsElement)}else{const t=this._hlsOptions,{liveSeek:{hlsjsRef:i}}=this._liveSeekConfig,n=i?new i(t):Ai(t);this._addSeekableHandlers(this._hlsElement,n,!0),n.attachMedia(this._hlsElement,e),n.on(Pi().MEDIA_ATTACHED,(()=>{n.loadSource(e)})),this._hlsjsRef=n}}switchLiveSeek(e){this._hlsjsRef&&(this._hlsjsRef.destroy(),this._hlsjsRef=void 0),this.enableLiveSeek(e,this._subscriptionId,this._hlsElement),this.seekTo(1);try{this._view.play()}catch(e){Ii("[videoelement:action] play (FAULT) - "+e.message)}this._url=e}async play(e=!1){Ri("[videoelement:action] play");try{return e&&this._hlsElement&&this._hlsElement.paused?(await this._hlsElement.play(),!0):super.play()}catch(e){Ii("[videoelement:action] play (CATCH::FAULT) - "+e.message)}return!1}async pause(e=!1,t=!1){Ri("[videoelement:action] pause");try{return e&&t&&this._hlsElement?(this._hlsElement.pause(),super.pause()):e&&this._hlsElement&&!this._hlsElement.paused?(this._hlsElement.pause(),!0):super.pause()}catch(e){Ii("[videoelement:action] pause (CATCH::FAULT) - "+e.message)}return!1}async resume(e=!1){var t,i;Ri("[videoelement:action] resume");try{const n=this._isHLSPlaybackActive&&this._hlsElement?this._hlsElement.play():null===(t=this._view)||void 0===t?void 0:t.play();if(e&&this._isHLSPlaybackActive)return await(null===(i=this._view)||void 0===i?void 0:i.play()),!0;n&&n.then((()=>Ri("[videoelement:action] play (START)"))).catch((e=>Ii("[videoelement:action] play (CATCH::FAULT) "+(e.message?e.message:e))))}catch(e){Ii("[videoelement:action] resume (CATCH::FAULT) - "+e.message)}return!1}async stop(){Ri("[videoelement:action] stop");try{return this._hlsElement&&this._hlsElement.pause(),super.stop()}catch(e){Ii("[videoelement:action] stop (CATCH::FAULT) - "+e.message)}return!1}mute(){this._hlsElement&&(this._hlsElement.muted=this._isHLSPlaybackActive),this._view&&(this._view.muted=!0);const e=this.getControls();e&&e.setMutedState(!0)}unmute(){this._hlsElement&&(this._hlsElement.muted=!this._isHLSPlaybackActive,this._view&&(this._view.muted=this._isHLSPlaybackActive)),this._view&&(this._view.muted=!1);const e=this.getControls();e&&e.setMutedState(!1)}setVolume(e){this.unmute(),this._hlsElement&&this._isHLSPlaybackActive?this._hlsElement.volume=e:this._view?this._view.volume=e:Li("[videoelement:action] setVolume (CATCH::FAULT) - "+e)}seekTo(e,t=void 0){if(this.isSeekable)if(this.getControls()&&this.getControls().setSeekTime(e,t),this.trigger(new be(yi.LIVE_SEEK_CHANGE,void 0,{seek:e,duration:t})),this._hlsElement&&e<1)try{this._hlsElement.classList.remove("hidden"),this._hlsElement.currentTime=this._hlsElement.duration*e,this._isFragLoading=!0,this._showHLSLivePlayback(!0,this._hlsElement,this._view,this._container),this._view.paused||(Ri("[hlsvod:action] play (START) - (seekTo)"),this.play(!0))}catch(e){Ii("[hlsvod:action] play (CATCH::FAULT) - "+e.message)}else this._hlsElement&&e>=1&&(this._isFragLoading=!1,this._showHLSLivePlayback(!1,this._hlsElement,this._view,this._container));else this._view.currentTime=t?e*t:e}toggleFullScreen(e){var t;this._container&&super.toggleFullScreen(null!==(t=this._container)&&void 0!==t?t:e)}getControls(){return this._playbackControls}get isSeekable(){return this._isSeekable}set isSeekable(e){this._isSeekable=e,this.getControls()&&this.getControls().setAsVOD(e)}get isHLSPlaybackActive(){return this._isHLSPlaybackActive}get url(){return this._url}}const{supportsHLS:Oi,supportsNonNativeHLS:ki}=ie,Hi="WHEPLiveSeekClient",Mi=e=>H(Hi,e);class Ui extends $t{constructor(e,t,i){super(e,t,i)}async init(e){const{liveSeek:t}=e;return t||(e.liveSeek=ei),super.init(e)}_attachSourceHandler(e){var t;if((null===(t=this._playbackView)||void 0===t?void 0:t.view)&&!this._enableLiveSeek(this._playbackView.view))return k(Hi,"LiveSeek is not enabled, using default source handler"),void super._attachSourceHandler(e);this._startSeekableIfSeekableEnabled(this._options)}_enableLiveSeek(e){const{liveSeek:t}=this._options;if(t){const{hlsjsRef:i,usePlaybackControlsUI:n,options:s}=t;if(Oi()||ki(i))return this._sourceHandler=new Di(e,this.getType(),this._options,s,n),this._sourceHandler.addSource(),!0;Mi("Could not utilize the 'LiveSeek' request. This feature requires either native HLS playback or hls.js as a depenency."),this.trigger(new be(yi.LIVE_SEEK_UNSUPPORTED,this,{feature:"Live Seek",message:"Live Seek requires integration with the HLS.JS plugin in order work properly. Most likely you are viewing this on a browser that does not support the use of HLS.JS."}))}return!1}_startSeekableIfSeekableEnabled(e){const{liveSeek:t,subscriptionId:i}=e;if(!t)return;const{hlsjsRef:n,hlsElement:s}=t;if(this._sourceHandler)try{if(!Oi()&&!ki(n))throw new Error;{const t=ne(e);this._sourceHandler.enableLiveSeek(t,i,s,!ki(n))}}catch(e){Mi("Could not utilize the 'LiveSeek' request. This feature requires either native HLS playback or hls.js as a depenency.")}}_onUnpublish(){super._onUnpublish();const{liveSeek:e}=this._options;e||this.unsubscribe(!0)}_onStreamSwitchComplete(){const e=this._requestedStreamSwitch,{liveSeek:t}=this._options;if(t&&e){const{baseURL:i,fullURL:n}=t,s=e.split("/"),a=s.pop(),o=s.join("/"),r={...this._options,app:o,streamName:a};let l=n;if(n){const e=/.*\/(.*)\.m3u8/.exec(n);if(e&&e.length>1){const t=`${e[1]}.m3u8`;l=n.replace(t,`${a}.m3u8`)}}const h=ne(r,i,l);this._sourceHandler&&this._sourceHandler.switchLiveSeek(h)}super._onStreamSwitchComplete()}}const Bi="15.3.0";L(R.ERROR);const Vi=(e,t=!1)=>{Object.prototype.hasOwnProperty.call(R,e.toUpperCase())&&(L(e,t),console&&console.log(`Red5 Pro SDK Version ${Fi()}`))},Fi=()=>Bi;O("RED5",`Red5 Pro HTML SDK Version: ${Bi}`);var $i={version:Bi,LOG_LEVELS:R,getLogger:I,getRecordedLogs:D,setLogLevel:Vi,getVersion:Fi,PlaybackVideoEncoder:e.PlaybackVideoEncoder,PlaybackAudioEncoder:e.PlaybackAudioEncoder,PlaybackState:e.PlaybackState,PlaybackStateReadableMap:a,PublishVideoEncoder:e.PublishVideoEncoder,PublishAudioEncoder:e.PublishAudioEncoder,SubscriberEvent:be,PublisherEvent:Ee,MessageTransportStateEvent:Se,PubNubEvent:Ce,MessageChannelEvent:Te,PublisherEventTypes:e.PublisherEventTypes,SubscriberEventTypes:e.SubscriberEventTypes,RTCPublisherEventTypes:e.RTCPublisherEventTypes,RTCSubscriberEventTypes:e.RTCSubscriberEventTypes,MessageTransportStateEventTypes:e.MessageTransportStateEventTypes,MessageChannelEventTypes:e.MessageChannelEventTypes,PubNubEventTypes:lt,WHIPClient:Tt,WHEPClient:$t,HLSSubscriber:Zt,LiveSeekClient:Ui,PubNubClient:vt,MessageChannel:Jt,Capability:Gt,defaultWhepSubscriberConfig:yt,defaultWhipPublisherConfig:ge,defaultStatsConfig:pe,StatsEndpointType:e.StatsEndpointType};e.Capability=Gt,e.Event=me,e.EventEmitter=U,e.HLSSubscriber=Zt,e.LOG_LEVELS=R,e.LiveSeekClient=Ui,e.MessageChannel=Jt,e.MessageChannelEvent=Te,e.MessageTransportStateEvent=Se,e.PlaybackController=It,e.PlaybackControls=ii,e.PlaybackStateReadableMap=a,e.PubNubClient=vt,e.PubNubEvent=Ce,e.PublisherEvent=Ee,e.SourceHandler=Dt,e.SourceHandlerImpl=Ht,e.SubscriberEvent=be,e.WHEPClient=$t,e.WHIPClient=Tt,e.default=$i,e.defaultHLSSubscriberConfig=ft,e.defaultLiveSeekConfig=ti,e.defaultStatsConfig=pe,e.defaultWhepSubscriberConfig=yt,e.defaultWhipPublisherConfig=ge,e.getLogger=I,e.getRecordedLogs=D,e.getVersion=Fi,e.setLogLevel=Vi,Object.defineProperty(e,"__esModule",{value:!0})}));
diff --git a/static/script/message-channel-status.js b/static/script/message-channel-status.js
new file mode 100644
index 00000000..e0b3b06d
--- /dev/null
+++ b/static/script/message-channel-status.js
@@ -0,0 +1,98 @@
+/*
+Copyright © 2015 Infrared5, Inc. All rights reserved.
+
+The accompanying code comprising examples for use solely in conjunction with Red5 Pro (the "Example Code")
+is licensed to you by Infrared5 Inc. in consideration of your agreement to the following
+license terms and conditions. Access, use, modification, or redistribution of the accompanying
+code constitutes your acceptance of the following license terms and conditions.
+
+Permission is hereby granted, free of charge, to you to use the Example Code and associated documentation
+files (collectively, the "Software") without restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
+persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The Software shall be used solely in conjunction with Red5 Pro. Red5 Pro is licensed under a separate end
+user license agreement (the "EULA"), which must be executed with Infrared5, Inc.
+An example of the EULA can be found on our website at: https://account.red5.net/assets/LICENSE.txt.
+
+The above copyright notice and this license shall be included in all copies or portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL INFRARED5, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+;(function (window, document) {
+ 'use strict'
+
+ var field = document.getElementById('status-field')
+ var inFailedState = false
+
+ function updateStatusFromEvent(event, statusField) {
+ if (inFailedState) {
+ return
+ }
+ statusField = typeof statusField !== 'undefined' ? statusField : field
+ var pubTypes = window.red5prosdk.PublisherEventTypes
+ var rtcTypes = window.red5prosdk.RTCPublisherEventTypes
+ var messageChannelTypes = window.red5prosdk.MessageChannelEventTypes
+ var status
+
+ switch (event.type) {
+ case 'ERROR':
+ inFailedState = true
+ status = ['ERROR', event.data].join(': ')
+ break
+ case pubTypes.CONNECTION_CLOSED:
+ status = 'Connection closed.'
+ window.untrackBitrate()
+ inFailedState = false
+ break
+ case pubTypes.CONNECT_SUCCESS:
+ status = 'Connection established...'
+ inFailedState = false
+ break
+ case pubTypes.CONNECT_FAILURE:
+ status = 'Error - Could not establish connection.'
+ inFailedState = true
+ break
+ case rtcTypes.PEER_CONNECTION_AVAILABLE:
+ status = 'Peer Connection available...'
+ break
+ case rtcTypes.OFFER_START:
+ status = 'Begin offer...'
+ break
+ case rtcTypes.OFFER_END:
+ status = 'Offer accepted...'
+ break
+ case rtcTypes.ICE_TRICKLE_COMPLETE:
+ status = 'Negotiation complete. Waiting Publish Start...'
+ break
+ case messageChannelTypes.OPEN:
+ status = 'Message Channel opened.'
+ break
+ case messageChannelTypes.CLOSE:
+ status = 'Message Channel closed.'
+ break
+ case messageChannelTypes.ERROR:
+ status = 'Error - Message Channel error.'
+ break
+ case messageChannelTypes.FAIL:
+ status = 'Error - Message Channel fail.'
+ break
+ }
+ if (status && status.length > 0) {
+ statusField.innerText = ['STATUS', status].join(': ')
+ }
+ }
+
+ function clearStatusEvent(statusField) {
+ inFailedState = false
+ statusField = typeof statusField !== 'undefined' ? statusField : field
+ statusField.innerText = ''
+ }
+
+ window.red5proHandleMessageChannelEvent = updateStatusFromEvent
+ window.red5proClearMessageChannelEvent = clearStatusEvent
+})(this, document)