ovenlivekit 1.0.3 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -40,7 +40,7 @@ import OvenLiveKit from 'ovenlivekit'
40
40
  This is the simplest example of sending a device media stream such as a webcam to OvenMediaEngine's WebRTC Provider.
41
41
  ```JavaScript
42
42
  // Initialize OvenLiveKit
43
- let ovenLivekit = OvenLiveKit.create();
43
+ const ovenLivekit = OvenLiveKit.create();
44
44
 
45
45
  // Get media stream from user device
46
46
  ovenLivekit.getUserMedia().then(function () {
@@ -104,7 +104,7 @@ var config = {
104
104
  }
105
105
 
106
106
  // Initialize ovenLivekit instance
107
- let ovenLivekit = OvenLiveKit.create(config);
107
+ const ovenLivekit = OvenLiveKit.create(config);
108
108
 
109
109
  // Release all resources and destroy the instance
110
110
  ovenLivekit.remove();
@@ -219,7 +219,7 @@ OvenLiveKit also provides APIs to control a media stream from a user device.
219
219
  ```
220
220
  ```JavaScript
221
221
  // Create instance
222
- let ovenLivekit = OvenLiveKit.create();
222
+ const ovenLivekit = OvenLiveKit.create();
223
223
 
224
224
  // Attaching video element for playing device stream
225
225
  ovenLivekit.attachMedia(document.getElementById('myVideo'));
@@ -254,7 +254,7 @@ ovenLivekit.getUserMedia(constraints).then(function (stream) {
254
254
  Congrats on getting the media stream from the user device and then ready to stream into OvenMediaEngine.
255
255
  ```JavaScript
256
256
  // Create instance
257
- let ovenLivekit = OvenLiveKit.create();
257
+ const ovenLivekit = OvenLiveKit.create();
258
258
 
259
259
  ovenLivekit.getUserMedia().then(function () {
260
260
 
@@ -293,6 +293,9 @@ ovenLivekit.getUserMedia().then(function () {
293
293
  - String: String you want to append to a=fmtp of SDP.
294
294
  - If set video format is appended to the a=fmtp sections of SDP.
295
295
 
296
+ #### `instance.stopStreaming()`
297
+ - Close peer connection and websocket associated with OvenMediaEngine.
298
+
296
299
  ## For more information
297
300
  * [WebRTC Input in OvenPlayer Demo](https://demo.ovenplayer.com/demo_input.html)
298
301
  * Test Player based on OvenPlayer.
@@ -26,7 +26,7 @@ return /******/ (() => { // webpackBootstrap
26
26
  \****************************/
27
27
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
28
28
 
29
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\nconst OvenLiveKit = {};\r\n\r\nconst logHeader = 'OvenLiveKit.js :';\r\nconst logEventHeader = 'OvenLiveKit.js ====';\r\n\r\n// private methods\r\nfunction sendMessage(webSocket, message) {\r\n\r\n if (webSocket) {\r\n webSocket.send(JSON.stringify(message));\r\n }\r\n}\r\n\r\nfunction generateDomainFromUrl(url) {\r\n let result = '';\r\n let match;\r\n if (match = url.match(/^(?:wss?:\\/\\/)?(?:[^@\\n]+@)?(?:www\\.)?([^:\\/\\n\\?\\=]+)/im)) {\r\n result = match[1];\r\n }\r\n\r\n return result;\r\n}\r\n\r\nfunction findIp(string) {\r\n\r\n let result = '';\r\n let match;\r\n\r\n if (match = string.match(new RegExp('\\\\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\b', 'gi'))) {\r\n result = match[0];\r\n }\r\n\r\n return result;\r\n}\r\n\r\nfunction checkIOSVersion() {\r\n var agent = window.navigator.userAgent,\r\n start = agent.indexOf('OS ');\r\n if ((agent.indexOf('iPhone') > -1 || agent.indexOf('iPad') > -1) && start > -1) {\r\n return window.Number(agent.substr(start + 3, 3).replace('_', '.'));\r\n }\r\n return 0;\r\n}\r\n\r\nfunction getFormatNumber(sdp, format) {\r\n\r\n const lines = sdp.split('\\r\\n');\r\n let formatNumber = -1;\r\n\r\n for (let i = 0; i < lines.length - 1; i++) {\r\n\r\n lines[i] = lines[i].toLowerCase();\r\n\r\n if (lines[i].indexOf('a=rtpmap') > -1 && lines[i].indexOf(format.toLowerCase()) > -1) {\r\n // parsing \"a=rtpmap:100 H264/90000\" line\r\n formatNumber = lines[i].split(' ')[0].split(':')[1];\r\n break;\r\n }\r\n }\r\n\r\n return formatNumber;\r\n}\r\n\r\nfunction removeFormat(sdp, formatNumber) {\r\n let newLines = [];\r\n let lines = sdp.split('\\r\\n');\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n\r\n if (lines[i].indexOf('m=video') === 0) {\r\n newLines.push(lines[i].replace(' ' + formatNumber + '', ''));\r\n } else if (lines[i].indexOf(formatNumber + '') > -1) {\r\n\r\n } else {\r\n newLines.push(lines[i]);\r\n }\r\n }\r\n\r\n return newLines.join('\\r\\n')\r\n}\r\n\r\nasync function getStreamForDeviceCheck(type) {\r\n\r\n // High resolution video constraints makes browser to get maximum resolution of video device.\r\n const constraints = {\r\n };\r\n\r\n if (type === 'both') {\r\n constraints.audio = true;\r\n constraints.video = true;\r\n } else if (type === 'audio') {\r\n constraints.audio = true;\r\n } else if (type === 'video') {\r\n constraints.video = true;\r\n }\r\n\r\n return await navigator.mediaDevices.getUserMedia(constraints);\r\n}\r\n\r\nasync function getDevices() {\r\n\r\n return await navigator.mediaDevices.enumerateDevices();\r\n}\r\n\r\nfunction gotDevices(deviceInfos) {\r\n\r\n let devices = {\r\n 'audioinput': [],\r\n 'audiooutput': [],\r\n 'videoinput': [],\r\n 'other': [],\r\n };\r\n\r\n for (let i = 0; i !== deviceInfos.length; ++i) {\r\n\r\n const deviceInfo = deviceInfos[i];\r\n\r\n let info = {};\r\n\r\n info.deviceId = deviceInfo.deviceId;\r\n\r\n if (deviceInfo.kind === 'audioinput') {\r\n\r\n info.label = deviceInfo.label || `microphone ${devices.audioinput.length + 1}`;\r\n devices.audioinput.push(info);\r\n } else if (deviceInfo.kind === 'audiooutput') {\r\n\r\n info.label = deviceInfo.label || `speaker ${devices.audiooutput.length + 1}`;\r\n devices.audiooutput.push(info);\r\n } else if (deviceInfo.kind === 'videoinput') {\r\n\r\n info.label = deviceInfo.label || `camera ${devices.videoinput.length + 1}`;\r\n devices.videoinput.push(info);\r\n } else {\r\n\r\n info.label = deviceInfo.label || `other ${devices.other.length + 1}`;\r\n devices.other.push(info);\r\n }\r\n }\r\n\r\n return devices;\r\n}\r\n\r\nfunction initConfig(instance, options) {\r\n\r\n instance.stream = null;\r\n instance.webSocket = null;\r\n instance.peerConnection = null;\r\n instance.connectionConfig = {};\r\n\r\n instance.status = 'creating';\r\n\r\n instance.videoElement = null;\r\n instance.connectionUrl = null;\r\n\r\n if (options && options.callbacks) {\r\n\r\n instance.callbacks = options.callbacks;\r\n } else {\r\n instance.callbacks = {};\r\n }\r\n\r\n}\r\n\r\nfunction addMethod(instance) {\r\n\r\n function errorHandler(error) {\r\n\r\n if (instance.callbacks.error) {\r\n\r\n instance.callbacks.error(error);\r\n }\r\n }\r\n\r\n function getUserMedia(constraints) {\r\n\r\n if (!constraints) {\r\n\r\n constraints = {\r\n video: {\r\n deviceId: undefined\r\n },\r\n audio: {\r\n deviceId: undefined\r\n }\r\n };\r\n }\r\n\r\n console.info(logHeader, 'Requested Constraint To Input Devices', constraints);\r\n\r\n return navigator.mediaDevices.getUserMedia(constraints)\r\n .then(function (stream) {\r\n\r\n console.info(logHeader, 'Received Media Stream From Input Device', stream);\r\n\r\n instance.stream = stream;\r\n\r\n let elem = instance.videoElement;\r\n\r\n // Attach stream to video element when video element is provided.\r\n if (elem) {\r\n\r\n elem.srcObject = stream;\r\n\r\n elem.onloadedmetadata = function (e) {\r\n\r\n elem.play();\r\n };\r\n }\r\n\r\n return new Promise(function (resolve) {\r\n\r\n resolve(stream);\r\n });\r\n })\r\n .catch(function (error) {\r\n\r\n console.error(logHeader, 'Can\\'t Get Media Stream From Input Device', error);\r\n errorHandler(error);\r\n\r\n return new Promise(function (resolve, reject) {\r\n reject(error);\r\n });\r\n });\r\n }\r\n\r\n function getDisplayMedia(constraints) {\r\n\r\n if (!constraints) {\r\n constraints = {};\r\n }\r\n\r\n console.info(logHeader, 'Requested Constraint To Display', constraints);\r\n\r\n return navigator.mediaDevices.getDisplayMedia(constraints)\r\n .then(function (stream) {\r\n\r\n console.info(logHeader, 'Received Media Stream From Display', stream);\r\n\r\n instance.stream = stream;\r\n\r\n let elem = instance.videoElement;\r\n\r\n // Attach stream to video element when video element is provided.\r\n if (elem) {\r\n\r\n elem.srcObject = stream;\r\n\r\n elem.onloadedmetadata = function (e) {\r\n\r\n elem.play();\r\n };\r\n }\r\n\r\n return new Promise(function (resolve) {\r\n\r\n resolve(stream);\r\n });\r\n })\r\n .catch(function (error) {\r\n\r\n console.error(logHeader, 'Can\\'t Get Media Stream From Display', error);\r\n errorHandler(error);\r\n\r\n return new Promise(function (resolve, reject) {\r\n reject(error);\r\n });\r\n });\r\n }\r\n\r\n // From https://webrtchacks.com/limit-webrtc-bandwidth-sdp/\r\n function setBitrateLimit(sdp, media, bitrate) {\r\n\r\n let lines = sdp.split('\\r\\n');\r\n let line = -1;\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n if (lines[i].indexOf('m=' + media) === 0) {\r\n line = i;\r\n break;\r\n }\r\n }\r\n if (line === -1) {\r\n // Could not find the m line for media\r\n return sdp;\r\n }\r\n\r\n // Pass the m line\r\n line++;\r\n\r\n // Skip i and c lines\r\n while (lines[line].indexOf('i=') === 0 || lines[line].indexOf('c=') === 0) {\r\n\r\n line++;\r\n }\r\n\r\n // If we're on a b line, replace it\r\n if (lines[line].indexOf('b') === 0) {\r\n\r\n lines[line] = 'b=AS:' + bitrate;\r\n\r\n return lines.join('\\r\\n');\r\n }\r\n\r\n // Add a new b line\r\n let newLines = lines.slice(0, line)\r\n\r\n newLines.push('b=AS:' + bitrate)\r\n newLines = newLines.concat(lines.slice(line, lines.length))\r\n\r\n return newLines.join('\\r\\n')\r\n }\r\n\r\n function initWebSocket(connectionUrl) {\r\n\r\n if (!connectionUrl) {\r\n errorHandler('connectionUrl is required');\r\n return;\r\n }\r\n\r\n instance.connectionUrl = connectionUrl;\r\n\r\n let webSocket = null;\r\n\r\n try {\r\n\r\n webSocket = new WebSocket(connectionUrl);\r\n } catch (error) {\r\n\r\n errorHandler(error);\r\n }\r\n\r\n\r\n instance.webSocket = webSocket;\r\n\r\n webSocket.onopen = function () {\r\n\r\n // Request offer at the first time.\r\n sendMessage(webSocket, {\r\n command: 'request_offer'\r\n });\r\n };\r\n\r\n webSocket.onmessage = function (e) {\r\n\r\n let message = JSON.parse(e.data);\r\n\r\n if (message.error) {\r\n console.error('webSocket.onmessage', message.error);\r\n errorHandler(message.error);\r\n }\r\n\r\n if (message.command === 'offer') {\r\n\r\n // OME returns offer. Start create peer connection.\r\n createPeerConnection(\r\n message.id,\r\n message.peer_id,\r\n message.sdp,\r\n message.candidates,\r\n message.ice_servers\r\n );\r\n }\r\n };\r\n\r\n webSocket.onerror = function (error) {\r\n\r\n console.error('webSocket.onerror', error);\r\n errorHandler(error);\r\n };\r\n\r\n webSocket.onclose = function (e) {\r\n\r\n if (!instance.removing) {\r\n\r\n if (instance.callbacks.connectionClosed) {\r\n\r\n instance.callbacks.connectionClosed('websocket', e);\r\n }\r\n }\r\n };\r\n\r\n }\r\n\r\n function appendFmtp(sdp) {\r\n\r\n const fmtpStr = instance.connectionConfig.sdp.appendFmtp;\r\n\r\n const lines = sdp.split('\\r\\n');\r\n const payloads = [];\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n\r\n if (lines[i].indexOf('m=video') === 0) {\r\n\r\n let tokens = lines[i].split(' ')\r\n\r\n for (let j = 3; j < tokens.length; j++) {\r\n\r\n payloads.push(tokens[j]);\r\n }\r\n\r\n break;\r\n }\r\n }\r\n\r\n for (let i = 0; i < payloads.length; i++) {\r\n\r\n let fmtpLineFound = false;\r\n\r\n for (let j = 0; j < lines.length; j++) {\r\n\r\n if (lines[j].indexOf('a=fmtp:' + payloads[i]) === 0) {\r\n fmtpLineFound = true;\r\n lines[j] += ';' + fmtpStr;\r\n }\r\n }\r\n\r\n if (!fmtpLineFound) {\r\n\r\n for (let j = 0; j < lines.length; j++) {\r\n\r\n if (lines[j].indexOf('a=rtpmap:' + payloads[i]) === 0) {\r\n\r\n lines[j] += '\\r\\na=fmtp:' + payloads[i] + ' ' + fmtpStr;\r\n }\r\n }\r\n }\r\n }\r\n\r\n return lines.join('\\r\\n')\r\n }\r\n\r\n function appendOrientation(sdp) {\r\n\r\n const lines = sdp.split('\\r\\n');\r\n const payloads = [];\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n\r\n if (lines[i].indexOf('m=video') === 0) {\r\n\r\n let tokens = lines[i].split(' ')\r\n\r\n for (let j = 3; j < tokens.length; j++) {\r\n\r\n payloads.push(tokens[j]);\r\n }\r\n\r\n break;\r\n }\r\n }\r\n\r\n for (let i = 0; i < payloads.length; i++) {\r\n\r\n for (let j = 0; j < lines.length; j++) {\r\n\r\n if (lines[j].indexOf('a=rtpmap:' + payloads[i]) === 0) {\r\n\r\n lines[j] += '\\r\\na=extmap:' + payloads[i] + ' urn:3gpp:video-orientation';\r\n }\r\n }\r\n }\r\n\r\n return lines.join('\\r\\n')\r\n }\r\n\r\n function createPeerConnection(id, peerId, offer, candidates, iceServers) {\r\n\r\n let peerConnectionConfig = {};\r\n\r\n if (instance.connectionConfig.iceServers) {\r\n\r\n // first priority using ice servers from local config.\r\n peerConnectionConfig.iceServers = instance.connectionConfig.iceServers;\r\n\r\n if (instance.connectionConfig.iceTransportPolicy) {\r\n\r\n peerConnectionConfig.iceTransportPolicy = instance.connectionConfig.iceTransportPolicy;\r\n }\r\n } else if (iceServers) {\r\n\r\n // second priority using ice servers from ome and force using TCP\r\n peerConnectionConfig.iceServers = [];\r\n\r\n for (let i = 0; i < iceServers.length; i++) {\r\n\r\n let iceServer = iceServers[i];\r\n\r\n let regIceServer = {};\r\n\r\n regIceServer.urls = iceServer.urls;\r\n\r\n let hasWebSocketUrl = false;\r\n let webSocketUrl = generateDomainFromUrl(instance.connectionUrl);\r\n\r\n for (let j = 0; j < regIceServer.urls.length; j++) {\r\n\r\n let serverUrl = regIceServer.urls[j];\r\n\r\n if (serverUrl.indexOf(webSocketUrl) > -1) {\r\n hasWebSocketUrl = true;\r\n break;\r\n }\r\n }\r\n\r\n if (!hasWebSocketUrl) {\r\n\r\n if (regIceServer.urls.length > 0) {\r\n\r\n let cloneIceServer = regIceServer.urls[0];\r\n let ip = findIp(cloneIceServer);\r\n\r\n if (webSocketUrl && ip) {\r\n regIceServer.urls.push(cloneIceServer.replace(ip, webSocketUrl));\r\n }\r\n }\r\n }\r\n\r\n regIceServer.username = iceServer.user_name;\r\n regIceServer.credential = iceServer.credential;\r\n\r\n peerConnectionConfig.iceServers.push(regIceServer);\r\n }\r\n\r\n peerConnectionConfig.iceTransportPolicy = 'relay';\r\n } else {\r\n // last priority using default ice servers.\r\n\r\n if (instance.iceTransportPolicy) {\r\n\r\n peerConnectionConfig.iceTransportPolicy = instance.iceTransportPolicy;\r\n }\r\n }\r\n\r\n let advancedSetting = {\r\n optional: [\r\n {\r\n googHighStartBitrate: {\r\n exact: !0\r\n }\r\n },\r\n {\r\n googPayloadPadding: {\r\n exact: !0\r\n }\r\n },\r\n {\r\n googScreencastMinBitrate: {\r\n exact: 500\r\n }\r\n },\r\n {\r\n enableDscp: {\r\n exact: true\r\n }\r\n }\r\n ]\r\n };\r\n\r\n console.info(logHeader, 'Create Peer Connection With Config', peerConnectionConfig);\r\n\r\n let peerConnection = new RTCPeerConnection(peerConnectionConfig);\r\n\r\n instance.peerConnection = peerConnection;\r\n\r\n // set local stream\r\n instance.stream.getTracks().forEach(function (track) {\r\n\r\n console.info(logHeader, 'Add Track To Peer Connection', track);\r\n peerConnection.addTrack(track, instance.stream);\r\n });\r\n\r\n\r\n if (checkIOSVersion() >= 15) {\r\n const formatNumber = getFormatNumber(offer.sdp, 'H264');\r\n\r\n if (formatNumber > 0) {\r\n offer.sdp = removeFormat(offer.sdp, formatNumber);\r\n }\r\n }\r\n\r\n if (instance.connectionConfig.maxVideoBitrate) {\r\n\r\n // if bandwith limit is set. modify sdp from ome to limit acceptable bandwidth of ome\r\n offer.sdp = setBitrateLimit(offer.sdp, 'video', instance.connectionConfig.maxVideoBitrate);\r\n }\r\n\r\n if (instance.connectionConfig.sdp && instance.connectionConfig.sdp.appendFmtp) {\r\n\r\n offer.sdp = appendFmtp(offer.sdp);\r\n }\r\n\r\n // offer.sdp = appendOrientation(offer.sdp);\r\n\r\n peerConnection.setRemoteDescription(new RTCSessionDescription(offer))\r\n .then(function () {\r\n\r\n peerConnection.createAnswer()\r\n .then(function (answer) {\r\n\r\n if (checkIOSVersion() >= 15) {\r\n\r\n const formatNumber = getFormatNumber(answer.sdp, 'H264');\r\n\r\n if (formatNumber > 0) {\r\n\r\n answer.sdp = removeFormat(answer.sdp, formatNumber);\r\n }\r\n }\r\n\r\n if (instance.connectionConfig.sdp && instance.connectionConfig.sdp.appendFmtp) {\r\n\r\n answer.sdp = appendFmtp(answer.sdp);\r\n }\r\n\r\n peerConnection.setLocalDescription(answer)\r\n .then(function () {\r\n\r\n sendMessage(instance.webSocket, {\r\n id: id,\r\n peer_id: peerId,\r\n command: 'answer',\r\n sdp: answer\r\n });\r\n })\r\n .catch(function (error) {\r\n\r\n console.error('peerConnection.setLocalDescription', error);\r\n errorHandler(error);\r\n });\r\n })\r\n .catch(function (error) {\r\n\r\n console.error('peerConnection.createAnswer', error);\r\n errorHandler(error);\r\n });\r\n })\r\n .catch(function (error) {\r\n\r\n console.error('peerConnection.setRemoteDescription', error);\r\n errorHandler(error);\r\n });\r\n\r\n if (candidates) {\r\n\r\n addIceCandidate(peerConnection, candidates);\r\n }\r\n\r\n peerConnection.onicecandidate = function (e) {\r\n\r\n if (e.candidate && e.candidate.candidate) {\r\n\r\n console.info(logHeader, 'Candidate Sent', '\\n', e.candidate.candidate, '\\n', e);\r\n\r\n sendMessage(instance.webSocket, {\r\n id: id,\r\n peer_id: peerId,\r\n command: 'candidate',\r\n candidates: [e.candidate]\r\n });\r\n }\r\n };\r\n\r\n peerConnection.oniceconnectionstatechange = function (e) {\r\n\r\n let state = peerConnection.iceConnectionState;\r\n\r\n if (instance.callbacks.iceStateChange) {\r\n\r\n console.info(logHeader, 'ICE State', '[' + state + ']');\r\n instance.callbacks.iceStateChange(state);\r\n }\r\n\r\n if (state === 'connected') {\r\n\r\n if (instance.callbacks.connected) {\r\n\r\n console.info(logHeader, 'Iceconnection Connected', e);\r\n instance.callbacks.connected(e);\r\n }\r\n }\r\n\r\n if (state === 'failed' || state === 'disconnected' || state === 'closed') {\r\n\r\n if (instance.callbacks.connectionClosed) {\r\n\r\n console.error(logHeader, 'Iceconnection Closed', e);\r\n instance.callbacks.connectionClosed('ice', e);\r\n }\r\n }\r\n }\r\n }\r\n\r\n function addIceCandidate(peerConnection, candidates) {\r\n\r\n for (let i = 0; i < candidates.length; i++) {\r\n\r\n if (candidates[i] && candidates[i].candidate) {\r\n\r\n let basicCandidate = candidates[i];\r\n\r\n peerConnection.addIceCandidate(new RTCIceCandidate(basicCandidate))\r\n .then(function () {\r\n\r\n })\r\n .catch(function (error) {\r\n\r\n console.error('peerConnection.addIceCandidate', error);\r\n errorHandler(error);\r\n });\r\n }\r\n }\r\n }\r\n\r\n // instance methods\r\n instance.attachMedia = function (videoElement) {\r\n\r\n instance.videoElement = videoElement;\r\n };\r\n\r\n instance.getUserMedia = function (constraints) {\r\n\r\n return getUserMedia(constraints);\r\n };\r\n\r\n instance.getDisplayMedia = function (constraints) {\r\n\r\n return getDisplayMedia(constraints);\r\n };\r\n\r\n instance.startStreaming = function (connectionUrl, connectionConfig) {\r\n\r\n console.info(logEventHeader, 'Start Streaming');\r\n\r\n if (connectionConfig) {\r\n\r\n instance.connectionConfig = connectionConfig;\r\n }\r\n\r\n initWebSocket(connectionUrl);\r\n };\r\n\r\n instance.remove = function () {\r\n\r\n instance.removing = true;\r\n\r\n // first release peer connection with ome\r\n if (instance.peerConnection) {\r\n\r\n // remove tracks from peer connection\r\n instance.peerConnection.getSenders().forEach(function (sender) {\r\n instance.peerConnection.removeTrack(sender);\r\n });\r\n\r\n instance.peerConnection.close();\r\n instance.peerConnection = null;\r\n delete instance.peerConnection;\r\n }\r\n\r\n // release video, audio stream\r\n if (instance.stream) {\r\n\r\n instance.stream.getTracks().forEach(track => {\r\n\r\n track.stop();\r\n instance.stream.removeTrack(track);\r\n });\r\n\r\n if (instance.videoElement) {\r\n instance.videoElement.srcObject = null;\r\n }\r\n\r\n instance.stream = null;\r\n delete instance.stream;\r\n }\r\n\r\n // release websocket\r\n if (instance.webSocket) {\r\n\r\n instance.webSocket.close();\r\n instance.webSocket = null;\r\n delete instance.webSocket;\r\n }\r\n\r\n instance.status = 'removed';\r\n\r\n console.info(logEventHeader, 'Removed');\r\n\r\n };\r\n}\r\n\r\n// static methods\r\nOvenLiveKit.create = function (options) {\r\n\r\n console.info(logEventHeader, 'Create WebRTC Input v1.0.2');\r\n\r\n let instance = {};\r\n\r\n instance.removing = false;\r\n\r\n initConfig(instance, options);\r\n addMethod(instance);\r\n\r\n return instance;\r\n};\r\n\r\nOvenLiveKit.getDevices = async function () {\r\n\r\n try {\r\n // First check both audio and video sources are available.\r\n await getStreamForDeviceCheck('both');\r\n } catch (e) {\r\n\r\n console.warn(logHeader, 'Can not find Video and Audio devices', e);\r\n\r\n let videoFound = null;\r\n let audioFound = null;\r\n\r\n try {\r\n videoFound = await getStreamForDeviceCheck('video');\r\n } catch (e) {\r\n console.warn(logHeader, 'Can not find Video devices', e);\r\n }\r\n\r\n try {\r\n audioFound = await getStreamForDeviceCheck('audio');\r\n } catch (e) {\r\n console.warn(logHeader, 'Can not find Audio devices', e);\r\n }\r\n\r\n if (!videoFound && !audioFound) {\r\n throw new Error('No input devices were found.');\r\n }\r\n }\r\n\r\n const deviceInfos = await getDevices();\r\n return gotDevices(deviceInfos)\r\n};\r\n\r\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (OvenLiveKit);\n\n//# sourceURL=webpack://OvenLiveKit/./src/OvenLiveKit.js?");
29
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\nconst OvenLiveKit = {};\r\n\r\nconst version = '1.0.4';\r\nconst logHeader = 'OvenLiveKit.js :';\r\nconst logEventHeader = 'OvenLiveKit.js ====';\r\n\r\n// private methods\r\nfunction sendMessage(webSocket, message) {\r\n\r\n if (webSocket) {\r\n webSocket.send(JSON.stringify(message));\r\n }\r\n}\r\n\r\nfunction generateDomainFromUrl(url) {\r\n let result = '';\r\n let match;\r\n if (match = url.match(/^(?:wss?:\\/\\/)?(?:[^@\\n]+@)?(?:www\\.)?([^:\\/\\n\\?\\=]+)/im)) {\r\n result = match[1];\r\n }\r\n\r\n return result;\r\n}\r\n\r\nfunction findIp(string) {\r\n\r\n let result = '';\r\n let match;\r\n\r\n if (match = string.match(new RegExp('\\\\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\b', 'gi'))) {\r\n result = match[0];\r\n }\r\n\r\n return result;\r\n}\r\n\r\nfunction getFormatNumber(sdp, format) {\r\n\r\n const lines = sdp.split('\\r\\n');\r\n let formatNumber = -1;\r\n\r\n for (let i = 0; i < lines.length - 1; i++) {\r\n\r\n lines[i] = lines[i].toLowerCase();\r\n\r\n if (lines[i].indexOf('a=rtpmap') > -1 && lines[i].indexOf(format.toLowerCase()) > -1) {\r\n // parsing \"a=rtpmap:100 H264/90000\" line\r\n formatNumber = lines[i].split(' ')[0].split(':')[1];\r\n break;\r\n }\r\n }\r\n\r\n return formatNumber;\r\n}\r\n\r\nfunction removeFormat(sdp, formatNumber) {\r\n let newLines = [];\r\n let lines = sdp.split('\\r\\n');\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n\r\n if (lines[i].indexOf('m=video') === 0) {\r\n newLines.push(lines[i].replace(' ' + formatNumber + '', ''));\r\n } else if (lines[i].indexOf(formatNumber + '') > -1) {\r\n\r\n } else {\r\n newLines.push(lines[i]);\r\n }\r\n }\r\n\r\n return newLines.join('\\r\\n')\r\n}\r\n\r\nasync function getStreamForDeviceCheck(type) {\r\n\r\n // High resolution video constraints makes browser to get maximum resolution of video device.\r\n const constraints = {\r\n };\r\n\r\n if (type === 'both') {\r\n constraints.audio = true;\r\n constraints.video = true;\r\n } else if (type === 'audio') {\r\n constraints.audio = true;\r\n } else if (type === 'video') {\r\n constraints.video = true;\r\n }\r\n\r\n return await navigator.mediaDevices.getUserMedia(constraints);\r\n}\r\n\r\nasync function getDevices() {\r\n\r\n return await navigator.mediaDevices.enumerateDevices();\r\n}\r\n\r\nfunction gotDevices(deviceInfos) {\r\n\r\n let devices = {\r\n 'audioinput': [],\r\n 'audiooutput': [],\r\n 'videoinput': [],\r\n 'other': [],\r\n };\r\n\r\n for (let i = 0; i !== deviceInfos.length; ++i) {\r\n\r\n const deviceInfo = deviceInfos[i];\r\n\r\n let info = {};\r\n\r\n info.deviceId = deviceInfo.deviceId;\r\n\r\n if (deviceInfo.kind === 'audioinput') {\r\n\r\n info.label = deviceInfo.label || `microphone ${devices.audioinput.length + 1}`;\r\n devices.audioinput.push(info);\r\n } else if (deviceInfo.kind === 'audiooutput') {\r\n\r\n info.label = deviceInfo.label || `speaker ${devices.audiooutput.length + 1}`;\r\n devices.audiooutput.push(info);\r\n } else if (deviceInfo.kind === 'videoinput') {\r\n\r\n info.label = deviceInfo.label || `camera ${devices.videoinput.length + 1}`;\r\n devices.videoinput.push(info);\r\n } else {\r\n\r\n info.label = deviceInfo.label || `other ${devices.other.length + 1}`;\r\n devices.other.push(info);\r\n }\r\n }\r\n\r\n return devices;\r\n}\r\n\r\nfunction initConfig(instance, options) {\r\n\r\n instance.inputStream = null;\r\n instance.webSocket = null;\r\n instance.peerConnection = null;\r\n instance.connectionConfig = {};\r\n\r\n instance.videoElement = null;\r\n instance.connectionUrl = null;\r\n\r\n if (options && options.callbacks) {\r\n\r\n instance.callbacks = options.callbacks;\r\n } else {\r\n instance.callbacks = {};\r\n }\r\n}\r\n\r\nfunction addMethod(instance) {\r\n\r\n function errorHandler(error) {\r\n\r\n if (instance.callbacks.error) {\r\n\r\n instance.callbacks.error(error);\r\n }\r\n }\r\n\r\n function getUserMedia(constraints) {\r\n\r\n if (!constraints) {\r\n\r\n constraints = {\r\n video: {\r\n deviceId: undefined\r\n },\r\n audio: {\r\n deviceId: undefined\r\n }\r\n };\r\n }\r\n\r\n console.info(logHeader, 'Request Stream To Input Devices With Constraints', constraints);\r\n\r\n return navigator.mediaDevices.getUserMedia(constraints)\r\n .then(function (stream) {\r\n\r\n console.info(logHeader, 'Received Media Stream From Input Device', stream);\r\n\r\n instance.inputStream = stream;\r\n\r\n let elem = instance.videoElement;\r\n\r\n // Attach stream to video element when video element is provided.\r\n if (elem) {\r\n\r\n elem.srcObject = stream;\r\n\r\n elem.onloadedmetadata = function (e) {\r\n\r\n elem.play();\r\n };\r\n }\r\n\r\n return new Promise(function (resolve) {\r\n\r\n resolve(stream);\r\n });\r\n })\r\n .catch(function (error) {\r\n\r\n console.error(logHeader, 'Can\\'t Get Media Stream From Input Device', error);\r\n errorHandler(error);\r\n\r\n return new Promise(function (resolve, reject) {\r\n reject(error);\r\n });\r\n });\r\n }\r\n\r\n function getDisplayMedia(constraints) {\r\n\r\n if (!constraints) {\r\n constraints = {};\r\n }\r\n\r\n console.info(logHeader, 'Request Stream To Display With Constraints', constraints);\r\n\r\n return navigator.mediaDevices.getDisplayMedia(constraints)\r\n .then(function (stream) {\r\n\r\n console.info(logHeader, 'Received Media Stream From Display', stream);\r\n\r\n instance.inputStream = stream;\r\n\r\n let elem = instance.videoElement;\r\n\r\n // Attach stream to video element when video element is provided.\r\n if (elem) {\r\n\r\n elem.srcObject = stream;\r\n\r\n elem.onloadedmetadata = function (e) {\r\n\r\n elem.play();\r\n };\r\n }\r\n\r\n return new Promise(function (resolve) {\r\n\r\n resolve(stream);\r\n });\r\n })\r\n .catch(function (error) {\r\n\r\n console.error(logHeader, 'Can\\'t Get Media Stream From Display', error);\r\n errorHandler(error);\r\n\r\n return new Promise(function (resolve, reject) {\r\n reject(error);\r\n });\r\n });\r\n }\r\n\r\n // From https://webrtchacks.com/limit-webrtc-bandwidth-sdp/\r\n function setBitrateLimit(sdp, media, bitrate) {\r\n\r\n let lines = sdp.split('\\r\\n');\r\n let line = -1;\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n if (lines[i].indexOf('m=' + media) === 0) {\r\n line = i;\r\n break;\r\n }\r\n }\r\n if (line === -1) {\r\n // Could not find the m line for media\r\n return sdp;\r\n }\r\n\r\n // Pass the m line\r\n line++;\r\n\r\n // Skip i and c lines\r\n while (lines[line].indexOf('i=') === 0 || lines[line].indexOf('c=') === 0) {\r\n\r\n line++;\r\n }\r\n\r\n // If we're on a b line, replace it\r\n if (lines[line].indexOf('b') === 0) {\r\n\r\n lines[line] = 'b=AS:' + bitrate;\r\n\r\n return lines.join('\\r\\n');\r\n }\r\n\r\n // Add a new b line\r\n let newLines = lines.slice(0, line)\r\n\r\n newLines.push('b=AS:' + bitrate)\r\n newLines = newLines.concat(lines.slice(line, lines.length))\r\n\r\n return newLines.join('\\r\\n')\r\n }\r\n\r\n function initWebSocket(connectionUrl) {\r\n\r\n if (!connectionUrl) {\r\n errorHandler('connectionUrl is required');\r\n return;\r\n }\r\n\r\n instance.connectionUrl = connectionUrl;\r\n\r\n let webSocket = null;\r\n\r\n try {\r\n\r\n webSocket = new WebSocket(connectionUrl);\r\n } catch (error) {\r\n\r\n errorHandler(error);\r\n }\r\n\r\n\r\n instance.webSocket = webSocket;\r\n\r\n webSocket.onopen = function () {\r\n\r\n // Request offer at the first time.\r\n sendMessage(webSocket, {\r\n command: 'request_offer'\r\n });\r\n };\r\n\r\n webSocket.onmessage = function (e) {\r\n\r\n let message = JSON.parse(e.data);\r\n\r\n if (message.error) {\r\n console.error('webSocket.onmessage', message.error);\r\n errorHandler(message.error);\r\n }\r\n\r\n if (message.command === 'offer') {\r\n\r\n // OME returns offer. Start create peer connection.\r\n createPeerConnection(\r\n message.id,\r\n message.peer_id,\r\n message.sdp,\r\n message.candidates,\r\n message.ice_servers\r\n );\r\n }\r\n };\r\n\r\n webSocket.onerror = function (error) {\r\n\r\n console.error('webSocket.onerror', error);\r\n errorHandler(error);\r\n };\r\n\r\n webSocket.onclose = function (e) {\r\n\r\n if (!instance.webSocketClosedByUser) {\r\n\r\n if (instance.callbacks.connectionClosed) {\r\n instance.callbacks.connectionClosed('websocket', e);\r\n }\r\n }\r\n };\r\n\r\n }\r\n\r\n function appendFmtp(sdp) {\r\n\r\n const fmtpStr = instance.connectionConfig.sdp.appendFmtp;\r\n\r\n const lines = sdp.split('\\r\\n');\r\n const payloads = [];\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n\r\n if (lines[i].indexOf('m=video') === 0) {\r\n\r\n let tokens = lines[i].split(' ')\r\n\r\n for (let j = 3; j < tokens.length; j++) {\r\n\r\n payloads.push(tokens[j]);\r\n }\r\n\r\n break;\r\n }\r\n }\r\n\r\n for (let i = 0; i < payloads.length; i++) {\r\n\r\n let fmtpLineFound = false;\r\n\r\n for (let j = 0; j < lines.length; j++) {\r\n\r\n if (lines[j].indexOf('a=fmtp:' + payloads[i]) === 0) {\r\n fmtpLineFound = true;\r\n lines[j] += ';' + fmtpStr;\r\n }\r\n }\r\n\r\n if (!fmtpLineFound) {\r\n\r\n for (let j = 0; j < lines.length; j++) {\r\n\r\n if (lines[j].indexOf('a=rtpmap:' + payloads[i]) === 0) {\r\n\r\n lines[j] += '\\r\\na=fmtp:' + payloads[i] + ' ' + fmtpStr;\r\n }\r\n }\r\n }\r\n }\r\n\r\n return lines.join('\\r\\n')\r\n }\r\n\r\n function appendOrientation(sdp) {\r\n\r\n const lines = sdp.split('\\r\\n');\r\n const payloads = [];\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n\r\n if (lines[i].indexOf('m=video') === 0) {\r\n\r\n let tokens = lines[i].split(' ')\r\n\r\n for (let j = 3; j < tokens.length; j++) {\r\n\r\n payloads.push(tokens[j]);\r\n }\r\n\r\n break;\r\n }\r\n }\r\n\r\n for (let i = 0; i < payloads.length; i++) {\r\n\r\n for (let j = 0; j < lines.length; j++) {\r\n\r\n if (lines[j].indexOf('a=rtpmap:' + payloads[i]) === 0) {\r\n\r\n lines[j] += '\\r\\na=extmap:' + payloads[i] + ' urn:3gpp:video-orientation';\r\n }\r\n }\r\n }\r\n\r\n return lines.join('\\r\\n')\r\n }\r\n\r\n function createPeerConnection(id, peerId, offer, candidates, iceServers) {\r\n\r\n let peerConnectionConfig = {};\r\n\r\n if (instance.connectionConfig.iceServers) {\r\n\r\n // first priority using ice servers from local config.\r\n peerConnectionConfig.iceServers = instance.connectionConfig.iceServers;\r\n\r\n if (instance.connectionConfig.iceTransportPolicy) {\r\n\r\n peerConnectionConfig.iceTransportPolicy = instance.connectionConfig.iceTransportPolicy;\r\n }\r\n } else if (iceServers) {\r\n\r\n // second priority using ice servers from ome and force using TCP\r\n peerConnectionConfig.iceServers = [];\r\n\r\n for (let i = 0; i < iceServers.length; i++) {\r\n\r\n let iceServer = iceServers[i];\r\n\r\n let regIceServer = {};\r\n\r\n regIceServer.urls = iceServer.urls;\r\n\r\n let hasWebSocketUrl = false;\r\n let webSocketUrl = generateDomainFromUrl(instance.connectionUrl);\r\n\r\n for (let j = 0; j < regIceServer.urls.length; j++) {\r\n\r\n let serverUrl = regIceServer.urls[j];\r\n\r\n if (serverUrl.indexOf(webSocketUrl) > -1) {\r\n hasWebSocketUrl = true;\r\n break;\r\n }\r\n }\r\n\r\n if (!hasWebSocketUrl) {\r\n\r\n if (regIceServer.urls.length > 0) {\r\n\r\n let cloneIceServer = regIceServer.urls[0];\r\n let ip = findIp(cloneIceServer);\r\n\r\n if (webSocketUrl && ip) {\r\n regIceServer.urls.push(cloneIceServer.replace(ip, webSocketUrl));\r\n }\r\n }\r\n }\r\n\r\n regIceServer.username = iceServer.user_name;\r\n regIceServer.credential = iceServer.credential;\r\n\r\n peerConnectionConfig.iceServers.push(regIceServer);\r\n }\r\n\r\n peerConnectionConfig.iceTransportPolicy = 'relay';\r\n } else {\r\n // last priority using default ice servers.\r\n\r\n if (instance.iceTransportPolicy) {\r\n\r\n peerConnectionConfig.iceTransportPolicy = instance.iceTransportPolicy;\r\n }\r\n }\r\n\r\n let advancedSetting = {\r\n optional: [\r\n {\r\n googHighStartBitrate: {\r\n exact: !0\r\n }\r\n },\r\n {\r\n googPayloadPadding: {\r\n exact: !0\r\n }\r\n },\r\n {\r\n googScreencastMinBitrate: {\r\n exact: 500\r\n }\r\n },\r\n {\r\n enableDscp: {\r\n exact: true\r\n }\r\n }\r\n ]\r\n };\r\n\r\n console.info(logHeader, 'Create Peer Connection With Config', peerConnectionConfig);\r\n\r\n let peerConnection = new RTCPeerConnection(peerConnectionConfig);\r\n\r\n instance.peerConnection = peerConnection;\r\n\r\n // set local stream\r\n instance.inputStream.getTracks().forEach(function (track) {\r\n\r\n console.info(logHeader, 'Add Track To Peer Connection', track);\r\n peerConnection.addTrack(track, instance.inputStream);\r\n });\r\n\r\n if (instance.connectionConfig.maxVideoBitrate) {\r\n\r\n // if bandwith limit is set. modify sdp from ome to limit acceptable bandwidth of ome\r\n offer.sdp = setBitrateLimit(offer.sdp, 'video', instance.connectionConfig.maxVideoBitrate);\r\n }\r\n\r\n if (instance.connectionConfig.sdp && instance.connectionConfig.sdp.appendFmtp) {\r\n\r\n offer.sdp = appendFmtp(offer.sdp);\r\n }\r\n\r\n // offer.sdp = appendOrientation(offer.sdp);\r\n\r\n peerConnection.setRemoteDescription(new RTCSessionDescription(offer))\r\n .then(function () {\r\n\r\n peerConnection.createAnswer()\r\n .then(function (answer) {\r\n\r\n if (instance.connectionConfig.sdp && instance.connectionConfig.sdp.appendFmtp) {\r\n\r\n answer.sdp = appendFmtp(answer.sdp);\r\n }\r\n\r\n peerConnection.setLocalDescription(answer)\r\n .then(function () {\r\n\r\n sendMessage(instance.webSocket, {\r\n id: id,\r\n peer_id: peerId,\r\n command: 'answer',\r\n sdp: answer\r\n });\r\n })\r\n .catch(function (error) {\r\n\r\n console.error('peerConnection.setLocalDescription', error);\r\n errorHandler(error);\r\n });\r\n })\r\n .catch(function (error) {\r\n\r\n console.error('peerConnection.createAnswer', error);\r\n errorHandler(error);\r\n });\r\n })\r\n .catch(function (error) {\r\n\r\n console.error('peerConnection.setRemoteDescription', error);\r\n errorHandler(error);\r\n });\r\n\r\n if (candidates) {\r\n\r\n addIceCandidate(peerConnection, candidates);\r\n }\r\n\r\n peerConnection.onicecandidate = function (e) {\r\n\r\n if (e.candidate && e.candidate.candidate) {\r\n\r\n sendMessage(instance.webSocket, {\r\n id: id,\r\n peer_id: peerId,\r\n command: 'candidate',\r\n candidates: [e.candidate]\r\n });\r\n }\r\n };\r\n\r\n peerConnection.oniceconnectionstatechange = function (e) {\r\n\r\n let state = peerConnection.iceConnectionState;\r\n\r\n if (instance.callbacks.iceStateChange) {\r\n\r\n console.info(logHeader, 'ICE State', '[' + state + ']');\r\n instance.callbacks.iceStateChange(state);\r\n }\r\n\r\n if (state === 'connected') {\r\n\r\n if (instance.callbacks.connected) {\r\n instance.callbacks.connected(e);\r\n }\r\n }\r\n\r\n if (state === 'failed' || state === 'disconnected' || state === 'closed') {\r\n\r\n if (instance.callbacks.connectionClosed) {\r\n console.error(logHeader, 'Iceconnection Closed', e);\r\n instance.callbacks.connectionClosed('ice', e);\r\n }\r\n }\r\n }\r\n }\r\n\r\n function addIceCandidate(peerConnection, candidates) {\r\n\r\n for (let i = 0; i < candidates.length; i++) {\r\n\r\n if (candidates[i] && candidates[i].candidate) {\r\n\r\n let basicCandidate = candidates[i];\r\n\r\n peerConnection.addIceCandidate(new RTCIceCandidate(basicCandidate))\r\n .then(function () {\r\n\r\n })\r\n .catch(function (error) {\r\n\r\n console.error('peerConnection.addIceCandidate', error);\r\n errorHandler(error);\r\n });\r\n }\r\n }\r\n }\r\n\r\n function closePeerConnection() {\r\n if (instance.peerConnection) {\r\n\r\n // remove tracks from peer connection\r\n instance.peerConnection.getSenders().forEach(function (sender) {\r\n instance.peerConnection.removeTrack(sender);\r\n });\r\n\r\n instance.peerConnection.close();\r\n instance.peerConnection = null;\r\n delete instance.peerConnection;\r\n }\r\n }\r\n\r\n function closeWebSocket() {\r\n\r\n if (instance.webSocket) {\r\n\r\n instance.webSocket.close();\r\n instance.webSocket = null;\r\n delete instance.webSocket;\r\n }\r\n }\r\n\r\n function closeInputStream() {\r\n // release video, audio stream\r\n if (instance.inputStream) {\r\n\r\n instance.inputStream.getTracks().forEach(track => {\r\n\r\n track.stop();\r\n instance.inputStream.removeTrack(track);\r\n });\r\n\r\n if (instance.videoElement) {\r\n instance.videoElement.srcObject = null;\r\n }\r\n\r\n instance.inputStream = null;\r\n delete instance.inputStream;\r\n }\r\n }\r\n\r\n // instance methods\r\n instance.attachMedia = function (videoElement) {\r\n\r\n instance.videoElement = videoElement;\r\n };\r\n\r\n instance.getUserMedia = function (constraints) {\r\n\r\n return getUserMedia(constraints);\r\n };\r\n\r\n instance.getDisplayMedia = function (constraints) {\r\n\r\n return getDisplayMedia(constraints);\r\n };\r\n\r\n instance.startStreaming = function (connectionUrl, connectionConfig) {\r\n\r\n console.info(logEventHeader, 'Start Streaming');\r\n\r\n if (connectionConfig) {\r\n\r\n instance.connectionConfig = connectionConfig;\r\n }\r\n\r\n initWebSocket(connectionUrl);\r\n };\r\n\r\n instance.stopStreaming = function () {\r\n\r\n instance.webSocketClosedByUser = true;\r\n\r\n closeWebSocket();\r\n closePeerConnection();\r\n };\r\n\r\n instance.remove = function () {\r\n\r\n instance.webSocketClosedByUser = true;\r\n\r\n closeWebSocket();\r\n closePeerConnection();\r\n closeInputStream();\r\n\r\n console.info(logEventHeader, 'Removed');\r\n\r\n };\r\n}\r\n\r\nOvenLiveKit.getVersion = function () {\r\n return version;\r\n}\r\n\r\n// static methods\r\nOvenLiveKit.create = function (options) {\r\n\r\n console.info(logEventHeader, 'Create WebRTC Input ' + version);\r\n\r\n let instance = {};\r\n\r\n instance.webSocketClosedByUser = false;\r\n\r\n initConfig(instance, options);\r\n addMethod(instance);\r\n\r\n return instance;\r\n};\r\n\r\nOvenLiveKit.getDevices = async function () {\r\n\r\n try {\r\n // First check both audio and video sources are available.\r\n await getStreamForDeviceCheck('both');\r\n } catch (e) {\r\n\r\n console.warn(logHeader, 'Can not find Video and Audio devices', e);\r\n\r\n let videoFound = null;\r\n let audioFound = null;\r\n\r\n try {\r\n videoFound = await getStreamForDeviceCheck('video');\r\n } catch (e) {\r\n console.warn(logHeader, 'Can not find Video devices', e);\r\n }\r\n\r\n try {\r\n audioFound = await getStreamForDeviceCheck('audio');\r\n } catch (e) {\r\n console.warn(logHeader, 'Can not find Audio devices', e);\r\n }\r\n\r\n if (!videoFound && !audioFound) {\r\n throw new Error('No input devices were found.');\r\n }\r\n }\r\n\r\n const deviceInfos = await getDevices();\r\n return gotDevices(deviceInfos)\r\n};\r\n\r\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (OvenLiveKit);\n\n//# sourceURL=webpack://OvenLiveKit/./src/OvenLiveKit.js?");
30
30
 
31
31
  /***/ })
32
32
 
@@ -1,2 +1,2 @@
1
- !function(e,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.OvenLiveKit=n():e.OvenLiveKit=n()}(self,(function(){return(()=>{"use strict";var e={d:(n,o)=>{for(var t in o)e.o(o,t)&&!e.o(n,t)&&Object.defineProperty(n,t,{enumerable:!0,get:o[t]})},o:(e,n)=>Object.prototype.hasOwnProperty.call(e,n)},n={};e.d(n,{default:()=>p});const o={},t="OvenLiveKit.js :",i="OvenLiveKit.js ====";function c(e,n){e&&e.send(JSON.stringify(n))}function r(e){let n,o="";return(n=e.match(/^(?:wss?:\/\/)?(?:[^@\n]+@)?(?:www\.)?([^:\/\n\?\=]+)/im))&&(o=n[1]),o}function a(e){let n,o="";return(n=e.match(new RegExp("\\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b","gi")))&&(o=n[0]),o}function l(){var e=window.navigator.userAgent,n=e.indexOf("OS ");return(e.indexOf("iPhone")>-1||e.indexOf("iPad")>-1)&&n>-1?window.Number(e.substr(n+3,3).replace("_",".")):0}function s(e,n){const o=e.split("\r\n");let t=-1;for(let e=0;e<o.length-1;e++)if(o[e]=o[e].toLowerCase(),o[e].indexOf("a=rtpmap")>-1&&o[e].indexOf(n.toLowerCase())>-1){t=o[e].split(" ")[0].split(":")[1];break}return t}function d(e,n){let o=[],t=e.split("\r\n");for(let e=0;e<t.length;e++)0===t[e].indexOf("m=video")?o.push(t[e].replace(" "+n,"")):t[e].indexOf(n+"")>-1||o.push(t[e]);return o.join("\r\n")}async function u(e){const n={};return"both"===e?(n.audio=!0,n.video=!0):"audio"===e?n.audio=!0:"video"===e&&(n.video=!0),await navigator.mediaDevices.getUserMedia(n)}function f(e){function n(n){e.callbacks.error&&e.callbacks.error(n)}function o(n){const o=e.connectionConfig.sdp.appendFmtp,t=n.split("\r\n"),i=[];for(let e=0;e<t.length;e++)if(0===t[e].indexOf("m=video")){let n=t[e].split(" ");for(let e=3;e<n.length;e++)i.push(n[e]);break}for(let e=0;e<i.length;e++){let n=!1;for(let c=0;c<t.length;c++)0===t[c].indexOf("a=fmtp:"+i[e])&&(n=!0,t[c]+=";"+o);if(!n)for(let n=0;n<t.length;n++)0===t[n].indexOf("a=rtpmap:"+i[e])&&(t[n]+="\r\na=fmtp:"+i[e]+" "+o)}return t.join("\r\n")}e.attachMedia=function(n){e.videoElement=n},e.getUserMedia=function(o){return function(o){return o||(o={video:{deviceId:void 0},audio:{deviceId:void 0}}),console.info(t,"Requested Constraint To Input Devices",o),navigator.mediaDevices.getUserMedia(o).then((function(n){console.info(t,"Received Media Stream From Input Device",n),e.stream=n;let o=e.videoElement;return o&&(o.srcObject=n,o.onloadedmetadata=function(e){o.play()}),new Promise((function(e){e(n)}))})).catch((function(e){return console.error(t,"Can't Get Media Stream From Input Device",e),n(e),new Promise((function(n,o){o(e)}))}))}(o)},e.getDisplayMedia=function(o){return function(o){return o||(o={}),console.info(t,"Requested Constraint To Display",o),navigator.mediaDevices.getDisplayMedia(o).then((function(n){console.info(t,"Received Media Stream From Display",n),e.stream=n;let o=e.videoElement;return o&&(o.srcObject=n,o.onloadedmetadata=function(e){o.play()}),new Promise((function(e){e(n)}))})).catch((function(e){return console.error(t,"Can't Get Media Stream From Display",e),n(e),new Promise((function(n,o){o(e)}))}))}(o)},e.startStreaming=function(u,f){console.info(i,"Start Streaming"),f&&(e.connectionConfig=f),function(i){if(!i)return void n("connectionUrl is required");e.connectionUrl=i;let u=null;try{u=new WebSocket(i)}catch(e){n(e)}e.webSocket=u,u.onopen=function(){c(u,{command:"request_offer"})},u.onmessage=function(i){let u=JSON.parse(i.data);u.error&&(console.error("webSocket.onmessage",u.error),n(u.error)),"offer"===u.command&&function(i,u,f,p,m){let v={};if(e.connectionConfig.iceServers)v.iceServers=e.connectionConfig.iceServers,e.connectionConfig.iceTransportPolicy&&(v.iceTransportPolicy=e.connectionConfig.iceTransportPolicy);else if(m){v.iceServers=[];for(let n=0;n<m.length;n++){let o=m[n],t={};t.urls=o.urls;let i=!1,c=r(e.connectionUrl);for(let e=0;e<t.urls.length;e++)if(t.urls[e].indexOf(c)>-1){i=!0;break}if(!i&&t.urls.length>0){let e=t.urls[0],n=a(e);c&&n&&t.urls.push(e.replace(n,c))}t.username=o.user_name,t.credential=o.credential,v.iceServers.push(t)}v.iceTransportPolicy="relay"}else e.iceTransportPolicy&&(v.iceTransportPolicy=e.iceTransportPolicy);console.info(t,"Create Peer Connection With Config",v);let h=new RTCPeerConnection(v);if(e.peerConnection=h,e.stream.getTracks().forEach((function(n){console.info(t,"Add Track To Peer Connection",n),h.addTrack(n,e.stream)})),l()>=15){const e=s(f.sdp,"H264");e>0&&(f.sdp=d(f.sdp,e))}e.connectionConfig.maxVideoBitrate&&(f.sdp=function(e,n,o){let t=e.split("\r\n"),i=-1;for(let e=0;e<t.length;e++)if(0===t[e].indexOf("m=video")){i=e;break}if(-1===i)return e;for(i++;0===t[i].indexOf("i=")||0===t[i].indexOf("c=");)i++;if(0===t[i].indexOf("b"))return t[i]="b=AS:"+o,t.join("\r\n");let c=t.slice(0,i);return c.push("b=AS:"+o),c=c.concat(t.slice(i,t.length)),c.join("\r\n")}(f.sdp,0,e.connectionConfig.maxVideoBitrate)),e.connectionConfig.sdp&&e.connectionConfig.sdp.appendFmtp&&(f.sdp=o(f.sdp)),h.setRemoteDescription(new RTCSessionDescription(f)).then((function(){h.createAnswer().then((function(t){if(l()>=15){const e=s(t.sdp,"H264");e>0&&(t.sdp=d(t.sdp,e))}e.connectionConfig.sdp&&e.connectionConfig.sdp.appendFmtp&&(t.sdp=o(t.sdp)),h.setLocalDescription(t).then((function(){c(e.webSocket,{id:i,peer_id:u,command:"answer",sdp:t})})).catch((function(e){console.error("peerConnection.setLocalDescription",e),n(e)}))})).catch((function(e){console.error("peerConnection.createAnswer",e),n(e)}))})).catch((function(e){console.error("peerConnection.setRemoteDescription",e),n(e)})),p&&function(e,o){for(let t=0;t<o.length;t++)if(o[t]&&o[t].candidate){let i=o[t];e.addIceCandidate(new RTCIceCandidate(i)).then((function(){})).catch((function(e){console.error("peerConnection.addIceCandidate",e),n(e)}))}}(h,p),h.onicecandidate=function(n){n.candidate&&n.candidate.candidate&&(console.info(t,"Candidate Sent","\n",n.candidate.candidate,"\n",n),c(e.webSocket,{id:i,peer_id:u,command:"candidate",candidates:[n.candidate]}))},h.oniceconnectionstatechange=function(n){let o=h.iceConnectionState;e.callbacks.iceStateChange&&(console.info(t,"ICE State","["+o+"]"),e.callbacks.iceStateChange(o)),"connected"===o&&e.callbacks.connected&&(console.info(t,"Iceconnection Connected",n),e.callbacks.connected(n)),"failed"!==o&&"disconnected"!==o&&"closed"!==o||e.callbacks.connectionClosed&&(console.error(t,"Iceconnection Closed",n),e.callbacks.connectionClosed("ice",n))}}(u.id,u.peer_id,u.sdp,u.candidates,u.ice_servers)},u.onerror=function(e){console.error("webSocket.onerror",e),n(e)},u.onclose=function(n){e.removing||e.callbacks.connectionClosed&&e.callbacks.connectionClosed("websocket",n)}}(u)},e.remove=function(){e.removing=!0,e.peerConnection&&(e.peerConnection.getSenders().forEach((function(n){e.peerConnection.removeTrack(n)})),e.peerConnection.close(),e.peerConnection=null,delete e.peerConnection),e.stream&&(e.stream.getTracks().forEach((n=>{n.stop(),e.stream.removeTrack(n)})),e.videoElement&&(e.videoElement.srcObject=null),e.stream=null,delete e.stream),e.webSocket&&(e.webSocket.close(),e.webSocket=null,delete e.webSocket),e.status="removed",console.info(i,"Removed")}}o.create=function(e){console.info(i,"Create WebRTC Input v1.0.2");let n={removing:!1};return function(e,n){e.stream=null,e.webSocket=null,e.peerConnection=null,e.connectionConfig={},e.status="creating",e.videoElement=null,e.connectionUrl=null,n&&n.callbacks?e.callbacks=n.callbacks:e.callbacks={}}(n,e),f(n),n},o.getDevices=async function(){try{await u("both")}catch(e){console.warn(t,"Can not find Video and Audio devices",e);let n=null,o=null;try{n=await u("video")}catch(e){console.warn(t,"Can not find Video devices",e)}try{o=await u("audio")}catch(e){console.warn(t,"Can not find Audio devices",e)}if(!n&&!o)throw new Error("No input devices were found.")}return function(e){let n={audioinput:[],audiooutput:[],videoinput:[],other:[]};for(let o=0;o!==e.length;++o){const t=e[o];let i={};i.deviceId=t.deviceId,"audioinput"===t.kind?(i.label=t.label||`microphone ${n.audioinput.length+1}`,n.audioinput.push(i)):"audiooutput"===t.kind?(i.label=t.label||`speaker ${n.audiooutput.length+1}`,n.audiooutput.push(i)):"videoinput"===t.kind?(i.label=t.label||`camera ${n.videoinput.length+1}`,n.videoinput.push(i)):(i.label=t.label||`other ${n.other.length+1}`,n.other.push(i))}return n}(await async function(){return await navigator.mediaDevices.enumerateDevices()}())};const p=o;return n.default})()}));
1
+ !function(e,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.OvenLiveKit=n():e.OvenLiveKit=n()}(self,(function(){return(()=>{"use strict";var e={d:(n,o)=>{for(var t in o)e.o(o,t)&&!e.o(n,t)&&Object.defineProperty(n,t,{enumerable:!0,get:o[t]})},o:(e,n)=>Object.prototype.hasOwnProperty.call(e,n)},n={};e.d(n,{default:()=>d});const o={},t="OvenLiveKit.js :",i="OvenLiveKit.js ====";function c(e,n){e&&e.send(JSON.stringify(n))}function r(e){let n,o="";return(n=e.match(/^(?:wss?:\/\/)?(?:[^@\n]+@)?(?:www\.)?([^:\/\n\?\=]+)/im))&&(o=n[1]),o}function a(e){let n,o="";return(n=e.match(new RegExp("\\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b","gi")))&&(o=n[0]),o}async function l(e){const n={};return"both"===e?(n.audio=!0,n.video=!0):"audio"===e?n.audio=!0:"video"===e&&(n.video=!0),await navigator.mediaDevices.getUserMedia(n)}function s(e){function n(n){e.callbacks.error&&e.callbacks.error(n)}function o(n){const o=e.connectionConfig.sdp.appendFmtp,t=n.split("\r\n"),i=[];for(let e=0;e<t.length;e++)if(0===t[e].indexOf("m=video")){let n=t[e].split(" ");for(let e=3;e<n.length;e++)i.push(n[e]);break}for(let e=0;e<i.length;e++){let n=!1;for(let c=0;c<t.length;c++)0===t[c].indexOf("a=fmtp:"+i[e])&&(n=!0,t[c]+=";"+o);if(!n)for(let n=0;n<t.length;n++)0===t[n].indexOf("a=rtpmap:"+i[e])&&(t[n]+="\r\na=fmtp:"+i[e]+" "+o)}return t.join("\r\n")}function l(){e.peerConnection&&(e.peerConnection.getSenders().forEach((function(n){e.peerConnection.removeTrack(n)})),e.peerConnection.close(),e.peerConnection=null,delete e.peerConnection)}function s(){e.webSocket&&(e.webSocket.close(),e.webSocket=null,delete e.webSocket)}e.attachMedia=function(n){e.videoElement=n},e.getUserMedia=function(o){return function(o){return o||(o={video:{deviceId:void 0},audio:{deviceId:void 0}}),console.info(t,"Request Stream To Input Devices With Constraints",o),navigator.mediaDevices.getUserMedia(o).then((function(n){console.info(t,"Received Media Stream From Input Device",n),e.inputStream=n;let o=e.videoElement;return o&&(o.srcObject=n,o.onloadedmetadata=function(e){o.play()}),new Promise((function(e){e(n)}))})).catch((function(e){return console.error(t,"Can't Get Media Stream From Input Device",e),n(e),new Promise((function(n,o){o(e)}))}))}(o)},e.getDisplayMedia=function(o){return function(o){return o||(o={}),console.info(t,"Request Stream To Display With Constraints",o),navigator.mediaDevices.getDisplayMedia(o).then((function(n){console.info(t,"Received Media Stream From Display",n),e.inputStream=n;let o=e.videoElement;return o&&(o.srcObject=n,o.onloadedmetadata=function(e){o.play()}),new Promise((function(e){e(n)}))})).catch((function(e){return console.error(t,"Can't Get Media Stream From Display",e),n(e),new Promise((function(n,o){o(e)}))}))}(o)},e.startStreaming=function(l,s){console.info(i,"Start Streaming"),s&&(e.connectionConfig=s),function(i){if(!i)return void n("connectionUrl is required");e.connectionUrl=i;let l=null;try{l=new WebSocket(i)}catch(e){n(e)}e.webSocket=l,l.onopen=function(){c(l,{command:"request_offer"})},l.onmessage=function(i){let l=JSON.parse(i.data);l.error&&(console.error("webSocket.onmessage",l.error),n(l.error)),"offer"===l.command&&function(i,l,s,d,u){let f={};if(e.connectionConfig.iceServers)f.iceServers=e.connectionConfig.iceServers,e.connectionConfig.iceTransportPolicy&&(f.iceTransportPolicy=e.connectionConfig.iceTransportPolicy);else if(u){f.iceServers=[];for(let n=0;n<u.length;n++){let o=u[n],t={};t.urls=o.urls;let i=!1,c=r(e.connectionUrl);for(let e=0;e<t.urls.length;e++)if(t.urls[e].indexOf(c)>-1){i=!0;break}if(!i&&t.urls.length>0){let e=t.urls[0],n=a(e);c&&n&&t.urls.push(e.replace(n,c))}t.username=o.user_name,t.credential=o.credential,f.iceServers.push(t)}f.iceTransportPolicy="relay"}else e.iceTransportPolicy&&(f.iceTransportPolicy=e.iceTransportPolicy);console.info(t,"Create Peer Connection With Config",f);let p=new RTCPeerConnection(f);e.peerConnection=p,e.inputStream.getTracks().forEach((function(n){console.info(t,"Add Track To Peer Connection",n),p.addTrack(n,e.inputStream)})),e.connectionConfig.maxVideoBitrate&&(s.sdp=function(e,n,o){let t=e.split("\r\n"),i=-1;for(let e=0;e<t.length;e++)if(0===t[e].indexOf("m=video")){i=e;break}if(-1===i)return e;for(i++;0===t[i].indexOf("i=")||0===t[i].indexOf("c=");)i++;if(0===t[i].indexOf("b"))return t[i]="b=AS:"+o,t.join("\r\n");let c=t.slice(0,i);return c.push("b=AS:"+o),c=c.concat(t.slice(i,t.length)),c.join("\r\n")}(s.sdp,0,e.connectionConfig.maxVideoBitrate)),e.connectionConfig.sdp&&e.connectionConfig.sdp.appendFmtp&&(s.sdp=o(s.sdp)),p.setRemoteDescription(new RTCSessionDescription(s)).then((function(){p.createAnswer().then((function(t){e.connectionConfig.sdp&&e.connectionConfig.sdp.appendFmtp&&(t.sdp=o(t.sdp)),p.setLocalDescription(t).then((function(){c(e.webSocket,{id:i,peer_id:l,command:"answer",sdp:t})})).catch((function(e){console.error("peerConnection.setLocalDescription",e),n(e)}))})).catch((function(e){console.error("peerConnection.createAnswer",e),n(e)}))})).catch((function(e){console.error("peerConnection.setRemoteDescription",e),n(e)})),d&&function(e,o){for(let t=0;t<o.length;t++)if(o[t]&&o[t].candidate){let i=o[t];e.addIceCandidate(new RTCIceCandidate(i)).then((function(){})).catch((function(e){console.error("peerConnection.addIceCandidate",e),n(e)}))}}(p,d),p.onicecandidate=function(n){n.candidate&&n.candidate.candidate&&c(e.webSocket,{id:i,peer_id:l,command:"candidate",candidates:[n.candidate]})},p.oniceconnectionstatechange=function(n){let o=p.iceConnectionState;e.callbacks.iceStateChange&&(console.info(t,"ICE State","["+o+"]"),e.callbacks.iceStateChange(o)),"connected"===o&&e.callbacks.connected&&e.callbacks.connected(n),"failed"!==o&&"disconnected"!==o&&"closed"!==o||e.callbacks.connectionClosed&&(console.error(t,"Iceconnection Closed",n),e.callbacks.connectionClosed("ice",n))}}(l.id,l.peer_id,l.sdp,l.candidates,l.ice_servers)},l.onerror=function(e){console.error("webSocket.onerror",e),n(e)},l.onclose=function(n){e.webSocketClosedByUser||e.callbacks.connectionClosed&&e.callbacks.connectionClosed("websocket",n)}}(l)},e.stopStreaming=function(){e.webSocketClosedByUser=!0,s(),l()},e.remove=function(){e.webSocketClosedByUser=!0,s(),l(),e.inputStream&&(e.inputStream.getTracks().forEach((n=>{n.stop(),e.inputStream.removeTrack(n)})),e.videoElement&&(e.videoElement.srcObject=null),e.inputStream=null,delete e.inputStream),console.info(i,"Removed")}}o.getVersion=function(){return"1.0.4"},o.create=function(e){console.info(i,"Create WebRTC Input 1.0.4");let n={webSocketClosedByUser:!1};return function(e,n){e.inputStream=null,e.webSocket=null,e.peerConnection=null,e.connectionConfig={},e.videoElement=null,e.connectionUrl=null,n&&n.callbacks?e.callbacks=n.callbacks:e.callbacks={}}(n,e),s(n),n},o.getDevices=async function(){try{await l("both")}catch(e){console.warn(t,"Can not find Video and Audio devices",e);let n=null,o=null;try{n=await l("video")}catch(e){console.warn(t,"Can not find Video devices",e)}try{o=await l("audio")}catch(e){console.warn(t,"Can not find Audio devices",e)}if(!n&&!o)throw new Error("No input devices were found.")}return function(e){let n={audioinput:[],audiooutput:[],videoinput:[],other:[]};for(let o=0;o!==e.length;++o){const t=e[o];let i={};i.deviceId=t.deviceId,"audioinput"===t.kind?(i.label=t.label||`microphone ${n.audioinput.length+1}`,n.audioinput.push(i)):"audiooutput"===t.kind?(i.label=t.label||`speaker ${n.audiooutput.length+1}`,n.audiooutput.push(i)):"videoinput"===t.kind?(i.label=t.label||`camera ${n.videoinput.length+1}`,n.videoinput.push(i)):(i.label=t.label||`other ${n.other.length+1}`,n.other.push(i))}return n}(await async function(){return await navigator.mediaDevices.enumerateDevices()}())};const d=o;return n.default})()}));
2
2
  //# sourceMappingURL=OvenLiveKit.min.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"OvenLiveKit.min.js","mappings":"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","sources":["webpack://OvenLiveKit/webpack/universalModuleDefinition","webpack://OvenLiveKit/webpack/bootstrap","webpack://OvenLiveKit/webpack/runtime/define property getters","webpack://OvenLiveKit/webpack/runtime/hasOwnProperty shorthand","webpack://OvenLiveKit/./src/OvenLiveKit.js"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"OvenLiveKit\"] = factory();\n\telse\n\t\troot[\"OvenLiveKit\"] = factory();\n})(self, function() {\nreturn ","// The require scope\nvar __webpack_require__ = {};\n\n","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","const OvenLiveKit = {};\r\n\r\nconst logHeader = 'OvenLiveKit.js :';\r\nconst logEventHeader = 'OvenLiveKit.js ====';\r\n\r\n// private methods\r\nfunction sendMessage(webSocket, message) {\r\n\r\n if (webSocket) {\r\n webSocket.send(JSON.stringify(message));\r\n }\r\n}\r\n\r\nfunction generateDomainFromUrl(url) {\r\n let result = '';\r\n let match;\r\n if (match = url.match(/^(?:wss?:\\/\\/)?(?:[^@\\n]+@)?(?:www\\.)?([^:\\/\\n\\?\\=]+)/im)) {\r\n result = match[1];\r\n }\r\n\r\n return result;\r\n}\r\n\r\nfunction findIp(string) {\r\n\r\n let result = '';\r\n let match;\r\n\r\n if (match = string.match(new RegExp('\\\\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\b', 'gi'))) {\r\n result = match[0];\r\n }\r\n\r\n return result;\r\n}\r\n\r\nfunction checkIOSVersion() {\r\n var agent = window.navigator.userAgent,\r\n start = agent.indexOf('OS ');\r\n if ((agent.indexOf('iPhone') > -1 || agent.indexOf('iPad') > -1) && start > -1) {\r\n return window.Number(agent.substr(start + 3, 3).replace('_', '.'));\r\n }\r\n return 0;\r\n}\r\n\r\nfunction getFormatNumber(sdp, format) {\r\n\r\n const lines = sdp.split('\\r\\n');\r\n let formatNumber = -1;\r\n\r\n for (let i = 0; i < lines.length - 1; i++) {\r\n\r\n lines[i] = lines[i].toLowerCase();\r\n\r\n if (lines[i].indexOf('a=rtpmap') > -1 && lines[i].indexOf(format.toLowerCase()) > -1) {\r\n // parsing \"a=rtpmap:100 H264/90000\" line\r\n formatNumber = lines[i].split(' ')[0].split(':')[1];\r\n break;\r\n }\r\n }\r\n\r\n return formatNumber;\r\n}\r\n\r\nfunction removeFormat(sdp, formatNumber) {\r\n let newLines = [];\r\n let lines = sdp.split('\\r\\n');\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n\r\n if (lines[i].indexOf('m=video') === 0) {\r\n newLines.push(lines[i].replace(' ' + formatNumber + '', ''));\r\n } else if (lines[i].indexOf(formatNumber + '') > -1) {\r\n\r\n } else {\r\n newLines.push(lines[i]);\r\n }\r\n }\r\n\r\n return newLines.join('\\r\\n')\r\n}\r\n\r\nasync function getStreamForDeviceCheck(type) {\r\n\r\n // High resolution video constraints makes browser to get maximum resolution of video device.\r\n const constraints = {\r\n };\r\n\r\n if (type === 'both') {\r\n constraints.audio = true;\r\n constraints.video = true;\r\n } else if (type === 'audio') {\r\n constraints.audio = true;\r\n } else if (type === 'video') {\r\n constraints.video = true;\r\n }\r\n\r\n return await navigator.mediaDevices.getUserMedia(constraints);\r\n}\r\n\r\nasync function getDevices() {\r\n\r\n return await navigator.mediaDevices.enumerateDevices();\r\n}\r\n\r\nfunction gotDevices(deviceInfos) {\r\n\r\n let devices = {\r\n 'audioinput': [],\r\n 'audiooutput': [],\r\n 'videoinput': [],\r\n 'other': [],\r\n };\r\n\r\n for (let i = 0; i !== deviceInfos.length; ++i) {\r\n\r\n const deviceInfo = deviceInfos[i];\r\n\r\n let info = {};\r\n\r\n info.deviceId = deviceInfo.deviceId;\r\n\r\n if (deviceInfo.kind === 'audioinput') {\r\n\r\n info.label = deviceInfo.label || `microphone ${devices.audioinput.length + 1}`;\r\n devices.audioinput.push(info);\r\n } else if (deviceInfo.kind === 'audiooutput') {\r\n\r\n info.label = deviceInfo.label || `speaker ${devices.audiooutput.length + 1}`;\r\n devices.audiooutput.push(info);\r\n } else if (deviceInfo.kind === 'videoinput') {\r\n\r\n info.label = deviceInfo.label || `camera ${devices.videoinput.length + 1}`;\r\n devices.videoinput.push(info);\r\n } else {\r\n\r\n info.label = deviceInfo.label || `other ${devices.other.length + 1}`;\r\n devices.other.push(info);\r\n }\r\n }\r\n\r\n return devices;\r\n}\r\n\r\nfunction initConfig(instance, options) {\r\n\r\n instance.stream = null;\r\n instance.webSocket = null;\r\n instance.peerConnection = null;\r\n instance.connectionConfig = {};\r\n\r\n instance.status = 'creating';\r\n\r\n instance.videoElement = null;\r\n instance.connectionUrl = null;\r\n\r\n if (options && options.callbacks) {\r\n\r\n instance.callbacks = options.callbacks;\r\n } else {\r\n instance.callbacks = {};\r\n }\r\n\r\n}\r\n\r\nfunction addMethod(instance) {\r\n\r\n function errorHandler(error) {\r\n\r\n if (instance.callbacks.error) {\r\n\r\n instance.callbacks.error(error);\r\n }\r\n }\r\n\r\n function getUserMedia(constraints) {\r\n\r\n if (!constraints) {\r\n\r\n constraints = {\r\n video: {\r\n deviceId: undefined\r\n },\r\n audio: {\r\n deviceId: undefined\r\n }\r\n };\r\n }\r\n\r\n console.info(logHeader, 'Requested Constraint To Input Devices', constraints);\r\n\r\n return navigator.mediaDevices.getUserMedia(constraints)\r\n .then(function (stream) {\r\n\r\n console.info(logHeader, 'Received Media Stream From Input Device', stream);\r\n\r\n instance.stream = stream;\r\n\r\n let elem = instance.videoElement;\r\n\r\n // Attach stream to video element when video element is provided.\r\n if (elem) {\r\n\r\n elem.srcObject = stream;\r\n\r\n elem.onloadedmetadata = function (e) {\r\n\r\n elem.play();\r\n };\r\n }\r\n\r\n return new Promise(function (resolve) {\r\n\r\n resolve(stream);\r\n });\r\n })\r\n .catch(function (error) {\r\n\r\n console.error(logHeader, 'Can\\'t Get Media Stream From Input Device', error);\r\n errorHandler(error);\r\n\r\n return new Promise(function (resolve, reject) {\r\n reject(error);\r\n });\r\n });\r\n }\r\n\r\n function getDisplayMedia(constraints) {\r\n\r\n if (!constraints) {\r\n constraints = {};\r\n }\r\n\r\n console.info(logHeader, 'Requested Constraint To Display', constraints);\r\n\r\n return navigator.mediaDevices.getDisplayMedia(constraints)\r\n .then(function (stream) {\r\n\r\n console.info(logHeader, 'Received Media Stream From Display', stream);\r\n\r\n instance.stream = stream;\r\n\r\n let elem = instance.videoElement;\r\n\r\n // Attach stream to video element when video element is provided.\r\n if (elem) {\r\n\r\n elem.srcObject = stream;\r\n\r\n elem.onloadedmetadata = function (e) {\r\n\r\n elem.play();\r\n };\r\n }\r\n\r\n return new Promise(function (resolve) {\r\n\r\n resolve(stream);\r\n });\r\n })\r\n .catch(function (error) {\r\n\r\n console.error(logHeader, 'Can\\'t Get Media Stream From Display', error);\r\n errorHandler(error);\r\n\r\n return new Promise(function (resolve, reject) {\r\n reject(error);\r\n });\r\n });\r\n }\r\n\r\n // From https://webrtchacks.com/limit-webrtc-bandwidth-sdp/\r\n function setBitrateLimit(sdp, media, bitrate) {\r\n\r\n let lines = sdp.split('\\r\\n');\r\n let line = -1;\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n if (lines[i].indexOf('m=' + media) === 0) {\r\n line = i;\r\n break;\r\n }\r\n }\r\n if (line === -1) {\r\n // Could not find the m line for media\r\n return sdp;\r\n }\r\n\r\n // Pass the m line\r\n line++;\r\n\r\n // Skip i and c lines\r\n while (lines[line].indexOf('i=') === 0 || lines[line].indexOf('c=') === 0) {\r\n\r\n line++;\r\n }\r\n\r\n // If we're on a b line, replace it\r\n if (lines[line].indexOf('b') === 0) {\r\n\r\n lines[line] = 'b=AS:' + bitrate;\r\n\r\n return lines.join('\\r\\n');\r\n }\r\n\r\n // Add a new b line\r\n let newLines = lines.slice(0, line)\r\n\r\n newLines.push('b=AS:' + bitrate)\r\n newLines = newLines.concat(lines.slice(line, lines.length))\r\n\r\n return newLines.join('\\r\\n')\r\n }\r\n\r\n function initWebSocket(connectionUrl) {\r\n\r\n if (!connectionUrl) {\r\n errorHandler('connectionUrl is required');\r\n return;\r\n }\r\n\r\n instance.connectionUrl = connectionUrl;\r\n\r\n let webSocket = null;\r\n\r\n try {\r\n\r\n webSocket = new WebSocket(connectionUrl);\r\n } catch (error) {\r\n\r\n errorHandler(error);\r\n }\r\n\r\n\r\n instance.webSocket = webSocket;\r\n\r\n webSocket.onopen = function () {\r\n\r\n // Request offer at the first time.\r\n sendMessage(webSocket, {\r\n command: 'request_offer'\r\n });\r\n };\r\n\r\n webSocket.onmessage = function (e) {\r\n\r\n let message = JSON.parse(e.data);\r\n\r\n if (message.error) {\r\n console.error('webSocket.onmessage', message.error);\r\n errorHandler(message.error);\r\n }\r\n\r\n if (message.command === 'offer') {\r\n\r\n // OME returns offer. Start create peer connection.\r\n createPeerConnection(\r\n message.id,\r\n message.peer_id,\r\n message.sdp,\r\n message.candidates,\r\n message.ice_servers\r\n );\r\n }\r\n };\r\n\r\n webSocket.onerror = function (error) {\r\n\r\n console.error('webSocket.onerror', error);\r\n errorHandler(error);\r\n };\r\n\r\n webSocket.onclose = function (e) {\r\n\r\n if (!instance.removing) {\r\n\r\n if (instance.callbacks.connectionClosed) {\r\n\r\n instance.callbacks.connectionClosed('websocket', e);\r\n }\r\n }\r\n };\r\n\r\n }\r\n\r\n function appendFmtp(sdp) {\r\n\r\n const fmtpStr = instance.connectionConfig.sdp.appendFmtp;\r\n\r\n const lines = sdp.split('\\r\\n');\r\n const payloads = [];\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n\r\n if (lines[i].indexOf('m=video') === 0) {\r\n\r\n let tokens = lines[i].split(' ')\r\n\r\n for (let j = 3; j < tokens.length; j++) {\r\n\r\n payloads.push(tokens[j]);\r\n }\r\n\r\n break;\r\n }\r\n }\r\n\r\n for (let i = 0; i < payloads.length; i++) {\r\n\r\n let fmtpLineFound = false;\r\n\r\n for (let j = 0; j < lines.length; j++) {\r\n\r\n if (lines[j].indexOf('a=fmtp:' + payloads[i]) === 0) {\r\n fmtpLineFound = true;\r\n lines[j] += ';' + fmtpStr;\r\n }\r\n }\r\n\r\n if (!fmtpLineFound) {\r\n\r\n for (let j = 0; j < lines.length; j++) {\r\n\r\n if (lines[j].indexOf('a=rtpmap:' + payloads[i]) === 0) {\r\n\r\n lines[j] += '\\r\\na=fmtp:' + payloads[i] + ' ' + fmtpStr;\r\n }\r\n }\r\n }\r\n }\r\n\r\n return lines.join('\\r\\n')\r\n }\r\n\r\n function appendOrientation(sdp) {\r\n\r\n const lines = sdp.split('\\r\\n');\r\n const payloads = [];\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n\r\n if (lines[i].indexOf('m=video') === 0) {\r\n\r\n let tokens = lines[i].split(' ')\r\n\r\n for (let j = 3; j < tokens.length; j++) {\r\n\r\n payloads.push(tokens[j]);\r\n }\r\n\r\n break;\r\n }\r\n }\r\n\r\n for (let i = 0; i < payloads.length; i++) {\r\n\r\n for (let j = 0; j < lines.length; j++) {\r\n\r\n if (lines[j].indexOf('a=rtpmap:' + payloads[i]) === 0) {\r\n\r\n lines[j] += '\\r\\na=extmap:' + payloads[i] + ' urn:3gpp:video-orientation';\r\n }\r\n }\r\n }\r\n\r\n return lines.join('\\r\\n')\r\n }\r\n\r\n function createPeerConnection(id, peerId, offer, candidates, iceServers) {\r\n\r\n let peerConnectionConfig = {};\r\n\r\n if (instance.connectionConfig.iceServers) {\r\n\r\n // first priority using ice servers from local config.\r\n peerConnectionConfig.iceServers = instance.connectionConfig.iceServers;\r\n\r\n if (instance.connectionConfig.iceTransportPolicy) {\r\n\r\n peerConnectionConfig.iceTransportPolicy = instance.connectionConfig.iceTransportPolicy;\r\n }\r\n } else if (iceServers) {\r\n\r\n // second priority using ice servers from ome and force using TCP\r\n peerConnectionConfig.iceServers = [];\r\n\r\n for (let i = 0; i < iceServers.length; i++) {\r\n\r\n let iceServer = iceServers[i];\r\n\r\n let regIceServer = {};\r\n\r\n regIceServer.urls = iceServer.urls;\r\n\r\n let hasWebSocketUrl = false;\r\n let webSocketUrl = generateDomainFromUrl(instance.connectionUrl);\r\n\r\n for (let j = 0; j < regIceServer.urls.length; j++) {\r\n\r\n let serverUrl = regIceServer.urls[j];\r\n\r\n if (serverUrl.indexOf(webSocketUrl) > -1) {\r\n hasWebSocketUrl = true;\r\n break;\r\n }\r\n }\r\n\r\n if (!hasWebSocketUrl) {\r\n\r\n if (regIceServer.urls.length > 0) {\r\n\r\n let cloneIceServer = regIceServer.urls[0];\r\n let ip = findIp(cloneIceServer);\r\n\r\n if (webSocketUrl && ip) {\r\n regIceServer.urls.push(cloneIceServer.replace(ip, webSocketUrl));\r\n }\r\n }\r\n }\r\n\r\n regIceServer.username = iceServer.user_name;\r\n regIceServer.credential = iceServer.credential;\r\n\r\n peerConnectionConfig.iceServers.push(regIceServer);\r\n }\r\n\r\n peerConnectionConfig.iceTransportPolicy = 'relay';\r\n } else {\r\n // last priority using default ice servers.\r\n\r\n if (instance.iceTransportPolicy) {\r\n\r\n peerConnectionConfig.iceTransportPolicy = instance.iceTransportPolicy;\r\n }\r\n }\r\n\r\n let advancedSetting = {\r\n optional: [\r\n {\r\n googHighStartBitrate: {\r\n exact: !0\r\n }\r\n },\r\n {\r\n googPayloadPadding: {\r\n exact: !0\r\n }\r\n },\r\n {\r\n googScreencastMinBitrate: {\r\n exact: 500\r\n }\r\n },\r\n {\r\n enableDscp: {\r\n exact: true\r\n }\r\n }\r\n ]\r\n };\r\n\r\n console.info(logHeader, 'Create Peer Connection With Config', peerConnectionConfig);\r\n\r\n let peerConnection = new RTCPeerConnection(peerConnectionConfig);\r\n\r\n instance.peerConnection = peerConnection;\r\n\r\n // set local stream\r\n instance.stream.getTracks().forEach(function (track) {\r\n\r\n console.info(logHeader, 'Add Track To Peer Connection', track);\r\n peerConnection.addTrack(track, instance.stream);\r\n });\r\n\r\n\r\n if (checkIOSVersion() >= 15) {\r\n const formatNumber = getFormatNumber(offer.sdp, 'H264');\r\n\r\n if (formatNumber > 0) {\r\n offer.sdp = removeFormat(offer.sdp, formatNumber);\r\n }\r\n }\r\n\r\n if (instance.connectionConfig.maxVideoBitrate) {\r\n\r\n // if bandwith limit is set. modify sdp from ome to limit acceptable bandwidth of ome\r\n offer.sdp = setBitrateLimit(offer.sdp, 'video', instance.connectionConfig.maxVideoBitrate);\r\n }\r\n\r\n if (instance.connectionConfig.sdp && instance.connectionConfig.sdp.appendFmtp) {\r\n\r\n offer.sdp = appendFmtp(offer.sdp);\r\n }\r\n\r\n // offer.sdp = appendOrientation(offer.sdp);\r\n\r\n peerConnection.setRemoteDescription(new RTCSessionDescription(offer))\r\n .then(function () {\r\n\r\n peerConnection.createAnswer()\r\n .then(function (answer) {\r\n\r\n if (checkIOSVersion() >= 15) {\r\n\r\n const formatNumber = getFormatNumber(answer.sdp, 'H264');\r\n\r\n if (formatNumber > 0) {\r\n\r\n answer.sdp = removeFormat(answer.sdp, formatNumber);\r\n }\r\n }\r\n\r\n if (instance.connectionConfig.sdp && instance.connectionConfig.sdp.appendFmtp) {\r\n\r\n answer.sdp = appendFmtp(answer.sdp);\r\n }\r\n\r\n peerConnection.setLocalDescription(answer)\r\n .then(function () {\r\n\r\n sendMessage(instance.webSocket, {\r\n id: id,\r\n peer_id: peerId,\r\n command: 'answer',\r\n sdp: answer\r\n });\r\n })\r\n .catch(function (error) {\r\n\r\n console.error('peerConnection.setLocalDescription', error);\r\n errorHandler(error);\r\n });\r\n })\r\n .catch(function (error) {\r\n\r\n console.error('peerConnection.createAnswer', error);\r\n errorHandler(error);\r\n });\r\n })\r\n .catch(function (error) {\r\n\r\n console.error('peerConnection.setRemoteDescription', error);\r\n errorHandler(error);\r\n });\r\n\r\n if (candidates) {\r\n\r\n addIceCandidate(peerConnection, candidates);\r\n }\r\n\r\n peerConnection.onicecandidate = function (e) {\r\n\r\n if (e.candidate && e.candidate.candidate) {\r\n\r\n console.info(logHeader, 'Candidate Sent', '\\n', e.candidate.candidate, '\\n', e);\r\n\r\n sendMessage(instance.webSocket, {\r\n id: id,\r\n peer_id: peerId,\r\n command: 'candidate',\r\n candidates: [e.candidate]\r\n });\r\n }\r\n };\r\n\r\n peerConnection.oniceconnectionstatechange = function (e) {\r\n\r\n let state = peerConnection.iceConnectionState;\r\n\r\n if (instance.callbacks.iceStateChange) {\r\n\r\n console.info(logHeader, 'ICE State', '[' + state + ']');\r\n instance.callbacks.iceStateChange(state);\r\n }\r\n\r\n if (state === 'connected') {\r\n\r\n if (instance.callbacks.connected) {\r\n\r\n console.info(logHeader, 'Iceconnection Connected', e);\r\n instance.callbacks.connected(e);\r\n }\r\n }\r\n\r\n if (state === 'failed' || state === 'disconnected' || state === 'closed') {\r\n\r\n if (instance.callbacks.connectionClosed) {\r\n\r\n console.error(logHeader, 'Iceconnection Closed', e);\r\n instance.callbacks.connectionClosed('ice', e);\r\n }\r\n }\r\n }\r\n }\r\n\r\n function addIceCandidate(peerConnection, candidates) {\r\n\r\n for (let i = 0; i < candidates.length; i++) {\r\n\r\n if (candidates[i] && candidates[i].candidate) {\r\n\r\n let basicCandidate = candidates[i];\r\n\r\n peerConnection.addIceCandidate(new RTCIceCandidate(basicCandidate))\r\n .then(function () {\r\n\r\n })\r\n .catch(function (error) {\r\n\r\n console.error('peerConnection.addIceCandidate', error);\r\n errorHandler(error);\r\n });\r\n }\r\n }\r\n }\r\n\r\n // instance methods\r\n instance.attachMedia = function (videoElement) {\r\n\r\n instance.videoElement = videoElement;\r\n };\r\n\r\n instance.getUserMedia = function (constraints) {\r\n\r\n return getUserMedia(constraints);\r\n };\r\n\r\n instance.getDisplayMedia = function (constraints) {\r\n\r\n return getDisplayMedia(constraints);\r\n };\r\n\r\n instance.startStreaming = function (connectionUrl, connectionConfig) {\r\n\r\n console.info(logEventHeader, 'Start Streaming');\r\n\r\n if (connectionConfig) {\r\n\r\n instance.connectionConfig = connectionConfig;\r\n }\r\n\r\n initWebSocket(connectionUrl);\r\n };\r\n\r\n instance.remove = function () {\r\n\r\n instance.removing = true;\r\n\r\n // first release peer connection with ome\r\n if (instance.peerConnection) {\r\n\r\n // remove tracks from peer connection\r\n instance.peerConnection.getSenders().forEach(function (sender) {\r\n instance.peerConnection.removeTrack(sender);\r\n });\r\n\r\n instance.peerConnection.close();\r\n instance.peerConnection = null;\r\n delete instance.peerConnection;\r\n }\r\n\r\n // release video, audio stream\r\n if (instance.stream) {\r\n\r\n instance.stream.getTracks().forEach(track => {\r\n\r\n track.stop();\r\n instance.stream.removeTrack(track);\r\n });\r\n\r\n if (instance.videoElement) {\r\n instance.videoElement.srcObject = null;\r\n }\r\n\r\n instance.stream = null;\r\n delete instance.stream;\r\n }\r\n\r\n // release websocket\r\n if (instance.webSocket) {\r\n\r\n instance.webSocket.close();\r\n instance.webSocket = null;\r\n delete instance.webSocket;\r\n }\r\n\r\n instance.status = 'removed';\r\n\r\n console.info(logEventHeader, 'Removed');\r\n\r\n };\r\n}\r\n\r\n// static methods\r\nOvenLiveKit.create = function (options) {\r\n\r\n console.info(logEventHeader, 'Create WebRTC Input v1.0.2');\r\n\r\n let instance = {};\r\n\r\n instance.removing = false;\r\n\r\n initConfig(instance, options);\r\n addMethod(instance);\r\n\r\n return instance;\r\n};\r\n\r\nOvenLiveKit.getDevices = async function () {\r\n\r\n try {\r\n // First check both audio and video sources are available.\r\n await getStreamForDeviceCheck('both');\r\n } catch (e) {\r\n\r\n console.warn(logHeader, 'Can not find Video and Audio devices', e);\r\n\r\n let videoFound = null;\r\n let audioFound = null;\r\n\r\n try {\r\n videoFound = await getStreamForDeviceCheck('video');\r\n } catch (e) {\r\n console.warn(logHeader, 'Can not find Video devices', e);\r\n }\r\n\r\n try {\r\n audioFound = await getStreamForDeviceCheck('audio');\r\n } catch (e) {\r\n console.warn(logHeader, 'Can not find Audio devices', e);\r\n }\r\n\r\n if (!videoFound && !audioFound) {\r\n throw new Error('No input devices were found.');\r\n }\r\n }\r\n\r\n const deviceInfos = await getDevices();\r\n return gotDevices(deviceInfos)\r\n};\r\n\r\nexport default OvenLiveKit;"],"names":["root","factory","exports","module","define","amd","self","__webpack_require__","definition","key","o","Object","defineProperty","enumerable","get","obj","prop","prototype","hasOwnProperty","call","OvenLiveKit","logHeader","logEventHeader","sendMessage","webSocket","message","send","JSON","stringify","generateDomainFromUrl","url","match","result","findIp","string","RegExp","checkIOSVersion","agent","window","navigator","userAgent","start","indexOf","Number","substr","replace","getFormatNumber","sdp","format","lines","split","formatNumber","i","length","toLowerCase","removeFormat","newLines","push","join","async","getStreamForDeviceCheck","type","constraints","audio","video","mediaDevices","getUserMedia","addMethod","instance","errorHandler","error","callbacks","appendFmtp","fmtpStr","connectionConfig","payloads","tokens","j","fmtpLineFound","attachMedia","videoElement","deviceId","undefined","console","info","then","stream","elem","srcObject","onloadedmetadata","e","play","Promise","resolve","catch","reject","getDisplayMedia","startStreaming","connectionUrl","WebSocket","onopen","command","onmessage","parse","data","id","peerId","offer","candidates","iceServers","peerConnectionConfig","iceTransportPolicy","iceServer","regIceServer","urls","hasWebSocketUrl","webSocketUrl","cloneIceServer","ip","username","user_name","credential","peerConnection","RTCPeerConnection","getTracks","forEach","track","addTrack","maxVideoBitrate","media","bitrate","line","slice","concat","setBitrateLimit","setRemoteDescription","RTCSessionDescription","createAnswer","answer","setLocalDescription","peer_id","candidate","basicCandidate","addIceCandidate","RTCIceCandidate","onicecandidate","oniceconnectionstatechange","state","iceConnectionState","iceStateChange","connected","connectionClosed","createPeerConnection","ice_servers","onerror","onclose","removing","initWebSocket","remove","getSenders","sender","removeTrack","close","stop","status","create","options","initConfig","getDevices","warn","videoFound","audioFound","Error","deviceInfos","devices","deviceInfo","kind","label","audioinput","audiooutput","videoinput","other","gotDevices","enumerateDevices"],"sourceRoot":""}
1
+ {"version":3,"file":"OvenLiveKit.min.js","mappings":"CAAA,SAA2CA,EAAMC,GAC1B,iBAAZC,SAA0C,iBAAXC,OACxCA,OAAOD,QAAUD,IACQ,mBAAXG,QAAyBA,OAAOC,IAC9CD,OAAO,GAAIH,GACe,iBAAZC,QACdA,QAAqB,YAAID,IAEzBD,EAAkB,YAAIC,IARxB,CASGK,MAAM,WACT,M,mBCTA,IAAIC,EAAsB,CCA1B,EAAwB,CAACL,EAASM,KACjC,IAAI,IAAIC,KAAOD,EACXD,EAAoBG,EAAEF,EAAYC,KAASF,EAAoBG,EAAER,EAASO,IAC5EE,OAAOC,eAAeV,EAASO,EAAK,CAAEI,YAAY,EAAMC,IAAKN,EAAWC,MCJ3E,EAAwB,CAACM,EAAKC,IAAUL,OAAOM,UAAUC,eAAeC,KAAKJ,EAAKC,I,4BCAlF,MAAMI,EAAc,GAGdC,EAAY,mBACZC,EAAiB,sBAGvB,SAASC,EAAYC,EAAWC,GAExBD,GACAA,EAAUE,KAAKC,KAAKC,UAAUH,IAItC,SAASI,EAAsBC,GAC3B,IACIC,EADAC,EAAS,GAMb,OAJID,EAAQD,EAAIC,MAAM,8DAClBC,EAASD,EAAM,IAGZC,EAGX,SAASC,EAAOC,GAEZ,IACIH,EADAC,EAAS,GAOb,OAJID,EAAQG,EAAOH,MAAM,IAAII,OAAO,0KAA2K,UAC3MH,EAASD,EAAM,IAGZC,EAwCXI,eAAeC,EAAwBC,GAGnC,MAAMC,EAAc,GAYpB,MATa,SAATD,GACAC,EAAYC,OAAQ,EACpBD,EAAYE,OAAQ,GACJ,UAATH,EACPC,EAAYC,OAAQ,EACJ,UAATF,IACPC,EAAYE,OAAQ,SAGXC,UAAUC,aAAaC,aAAaL,GAiErD,SAASM,EAAUC,GAEf,SAASC,EAAaC,GAEdF,EAASG,UAAUD,OAEnBF,EAASG,UAAUD,MAAMA,GAqNjC,SAASE,EAAWC,GAEhB,MAAMC,EAAUN,EAASO,iBAAiBF,IAAID,WAExCI,EAAQH,EAAII,MAAM,QAClBC,EAAW,GAEjB,IAAK,IAAIC,EAAI,EAAGA,EAAIH,EAAMI,OAAQD,IAE9B,GAAoC,IAAhCH,EAAMG,GAAGE,QAAQ,WAAkB,CAEnC,IAAIC,EAASN,EAAMG,GAAGF,MAAM,KAE5B,IAAK,IAAIM,EAAI,EAAGA,EAAID,EAAOF,OAAQG,IAE/BL,EAASM,KAAKF,EAAOC,IAGzB,MAIR,IAAK,IAAIJ,EAAI,EAAGA,EAAID,EAASE,OAAQD,IAAK,CAEtC,IAAIM,GAAgB,EAEpB,IAAK,IAAIF,EAAI,EAAGA,EAAIP,EAAMI,OAAQG,IAEoB,IAA9CP,EAAMO,GAAGF,QAAQ,UAAYH,EAASC,MACtCM,GAAgB,EAChBT,EAAMO,IAAM,IAAMT,GAI1B,IAAKW,EAED,IAAK,IAAIF,EAAI,EAAGA,EAAIP,EAAMI,OAAQG,IAEsB,IAAhDP,EAAMO,GAAGF,QAAQ,YAAcH,EAASC,MAExCH,EAAMO,IAAM,cAAgBL,EAASC,GAAK,IAAML,GAMhE,OAAOE,EAAMU,KAAK,QAqQtB,SAASC,IACDnB,EAASoB,iBAGTpB,EAASoB,eAAeC,aAAaC,SAAQ,SAAUC,GACnDvB,EAASoB,eAAeI,YAAYD,MAGxCvB,EAASoB,eAAeK,QACxBzB,EAASoB,eAAiB,YACnBpB,EAASoB,gBAIxB,SAASM,IAED1B,EAAStB,YAETsB,EAAStB,UAAU+C,QACnBzB,EAAStB,UAAY,YACdsB,EAAStB,WAwBxBsB,EAAS2B,YAAc,SAAUC,GAE7B5B,EAAS4B,aAAeA,GAG5B5B,EAASF,aAAe,SAAUL,GAE9B,OAvjBJ,SAAsBA,GAgBlB,OAdKA,IAEDA,EAAc,CACVE,MAAO,CACHkC,cAAUC,GAEdpC,MAAO,CACHmC,cAAUC,KAKtBC,QAAQC,KAAKzD,EAAW,mDAAoDkB,GAErEG,UAAUC,aAAaC,aAAaL,GACtCwC,MAAK,SAAUC,GAEZH,QAAQC,KAAKzD,EAAW,0CAA2C2D,GAEnElC,EAASmC,YAAcD,EAEvB,IAAIE,EAAOpC,EAAS4B,aAapB,OAVIQ,IAEAA,EAAKC,UAAYH,EAEjBE,EAAKE,iBAAmB,SAAUC,GAE9BH,EAAKI,SAIN,IAAIC,SAAQ,SAAUC,GAEzBA,EAAQR,SAGfS,OAAM,SAAUzC,GAKb,OAHA6B,QAAQ7B,MAAM3B,EAAW,2CAA6C2B,GACtED,EAAaC,GAEN,IAAIuC,SAAQ,SAAUC,EAASE,GAClCA,EAAO1C,SAwgBZJ,CAAaL,IAGxBO,EAAS6C,gBAAkB,SAAUpD,GAEjC,OAxgBJ,SAAyBA,GAQrB,OANKA,IACDA,EAAc,IAGlBsC,QAAQC,KAAKzD,EAAW,6CAA8CkB,GAE/DG,UAAUC,aAAagD,gBAAgBpD,GACzCwC,MAAK,SAAUC,GAEZH,QAAQC,KAAKzD,EAAW,qCAAsC2D,GAE9DlC,EAASmC,YAAcD,EAEvB,IAAIE,EAAOpC,EAAS4B,aAapB,OAVIQ,IAEAA,EAAKC,UAAYH,EAEjBE,EAAKE,iBAAmB,SAAUC,GAE9BH,EAAKI,SAIN,IAAIC,SAAQ,SAAUC,GAEzBA,EAAQR,SAGfS,OAAM,SAAUzC,GAKb,OAHA6B,QAAQ7B,MAAM3B,EAAW,sCAAwC2B,GACjED,EAAaC,GAEN,IAAIuC,SAAQ,SAAUC,EAASE,GAClCA,EAAO1C,SAieZ2C,CAAgBpD,IAG3BO,EAAS8C,eAAiB,SAAUC,EAAexC,GAE/CwB,QAAQC,KAAKxD,EAAgB,mBAEzB+B,IAEAP,EAASO,iBAAmBA,GA1bpC,SAAuBwC,GAEnB,IAAKA,EAED,YADA9C,EAAa,6BAIjBD,EAAS+C,cAAgBA,EAEzB,IAAIrE,EAAY,KAEhB,IAEIA,EAAY,IAAIsE,UAAUD,GAC5B,MAAO7C,GAELD,EAAaC,GAIjBF,EAAStB,UAAYA,EAErBA,EAAUuE,OAAS,WAGfxE,EAAYC,EAAW,CACnBwE,QAAS,mBAIjBxE,EAAUyE,UAAY,SAAUZ,GAE5B,IAAI5D,EAAUE,KAAKuE,MAAMb,EAAEc,MAEvB1E,EAAQuB,QACR6B,QAAQ7B,MAAM,sBAAuBvB,EAAQuB,OAC7CD,EAAatB,EAAQuB,QAGD,UAApBvB,EAAQuE,SAkHpB,SAA8BI,EAAIC,EAAQC,EAAOC,EAAYC,GAEzD,IAAIC,EAAuB,GAE3B,GAAI3D,EAASO,iBAAiBmD,WAG1BC,EAAqBD,WAAa1D,EAASO,iBAAiBmD,WAExD1D,EAASO,iBAAiBqD,qBAE1BD,EAAqBC,mBAAqB5D,EAASO,iBAAiBqD,yBAErE,GAAIF,EAAY,CAGnBC,EAAqBD,WAAa,GAElC,IAAK,IAAI/C,EAAI,EAAGA,EAAI+C,EAAW9C,OAAQD,IAAK,CAExC,IAAIkD,EAAYH,EAAW/C,GAEvBmD,EAAe,GAEnBA,EAAaC,KAAOF,EAAUE,KAE9B,IAAIC,GAAkB,EAClBC,EAAelF,EAAsBiB,EAAS+C,eAElD,IAAK,IAAIhC,EAAI,EAAGA,EAAI+C,EAAaC,KAAKnD,OAAQG,IAI1C,GAFgB+C,EAAaC,KAAKhD,GAEpBF,QAAQoD,IAAiB,EAAG,CACtCD,GAAkB,EAClB,MAIR,IAAKA,GAEGF,EAAaC,KAAKnD,OAAS,EAAG,CAE9B,IAAIsD,EAAiBJ,EAAaC,KAAK,GACnCI,EAAKhF,EAAO+E,GAEZD,GAAgBE,GAChBL,EAAaC,KAAK/C,KAAKkD,EAAeE,QAAQD,EAAIF,IAK9DH,EAAaO,SAAWR,EAAUS,UAClCR,EAAaS,WAAaV,EAAUU,WAEpCZ,EAAqBD,WAAW1C,KAAK8C,GAGzCH,EAAqBC,mBAAqB,aAItC5D,EAAS4D,qBAETD,EAAqBC,mBAAqB5D,EAAS4D,oBA6B3D7B,QAAQC,KAAKzD,EAAW,qCAAsCoF,GAE9D,IAAIvC,EAAiB,IAAIoD,kBAAkBb,GAE3C3D,EAASoB,eAAiBA,EAG1BpB,EAASmC,YAAYsC,YAAYnD,SAAQ,SAAUoD,GAE/C3C,QAAQC,KAAKzD,EAAW,+BAAgCmG,GACxDtD,EAAeuD,SAASD,EAAO1E,EAASmC,gBAGxCnC,EAASO,iBAAiBqE,kBAG1BpB,EAAMnD,IAhTd,SAAyBA,EAAKwE,EAAOC,GAEjC,IAAItE,EAAQH,EAAII,MAAM,QAClBsE,GAAQ,EAEZ,IAAK,IAAIpE,EAAI,EAAGA,EAAIH,EAAMI,OAAQD,IAC9B,GAAuC,IAAnCH,EAAMG,GAAGE,QAAQ,WAAqB,CACtCkE,EAAOpE,EACP,MAGR,IAAc,IAAVoE,EAEA,OAAO1E,EAOX,IAHA0E,IAGqC,IAA9BvE,EAAMuE,GAAMlE,QAAQ,OAA6C,IAA9BL,EAAMuE,GAAMlE,QAAQ,OAE1DkE,IAIJ,GAAiC,IAA7BvE,EAAMuE,GAAMlE,QAAQ,KAIpB,OAFAL,EAAMuE,GAAQ,QAAUD,EAEjBtE,EAAMU,KAAK,QAItB,IAAI8D,EAAWxE,EAAMyE,MAAM,EAAGF,GAK9B,OAHAC,EAAShE,KAAK,QAAU8D,GACxBE,EAAWA,EAASE,OAAO1E,EAAMyE,MAAMF,EAAMvE,EAAMI,SAE5CoE,EAAS9D,KAAK,QAyQLiE,CAAgB3B,EAAMnD,IAAK,EAASL,EAASO,iBAAiBqE,kBAG1E5E,EAASO,iBAAiBF,KAAOL,EAASO,iBAAiBF,IAAID,aAE/DoD,EAAMnD,IAAMD,EAAWoD,EAAMnD,MAKjCe,EAAegE,qBAAqB,IAAIC,sBAAsB7B,IACzDvB,MAAK,WAEFb,EAAekE,eACVrD,MAAK,SAAUsD,GAERvF,EAASO,iBAAiBF,KAAOL,EAASO,iBAAiBF,IAAID,aAE/DmF,EAAOlF,IAAMD,EAAWmF,EAAOlF,MAGnCe,EAAeoE,oBAAoBD,GAC9BtD,MAAK,WAEFxD,EAAYuB,EAAStB,UAAW,CAC5B4E,GAAIA,EACJmC,QAASlC,EACTL,QAAS,SACT7C,IAAKkF,OAGZ5C,OAAM,SAAUzC,GAEb6B,QAAQ7B,MAAM,qCAAsCA,GACpDD,EAAaC,SAGxByC,OAAM,SAAUzC,GAEb6B,QAAQ7B,MAAM,8BAA+BA,GAC7CD,EAAaC,SAGxByC,OAAM,SAAUzC,GAEb6B,QAAQ7B,MAAM,sCAAuCA,GACrDD,EAAaC,MAGjBuD,GA6CR,SAAyBrC,EAAgBqC,GAErC,IAAK,IAAI9C,EAAI,EAAGA,EAAI8C,EAAW7C,OAAQD,IAEnC,GAAI8C,EAAW9C,IAAM8C,EAAW9C,GAAG+E,UAAW,CAE1C,IAAIC,EAAiBlC,EAAW9C,GAEhCS,EAAewE,gBAAgB,IAAIC,gBAAgBF,IAC9C1D,MAAK,eAGLU,OAAM,SAAUzC,GAEb6B,QAAQ7B,MAAM,iCAAkCA,GAChDD,EAAaC,OA1DzB0F,CAAgBxE,EAAgBqC,GAGpCrC,EAAe0E,eAAiB,SAAUvD,GAElCA,EAAEmD,WAAanD,EAAEmD,UAAUA,WAE3BjH,EAAYuB,EAAStB,UAAW,CAC5B4E,GAAIA,EACJmC,QAASlC,EACTL,QAAS,YACTO,WAAY,CAAClB,EAAEmD,cAK3BtE,EAAe2E,2BAA6B,SAAUxD,GAElD,IAAIyD,EAAQ5E,EAAe6E,mBAEvBjG,EAASG,UAAU+F,iBAEnBnE,QAAQC,KAAKzD,EAAW,YAAa,IAAMyH,EAAQ,KACnDhG,EAASG,UAAU+F,eAAeF,IAGxB,cAAVA,GAEIhG,EAASG,UAAUgG,WACnBnG,EAASG,UAAUgG,UAAU5D,GAIvB,WAAVyD,GAAgC,iBAAVA,GAAsC,WAAVA,GAE9ChG,EAASG,UAAUiG,mBACnBrE,QAAQ7B,MAAM3B,EAAW,uBAAwBgE,GACjDvC,EAASG,UAAUiG,iBAAiB,MAAO7D,KApT/C8D,CACI1H,EAAQ2E,GACR3E,EAAQ8G,QACR9G,EAAQ0B,IACR1B,EAAQ8E,WACR9E,EAAQ2H,cAKpB5H,EAAU6H,QAAU,SAAUrG,GAE1B6B,QAAQ7B,MAAM,oBAAqBA,GACnCD,EAAaC,IAGjBxB,EAAU8H,QAAU,SAAUjE,GAErBvC,EAASyG,uBAENzG,EAASG,UAAUiG,kBACnBpG,EAASG,UAAUiG,iBAAiB,YAAa7D,IA8X7DmE,CAAc3D,IAGlB/C,EAAS2G,cAAgB,WAErB3G,EAASyG,uBAAwB,EAEjC/E,IACAP,KAGJnB,EAAS4G,OAAS,WAEd5G,EAASyG,uBAAwB,EAEjC/E,IACAP,IA1DInB,EAASmC,cAETnC,EAASmC,YAAYsC,YAAYnD,SAAQoD,IAErCA,EAAMmC,OACN7G,EAASmC,YAAYX,YAAYkD,MAGjC1E,EAAS4B,eACT5B,EAAS4B,aAAaS,UAAY,MAGtCrC,EAASmC,YAAc,YAChBnC,EAASmC,aAgDpBJ,QAAQC,KAAKxD,EAAgB,YAKrCF,EAAYwI,WAAa,WACrB,MAlwBY,SAswBhBxI,EAAYyI,OAAS,SAAUC,GAE3BjF,QAAQC,KAAKxD,EAAgB,6BAE7B,IAAIwB,EAAW,CAEf,uBAAiC,GAKjC,OA5oBJ,SAAoBA,EAAUgH,GAE1BhH,EAASmC,YAAc,KACvBnC,EAAStB,UAAY,KACrBsB,EAASoB,eAAiB,KAC1BpB,EAASO,iBAAmB,GAE5BP,EAAS4B,aAAe,KACxB5B,EAAS+C,cAAgB,KAErBiE,GAAWA,EAAQ7G,UAEnBH,EAASG,UAAY6G,EAAQ7G,UAE7BH,EAASG,UAAY,GA2nBzB8G,CAAWjH,EAAUgH,GACrBjH,EAAUC,GAEHA,GAGX1B,EAAY4I,WAAa5H,iBAErB,UAEUC,EAAwB,QAChC,MAAOgD,GAELR,QAAQoF,KAAK5I,EAAW,uCAAwCgE,GAEhE,IAAI6E,EAAa,KACbC,EAAa,KAEjB,IACID,QAAmB7H,EAAwB,SAC7C,MAAOgD,GACLR,QAAQoF,KAAK5I,EAAW,6BAA8BgE,GAG1D,IACI8E,QAAmB9H,EAAwB,SAC7C,MAAOgD,GACLR,QAAQoF,KAAK5I,EAAW,6BAA8BgE,GAG1D,IAAK6E,IAAeC,EAChB,MAAM,IAAIC,MAAM,gCAKxB,OAptBJ,SAAoBC,GAEhB,IAAIC,EAAU,CACV,WAAc,GACd,YAAe,GACf,WAAc,GACd,MAAS,IAGb,IAAK,IAAI7G,EAAI,EAAGA,IAAM4G,EAAY3G,SAAUD,EAAG,CAE3C,MAAM8G,EAAaF,EAAY5G,GAE/B,IAAIqB,EAAO,GAEXA,EAAKH,SAAW4F,EAAW5F,SAEH,eAApB4F,EAAWC,MAEX1F,EAAK2F,MAAQF,EAAWE,OAAS,cAAcH,EAAQI,WAAWhH,OAAS,IAC3E4G,EAAQI,WAAW5G,KAAKgB,IACG,gBAApByF,EAAWC,MAElB1F,EAAK2F,MAAQF,EAAWE,OAAS,WAAWH,EAAQK,YAAYjH,OAAS,IACzE4G,EAAQK,YAAY7G,KAAKgB,IACE,eAApByF,EAAWC,MAElB1F,EAAK2F,MAAQF,EAAWE,OAAS,UAAUH,EAAQM,WAAWlH,OAAS,IACvE4G,EAAQM,WAAW9G,KAAKgB,KAGxBA,EAAK2F,MAAQF,EAAWE,OAAS,SAASH,EAAQO,MAAMnH,OAAS,IACjE4G,EAAQO,MAAM/G,KAAKgB,IAI3B,OAAOwF,EAgrBAQ,OAztBX1I,iBAEI,aAAaM,UAAUC,aAAaoI,mBAstBVf,KAI9B,U","sources":["webpack://OvenLiveKit/webpack/universalModuleDefinition","webpack://OvenLiveKit/webpack/bootstrap","webpack://OvenLiveKit/webpack/runtime/define property getters","webpack://OvenLiveKit/webpack/runtime/hasOwnProperty shorthand","webpack://OvenLiveKit/./src/OvenLiveKit.js"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"OvenLiveKit\"] = factory();\n\telse\n\t\troot[\"OvenLiveKit\"] = factory();\n})(self, function() {\nreturn ","// The require scope\nvar __webpack_require__ = {};\n\n","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","const OvenLiveKit = {};\r\n\r\nconst version = '1.0.4';\r\nconst logHeader = 'OvenLiveKit.js :';\r\nconst logEventHeader = 'OvenLiveKit.js ====';\r\n\r\n// private methods\r\nfunction sendMessage(webSocket, message) {\r\n\r\n if (webSocket) {\r\n webSocket.send(JSON.stringify(message));\r\n }\r\n}\r\n\r\nfunction generateDomainFromUrl(url) {\r\n let result = '';\r\n let match;\r\n if (match = url.match(/^(?:wss?:\\/\\/)?(?:[^@\\n]+@)?(?:www\\.)?([^:\\/\\n\\?\\=]+)/im)) {\r\n result = match[1];\r\n }\r\n\r\n return result;\r\n}\r\n\r\nfunction findIp(string) {\r\n\r\n let result = '';\r\n let match;\r\n\r\n if (match = string.match(new RegExp('\\\\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\b', 'gi'))) {\r\n result = match[0];\r\n }\r\n\r\n return result;\r\n}\r\n\r\nfunction getFormatNumber(sdp, format) {\r\n\r\n const lines = sdp.split('\\r\\n');\r\n let formatNumber = -1;\r\n\r\n for (let i = 0; i < lines.length - 1; i++) {\r\n\r\n lines[i] = lines[i].toLowerCase();\r\n\r\n if (lines[i].indexOf('a=rtpmap') > -1 && lines[i].indexOf(format.toLowerCase()) > -1) {\r\n // parsing \"a=rtpmap:100 H264/90000\" line\r\n formatNumber = lines[i].split(' ')[0].split(':')[1];\r\n break;\r\n }\r\n }\r\n\r\n return formatNumber;\r\n}\r\n\r\nfunction removeFormat(sdp, formatNumber) {\r\n let newLines = [];\r\n let lines = sdp.split('\\r\\n');\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n\r\n if (lines[i].indexOf('m=video') === 0) {\r\n newLines.push(lines[i].replace(' ' + formatNumber + '', ''));\r\n } else if (lines[i].indexOf(formatNumber + '') > -1) {\r\n\r\n } else {\r\n newLines.push(lines[i]);\r\n }\r\n }\r\n\r\n return newLines.join('\\r\\n')\r\n}\r\n\r\nasync function getStreamForDeviceCheck(type) {\r\n\r\n // High resolution video constraints makes browser to get maximum resolution of video device.\r\n const constraints = {\r\n };\r\n\r\n if (type === 'both') {\r\n constraints.audio = true;\r\n constraints.video = true;\r\n } else if (type === 'audio') {\r\n constraints.audio = true;\r\n } else if (type === 'video') {\r\n constraints.video = true;\r\n }\r\n\r\n return await navigator.mediaDevices.getUserMedia(constraints);\r\n}\r\n\r\nasync function getDevices() {\r\n\r\n return await navigator.mediaDevices.enumerateDevices();\r\n}\r\n\r\nfunction gotDevices(deviceInfos) {\r\n\r\n let devices = {\r\n 'audioinput': [],\r\n 'audiooutput': [],\r\n 'videoinput': [],\r\n 'other': [],\r\n };\r\n\r\n for (let i = 0; i !== deviceInfos.length; ++i) {\r\n\r\n const deviceInfo = deviceInfos[i];\r\n\r\n let info = {};\r\n\r\n info.deviceId = deviceInfo.deviceId;\r\n\r\n if (deviceInfo.kind === 'audioinput') {\r\n\r\n info.label = deviceInfo.label || `microphone ${devices.audioinput.length + 1}`;\r\n devices.audioinput.push(info);\r\n } else if (deviceInfo.kind === 'audiooutput') {\r\n\r\n info.label = deviceInfo.label || `speaker ${devices.audiooutput.length + 1}`;\r\n devices.audiooutput.push(info);\r\n } else if (deviceInfo.kind === 'videoinput') {\r\n\r\n info.label = deviceInfo.label || `camera ${devices.videoinput.length + 1}`;\r\n devices.videoinput.push(info);\r\n } else {\r\n\r\n info.label = deviceInfo.label || `other ${devices.other.length + 1}`;\r\n devices.other.push(info);\r\n }\r\n }\r\n\r\n return devices;\r\n}\r\n\r\nfunction initConfig(instance, options) {\r\n\r\n instance.inputStream = null;\r\n instance.webSocket = null;\r\n instance.peerConnection = null;\r\n instance.connectionConfig = {};\r\n\r\n instance.videoElement = null;\r\n instance.connectionUrl = null;\r\n\r\n if (options && options.callbacks) {\r\n\r\n instance.callbacks = options.callbacks;\r\n } else {\r\n instance.callbacks = {};\r\n }\r\n}\r\n\r\nfunction addMethod(instance) {\r\n\r\n function errorHandler(error) {\r\n\r\n if (instance.callbacks.error) {\r\n\r\n instance.callbacks.error(error);\r\n }\r\n }\r\n\r\n function getUserMedia(constraints) {\r\n\r\n if (!constraints) {\r\n\r\n constraints = {\r\n video: {\r\n deviceId: undefined\r\n },\r\n audio: {\r\n deviceId: undefined\r\n }\r\n };\r\n }\r\n\r\n console.info(logHeader, 'Request Stream To Input Devices With Constraints', constraints);\r\n\r\n return navigator.mediaDevices.getUserMedia(constraints)\r\n .then(function (stream) {\r\n\r\n console.info(logHeader, 'Received Media Stream From Input Device', stream);\r\n\r\n instance.inputStream = stream;\r\n\r\n let elem = instance.videoElement;\r\n\r\n // Attach stream to video element when video element is provided.\r\n if (elem) {\r\n\r\n elem.srcObject = stream;\r\n\r\n elem.onloadedmetadata = function (e) {\r\n\r\n elem.play();\r\n };\r\n }\r\n\r\n return new Promise(function (resolve) {\r\n\r\n resolve(stream);\r\n });\r\n })\r\n .catch(function (error) {\r\n\r\n console.error(logHeader, 'Can\\'t Get Media Stream From Input Device', error);\r\n errorHandler(error);\r\n\r\n return new Promise(function (resolve, reject) {\r\n reject(error);\r\n });\r\n });\r\n }\r\n\r\n function getDisplayMedia(constraints) {\r\n\r\n if (!constraints) {\r\n constraints = {};\r\n }\r\n\r\n console.info(logHeader, 'Request Stream To Display With Constraints', constraints);\r\n\r\n return navigator.mediaDevices.getDisplayMedia(constraints)\r\n .then(function (stream) {\r\n\r\n console.info(logHeader, 'Received Media Stream From Display', stream);\r\n\r\n instance.inputStream = stream;\r\n\r\n let elem = instance.videoElement;\r\n\r\n // Attach stream to video element when video element is provided.\r\n if (elem) {\r\n\r\n elem.srcObject = stream;\r\n\r\n elem.onloadedmetadata = function (e) {\r\n\r\n elem.play();\r\n };\r\n }\r\n\r\n return new Promise(function (resolve) {\r\n\r\n resolve(stream);\r\n });\r\n })\r\n .catch(function (error) {\r\n\r\n console.error(logHeader, 'Can\\'t Get Media Stream From Display', error);\r\n errorHandler(error);\r\n\r\n return new Promise(function (resolve, reject) {\r\n reject(error);\r\n });\r\n });\r\n }\r\n\r\n // From https://webrtchacks.com/limit-webrtc-bandwidth-sdp/\r\n function setBitrateLimit(sdp, media, bitrate) {\r\n\r\n let lines = sdp.split('\\r\\n');\r\n let line = -1;\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n if (lines[i].indexOf('m=' + media) === 0) {\r\n line = i;\r\n break;\r\n }\r\n }\r\n if (line === -1) {\r\n // Could not find the m line for media\r\n return sdp;\r\n }\r\n\r\n // Pass the m line\r\n line++;\r\n\r\n // Skip i and c lines\r\n while (lines[line].indexOf('i=') === 0 || lines[line].indexOf('c=') === 0) {\r\n\r\n line++;\r\n }\r\n\r\n // If we're on a b line, replace it\r\n if (lines[line].indexOf('b') === 0) {\r\n\r\n lines[line] = 'b=AS:' + bitrate;\r\n\r\n return lines.join('\\r\\n');\r\n }\r\n\r\n // Add a new b line\r\n let newLines = lines.slice(0, line)\r\n\r\n newLines.push('b=AS:' + bitrate)\r\n newLines = newLines.concat(lines.slice(line, lines.length))\r\n\r\n return newLines.join('\\r\\n')\r\n }\r\n\r\n function initWebSocket(connectionUrl) {\r\n\r\n if (!connectionUrl) {\r\n errorHandler('connectionUrl is required');\r\n return;\r\n }\r\n\r\n instance.connectionUrl = connectionUrl;\r\n\r\n let webSocket = null;\r\n\r\n try {\r\n\r\n webSocket = new WebSocket(connectionUrl);\r\n } catch (error) {\r\n\r\n errorHandler(error);\r\n }\r\n\r\n\r\n instance.webSocket = webSocket;\r\n\r\n webSocket.onopen = function () {\r\n\r\n // Request offer at the first time.\r\n sendMessage(webSocket, {\r\n command: 'request_offer'\r\n });\r\n };\r\n\r\n webSocket.onmessage = function (e) {\r\n\r\n let message = JSON.parse(e.data);\r\n\r\n if (message.error) {\r\n console.error('webSocket.onmessage', message.error);\r\n errorHandler(message.error);\r\n }\r\n\r\n if (message.command === 'offer') {\r\n\r\n // OME returns offer. Start create peer connection.\r\n createPeerConnection(\r\n message.id,\r\n message.peer_id,\r\n message.sdp,\r\n message.candidates,\r\n message.ice_servers\r\n );\r\n }\r\n };\r\n\r\n webSocket.onerror = function (error) {\r\n\r\n console.error('webSocket.onerror', error);\r\n errorHandler(error);\r\n };\r\n\r\n webSocket.onclose = function (e) {\r\n\r\n if (!instance.webSocketClosedByUser) {\r\n\r\n if (instance.callbacks.connectionClosed) {\r\n instance.callbacks.connectionClosed('websocket', e);\r\n }\r\n }\r\n };\r\n\r\n }\r\n\r\n function appendFmtp(sdp) {\r\n\r\n const fmtpStr = instance.connectionConfig.sdp.appendFmtp;\r\n\r\n const lines = sdp.split('\\r\\n');\r\n const payloads = [];\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n\r\n if (lines[i].indexOf('m=video') === 0) {\r\n\r\n let tokens = lines[i].split(' ')\r\n\r\n for (let j = 3; j < tokens.length; j++) {\r\n\r\n payloads.push(tokens[j]);\r\n }\r\n\r\n break;\r\n }\r\n }\r\n\r\n for (let i = 0; i < payloads.length; i++) {\r\n\r\n let fmtpLineFound = false;\r\n\r\n for (let j = 0; j < lines.length; j++) {\r\n\r\n if (lines[j].indexOf('a=fmtp:' + payloads[i]) === 0) {\r\n fmtpLineFound = true;\r\n lines[j] += ';' + fmtpStr;\r\n }\r\n }\r\n\r\n if (!fmtpLineFound) {\r\n\r\n for (let j = 0; j < lines.length; j++) {\r\n\r\n if (lines[j].indexOf('a=rtpmap:' + payloads[i]) === 0) {\r\n\r\n lines[j] += '\\r\\na=fmtp:' + payloads[i] + ' ' + fmtpStr;\r\n }\r\n }\r\n }\r\n }\r\n\r\n return lines.join('\\r\\n')\r\n }\r\n\r\n function appendOrientation(sdp) {\r\n\r\n const lines = sdp.split('\\r\\n');\r\n const payloads = [];\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n\r\n if (lines[i].indexOf('m=video') === 0) {\r\n\r\n let tokens = lines[i].split(' ')\r\n\r\n for (let j = 3; j < tokens.length; j++) {\r\n\r\n payloads.push(tokens[j]);\r\n }\r\n\r\n break;\r\n }\r\n }\r\n\r\n for (let i = 0; i < payloads.length; i++) {\r\n\r\n for (let j = 0; j < lines.length; j++) {\r\n\r\n if (lines[j].indexOf('a=rtpmap:' + payloads[i]) === 0) {\r\n\r\n lines[j] += '\\r\\na=extmap:' + payloads[i] + ' urn:3gpp:video-orientation';\r\n }\r\n }\r\n }\r\n\r\n return lines.join('\\r\\n')\r\n }\r\n\r\n function createPeerConnection(id, peerId, offer, candidates, iceServers) {\r\n\r\n let peerConnectionConfig = {};\r\n\r\n if (instance.connectionConfig.iceServers) {\r\n\r\n // first priority using ice servers from local config.\r\n peerConnectionConfig.iceServers = instance.connectionConfig.iceServers;\r\n\r\n if (instance.connectionConfig.iceTransportPolicy) {\r\n\r\n peerConnectionConfig.iceTransportPolicy = instance.connectionConfig.iceTransportPolicy;\r\n }\r\n } else if (iceServers) {\r\n\r\n // second priority using ice servers from ome and force using TCP\r\n peerConnectionConfig.iceServers = [];\r\n\r\n for (let i = 0; i < iceServers.length; i++) {\r\n\r\n let iceServer = iceServers[i];\r\n\r\n let regIceServer = {};\r\n\r\n regIceServer.urls = iceServer.urls;\r\n\r\n let hasWebSocketUrl = false;\r\n let webSocketUrl = generateDomainFromUrl(instance.connectionUrl);\r\n\r\n for (let j = 0; j < regIceServer.urls.length; j++) {\r\n\r\n let serverUrl = regIceServer.urls[j];\r\n\r\n if (serverUrl.indexOf(webSocketUrl) > -1) {\r\n hasWebSocketUrl = true;\r\n break;\r\n }\r\n }\r\n\r\n if (!hasWebSocketUrl) {\r\n\r\n if (regIceServer.urls.length > 0) {\r\n\r\n let cloneIceServer = regIceServer.urls[0];\r\n let ip = findIp(cloneIceServer);\r\n\r\n if (webSocketUrl && ip) {\r\n regIceServer.urls.push(cloneIceServer.replace(ip, webSocketUrl));\r\n }\r\n }\r\n }\r\n\r\n regIceServer.username = iceServer.user_name;\r\n regIceServer.credential = iceServer.credential;\r\n\r\n peerConnectionConfig.iceServers.push(regIceServer);\r\n }\r\n\r\n peerConnectionConfig.iceTransportPolicy = 'relay';\r\n } else {\r\n // last priority using default ice servers.\r\n\r\n if (instance.iceTransportPolicy) {\r\n\r\n peerConnectionConfig.iceTransportPolicy = instance.iceTransportPolicy;\r\n }\r\n }\r\n\r\n let advancedSetting = {\r\n optional: [\r\n {\r\n googHighStartBitrate: {\r\n exact: !0\r\n }\r\n },\r\n {\r\n googPayloadPadding: {\r\n exact: !0\r\n }\r\n },\r\n {\r\n googScreencastMinBitrate: {\r\n exact: 500\r\n }\r\n },\r\n {\r\n enableDscp: {\r\n exact: true\r\n }\r\n }\r\n ]\r\n };\r\n\r\n console.info(logHeader, 'Create Peer Connection With Config', peerConnectionConfig);\r\n\r\n let peerConnection = new RTCPeerConnection(peerConnectionConfig);\r\n\r\n instance.peerConnection = peerConnection;\r\n\r\n // set local stream\r\n instance.inputStream.getTracks().forEach(function (track) {\r\n\r\n console.info(logHeader, 'Add Track To Peer Connection', track);\r\n peerConnection.addTrack(track, instance.inputStream);\r\n });\r\n\r\n if (instance.connectionConfig.maxVideoBitrate) {\r\n\r\n // if bandwith limit is set. modify sdp from ome to limit acceptable bandwidth of ome\r\n offer.sdp = setBitrateLimit(offer.sdp, 'video', instance.connectionConfig.maxVideoBitrate);\r\n }\r\n\r\n if (instance.connectionConfig.sdp && instance.connectionConfig.sdp.appendFmtp) {\r\n\r\n offer.sdp = appendFmtp(offer.sdp);\r\n }\r\n\r\n // offer.sdp = appendOrientation(offer.sdp);\r\n\r\n peerConnection.setRemoteDescription(new RTCSessionDescription(offer))\r\n .then(function () {\r\n\r\n peerConnection.createAnswer()\r\n .then(function (answer) {\r\n\r\n if (instance.connectionConfig.sdp && instance.connectionConfig.sdp.appendFmtp) {\r\n\r\n answer.sdp = appendFmtp(answer.sdp);\r\n }\r\n\r\n peerConnection.setLocalDescription(answer)\r\n .then(function () {\r\n\r\n sendMessage(instance.webSocket, {\r\n id: id,\r\n peer_id: peerId,\r\n command: 'answer',\r\n sdp: answer\r\n });\r\n })\r\n .catch(function (error) {\r\n\r\n console.error('peerConnection.setLocalDescription', error);\r\n errorHandler(error);\r\n });\r\n })\r\n .catch(function (error) {\r\n\r\n console.error('peerConnection.createAnswer', error);\r\n errorHandler(error);\r\n });\r\n })\r\n .catch(function (error) {\r\n\r\n console.error('peerConnection.setRemoteDescription', error);\r\n errorHandler(error);\r\n });\r\n\r\n if (candidates) {\r\n\r\n addIceCandidate(peerConnection, candidates);\r\n }\r\n\r\n peerConnection.onicecandidate = function (e) {\r\n\r\n if (e.candidate && e.candidate.candidate) {\r\n\r\n sendMessage(instance.webSocket, {\r\n id: id,\r\n peer_id: peerId,\r\n command: 'candidate',\r\n candidates: [e.candidate]\r\n });\r\n }\r\n };\r\n\r\n peerConnection.oniceconnectionstatechange = function (e) {\r\n\r\n let state = peerConnection.iceConnectionState;\r\n\r\n if (instance.callbacks.iceStateChange) {\r\n\r\n console.info(logHeader, 'ICE State', '[' + state + ']');\r\n instance.callbacks.iceStateChange(state);\r\n }\r\n\r\n if (state === 'connected') {\r\n\r\n if (instance.callbacks.connected) {\r\n instance.callbacks.connected(e);\r\n }\r\n }\r\n\r\n if (state === 'failed' || state === 'disconnected' || state === 'closed') {\r\n\r\n if (instance.callbacks.connectionClosed) {\r\n console.error(logHeader, 'Iceconnection Closed', e);\r\n instance.callbacks.connectionClosed('ice', e);\r\n }\r\n }\r\n }\r\n }\r\n\r\n function addIceCandidate(peerConnection, candidates) {\r\n\r\n for (let i = 0; i < candidates.length; i++) {\r\n\r\n if (candidates[i] && candidates[i].candidate) {\r\n\r\n let basicCandidate = candidates[i];\r\n\r\n peerConnection.addIceCandidate(new RTCIceCandidate(basicCandidate))\r\n .then(function () {\r\n\r\n })\r\n .catch(function (error) {\r\n\r\n console.error('peerConnection.addIceCandidate', error);\r\n errorHandler(error);\r\n });\r\n }\r\n }\r\n }\r\n\r\n function closePeerConnection() {\r\n if (instance.peerConnection) {\r\n\r\n // remove tracks from peer connection\r\n instance.peerConnection.getSenders().forEach(function (sender) {\r\n instance.peerConnection.removeTrack(sender);\r\n });\r\n\r\n instance.peerConnection.close();\r\n instance.peerConnection = null;\r\n delete instance.peerConnection;\r\n }\r\n }\r\n\r\n function closeWebSocket() {\r\n\r\n if (instance.webSocket) {\r\n\r\n instance.webSocket.close();\r\n instance.webSocket = null;\r\n delete instance.webSocket;\r\n }\r\n }\r\n\r\n function closeInputStream() {\r\n // release video, audio stream\r\n if (instance.inputStream) {\r\n\r\n instance.inputStream.getTracks().forEach(track => {\r\n\r\n track.stop();\r\n instance.inputStream.removeTrack(track);\r\n });\r\n\r\n if (instance.videoElement) {\r\n instance.videoElement.srcObject = null;\r\n }\r\n\r\n instance.inputStream = null;\r\n delete instance.inputStream;\r\n }\r\n }\r\n\r\n // instance methods\r\n instance.attachMedia = function (videoElement) {\r\n\r\n instance.videoElement = videoElement;\r\n };\r\n\r\n instance.getUserMedia = function (constraints) {\r\n\r\n return getUserMedia(constraints);\r\n };\r\n\r\n instance.getDisplayMedia = function (constraints) {\r\n\r\n return getDisplayMedia(constraints);\r\n };\r\n\r\n instance.startStreaming = function (connectionUrl, connectionConfig) {\r\n\r\n console.info(logEventHeader, 'Start Streaming');\r\n\r\n if (connectionConfig) {\r\n\r\n instance.connectionConfig = connectionConfig;\r\n }\r\n\r\n initWebSocket(connectionUrl);\r\n };\r\n\r\n instance.stopStreaming = function () {\r\n\r\n instance.webSocketClosedByUser = true;\r\n\r\n closeWebSocket();\r\n closePeerConnection();\r\n };\r\n\r\n instance.remove = function () {\r\n\r\n instance.webSocketClosedByUser = true;\r\n\r\n closeWebSocket();\r\n closePeerConnection();\r\n closeInputStream();\r\n\r\n console.info(logEventHeader, 'Removed');\r\n\r\n };\r\n}\r\n\r\nOvenLiveKit.getVersion = function () {\r\n return version;\r\n}\r\n\r\n// static methods\r\nOvenLiveKit.create = function (options) {\r\n\r\n console.info(logEventHeader, 'Create WebRTC Input ' + version);\r\n\r\n let instance = {};\r\n\r\n instance.webSocketClosedByUser = false;\r\n\r\n initConfig(instance, options);\r\n addMethod(instance);\r\n\r\n return instance;\r\n};\r\n\r\nOvenLiveKit.getDevices = async function () {\r\n\r\n try {\r\n // First check both audio and video sources are available.\r\n await getStreamForDeviceCheck('both');\r\n } catch (e) {\r\n\r\n console.warn(logHeader, 'Can not find Video and Audio devices', e);\r\n\r\n let videoFound = null;\r\n let audioFound = null;\r\n\r\n try {\r\n videoFound = await getStreamForDeviceCheck('video');\r\n } catch (e) {\r\n console.warn(logHeader, 'Can not find Video devices', e);\r\n }\r\n\r\n try {\r\n audioFound = await getStreamForDeviceCheck('audio');\r\n } catch (e) {\r\n console.warn(logHeader, 'Can not find Audio devices', e);\r\n }\r\n\r\n if (!videoFound && !audioFound) {\r\n throw new Error('No input devices were found.');\r\n }\r\n }\r\n\r\n const deviceInfos = await getDevices();\r\n return gotDevices(deviceInfos)\r\n};\r\n\r\nexport default OvenLiveKit;"],"names":["root","factory","exports","module","define","amd","self","__webpack_require__","definition","key","o","Object","defineProperty","enumerable","get","obj","prop","prototype","hasOwnProperty","call","OvenLiveKit","logHeader","logEventHeader","sendMessage","webSocket","message","send","JSON","stringify","generateDomainFromUrl","url","match","result","findIp","string","RegExp","async","getStreamForDeviceCheck","type","constraints","audio","video","navigator","mediaDevices","getUserMedia","addMethod","instance","errorHandler","error","callbacks","appendFmtp","sdp","fmtpStr","connectionConfig","lines","split","payloads","i","length","indexOf","tokens","j","push","fmtpLineFound","join","closePeerConnection","peerConnection","getSenders","forEach","sender","removeTrack","close","closeWebSocket","attachMedia","videoElement","deviceId","undefined","console","info","then","stream","inputStream","elem","srcObject","onloadedmetadata","e","play","Promise","resolve","catch","reject","getDisplayMedia","startStreaming","connectionUrl","WebSocket","onopen","command","onmessage","parse","data","id","peerId","offer","candidates","iceServers","peerConnectionConfig","iceTransportPolicy","iceServer","regIceServer","urls","hasWebSocketUrl","webSocketUrl","cloneIceServer","ip","replace","username","user_name","credential","RTCPeerConnection","getTracks","track","addTrack","maxVideoBitrate","media","bitrate","line","newLines","slice","concat","setBitrateLimit","setRemoteDescription","RTCSessionDescription","createAnswer","answer","setLocalDescription","peer_id","candidate","basicCandidate","addIceCandidate","RTCIceCandidate","onicecandidate","oniceconnectionstatechange","state","iceConnectionState","iceStateChange","connected","connectionClosed","createPeerConnection","ice_servers","onerror","onclose","webSocketClosedByUser","initWebSocket","stopStreaming","remove","stop","getVersion","create","options","initConfig","getDevices","warn","videoFound","audioFound","Error","deviceInfos","devices","deviceInfo","kind","label","audioinput","audiooutput","videoinput","other","gotDevices","enumerateDevices"],"sourceRoot":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ovenlivekit",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "OvenLiveKit for Web is an open source JavaScript SDK suite for live streaming from web browsers to OvenMediaEngine.",
5
5
  "main": "dist/OvenLiveKit.min.js",
6
6
  "scripts": {
@@ -1,5 +1,6 @@
1
1
  const OvenLiveKit = {};
2
2
 
3
+ const version = '1.0.4';
3
4
  const logHeader = 'OvenLiveKit.js :';
4
5
  const logEventHeader = 'OvenLiveKit.js ====';
5
6
 
@@ -33,15 +34,6 @@ function findIp(string) {
33
34
  return result;
34
35
  }
35
36
 
36
- function checkIOSVersion() {
37
- var agent = window.navigator.userAgent,
38
- start = agent.indexOf('OS ');
39
- if ((agent.indexOf('iPhone') > -1 || agent.indexOf('iPad') > -1) && start > -1) {
40
- return window.Number(agent.substr(start + 3, 3).replace('_', '.'));
41
- }
42
- return 0;
43
- }
44
-
45
37
  function getFormatNumber(sdp, format) {
46
38
 
47
39
  const lines = sdp.split('\r\n');
@@ -143,13 +135,11 @@ function gotDevices(deviceInfos) {
143
135
 
144
136
  function initConfig(instance, options) {
145
137
 
146
- instance.stream = null;
138
+ instance.inputStream = null;
147
139
  instance.webSocket = null;
148
140
  instance.peerConnection = null;
149
141
  instance.connectionConfig = {};
150
142
 
151
- instance.status = 'creating';
152
-
153
143
  instance.videoElement = null;
154
144
  instance.connectionUrl = null;
155
145
 
@@ -159,7 +149,6 @@ function initConfig(instance, options) {
159
149
  } else {
160
150
  instance.callbacks = {};
161
151
  }
162
-
163
152
  }
164
153
 
165
154
  function addMethod(instance) {
@@ -186,14 +175,14 @@ function addMethod(instance) {
186
175
  };
187
176
  }
188
177
 
189
- console.info(logHeader, 'Requested Constraint To Input Devices', constraints);
178
+ console.info(logHeader, 'Request Stream To Input Devices With Constraints', constraints);
190
179
 
191
180
  return navigator.mediaDevices.getUserMedia(constraints)
192
181
  .then(function (stream) {
193
182
 
194
183
  console.info(logHeader, 'Received Media Stream From Input Device', stream);
195
184
 
196
- instance.stream = stream;
185
+ instance.inputStream = stream;
197
186
 
198
187
  let elem = instance.videoElement;
199
188
 
@@ -230,14 +219,14 @@ function addMethod(instance) {
230
219
  constraints = {};
231
220
  }
232
221
 
233
- console.info(logHeader, 'Requested Constraint To Display', constraints);
222
+ console.info(logHeader, 'Request Stream To Display With Constraints', constraints);
234
223
 
235
224
  return navigator.mediaDevices.getDisplayMedia(constraints)
236
225
  .then(function (stream) {
237
226
 
238
227
  console.info(logHeader, 'Received Media Stream From Display', stream);
239
228
 
240
- instance.stream = stream;
229
+ instance.inputStream = stream;
241
230
 
242
231
  let elem = instance.videoElement;
243
232
 
@@ -371,10 +360,9 @@ function addMethod(instance) {
371
360
 
372
361
  webSocket.onclose = function (e) {
373
362
 
374
- if (!instance.removing) {
363
+ if (!instance.webSocketClosedByUser) {
375
364
 
376
365
  if (instance.callbacks.connectionClosed) {
377
-
378
366
  instance.callbacks.connectionClosed('websocket', e);
379
367
  }
380
368
  }
@@ -565,21 +553,12 @@ function addMethod(instance) {
565
553
  instance.peerConnection = peerConnection;
566
554
 
567
555
  // set local stream
568
- instance.stream.getTracks().forEach(function (track) {
556
+ instance.inputStream.getTracks().forEach(function (track) {
569
557
 
570
558
  console.info(logHeader, 'Add Track To Peer Connection', track);
571
- peerConnection.addTrack(track, instance.stream);
559
+ peerConnection.addTrack(track, instance.inputStream);
572
560
  });
573
561
 
574
-
575
- if (checkIOSVersion() >= 15) {
576
- const formatNumber = getFormatNumber(offer.sdp, 'H264');
577
-
578
- if (formatNumber > 0) {
579
- offer.sdp = removeFormat(offer.sdp, formatNumber);
580
- }
581
- }
582
-
583
562
  if (instance.connectionConfig.maxVideoBitrate) {
584
563
 
585
564
  // if bandwith limit is set. modify sdp from ome to limit acceptable bandwidth of ome
@@ -599,16 +578,6 @@ function addMethod(instance) {
599
578
  peerConnection.createAnswer()
600
579
  .then(function (answer) {
601
580
 
602
- if (checkIOSVersion() >= 15) {
603
-
604
- const formatNumber = getFormatNumber(answer.sdp, 'H264');
605
-
606
- if (formatNumber > 0) {
607
-
608
- answer.sdp = removeFormat(answer.sdp, formatNumber);
609
- }
610
- }
611
-
612
581
  if (instance.connectionConfig.sdp && instance.connectionConfig.sdp.appendFmtp) {
613
582
 
614
583
  answer.sdp = appendFmtp(answer.sdp);
@@ -651,8 +620,6 @@ function addMethod(instance) {
651
620
 
652
621
  if (e.candidate && e.candidate.candidate) {
653
622
 
654
- console.info(logHeader, 'Candidate Sent', '\n', e.candidate.candidate, '\n', e);
655
-
656
623
  sendMessage(instance.webSocket, {
657
624
  id: id,
658
625
  peer_id: peerId,
@@ -675,8 +642,6 @@ function addMethod(instance) {
675
642
  if (state === 'connected') {
676
643
 
677
644
  if (instance.callbacks.connected) {
678
-
679
- console.info(logHeader, 'Iceconnection Connected', e);
680
645
  instance.callbacks.connected(e);
681
646
  }
682
647
  }
@@ -684,7 +649,6 @@ function addMethod(instance) {
684
649
  if (state === 'failed' || state === 'disconnected' || state === 'closed') {
685
650
 
686
651
  if (instance.callbacks.connectionClosed) {
687
-
688
652
  console.error(logHeader, 'Iceconnection Closed', e);
689
653
  instance.callbacks.connectionClosed('ice', e);
690
654
  }
@@ -713,6 +677,49 @@ function addMethod(instance) {
713
677
  }
714
678
  }
715
679
 
680
+ function closePeerConnection() {
681
+ if (instance.peerConnection) {
682
+
683
+ // remove tracks from peer connection
684
+ instance.peerConnection.getSenders().forEach(function (sender) {
685
+ instance.peerConnection.removeTrack(sender);
686
+ });
687
+
688
+ instance.peerConnection.close();
689
+ instance.peerConnection = null;
690
+ delete instance.peerConnection;
691
+ }
692
+ }
693
+
694
+ function closeWebSocket() {
695
+
696
+ if (instance.webSocket) {
697
+
698
+ instance.webSocket.close();
699
+ instance.webSocket = null;
700
+ delete instance.webSocket;
701
+ }
702
+ }
703
+
704
+ function closeInputStream() {
705
+ // release video, audio stream
706
+ if (instance.inputStream) {
707
+
708
+ instance.inputStream.getTracks().forEach(track => {
709
+
710
+ track.stop();
711
+ instance.inputStream.removeTrack(track);
712
+ });
713
+
714
+ if (instance.videoElement) {
715
+ instance.videoElement.srcObject = null;
716
+ }
717
+
718
+ instance.inputStream = null;
719
+ delete instance.inputStream;
720
+ }
721
+ }
722
+
716
723
  // instance methods
717
724
  instance.attachMedia = function (videoElement) {
718
725
 
@@ -741,63 +748,39 @@ function addMethod(instance) {
741
748
  initWebSocket(connectionUrl);
742
749
  };
743
750
 
744
- instance.remove = function () {
745
-
746
- instance.removing = true;
751
+ instance.stopStreaming = function () {
747
752
 
748
- // first release peer connection with ome
749
- if (instance.peerConnection) {
753
+ instance.webSocketClosedByUser = true;
750
754
 
751
- // remove tracks from peer connection
752
- instance.peerConnection.getSenders().forEach(function (sender) {
753
- instance.peerConnection.removeTrack(sender);
754
- });
755
-
756
- instance.peerConnection.close();
757
- instance.peerConnection = null;
758
- delete instance.peerConnection;
759
- }
760
-
761
- // release video, audio stream
762
- if (instance.stream) {
763
-
764
- instance.stream.getTracks().forEach(track => {
765
-
766
- track.stop();
767
- instance.stream.removeTrack(track);
768
- });
769
-
770
- if (instance.videoElement) {
771
- instance.videoElement.srcObject = null;
772
- }
773
-
774
- instance.stream = null;
775
- delete instance.stream;
776
- }
755
+ closeWebSocket();
756
+ closePeerConnection();
757
+ };
777
758
 
778
- // release websocket
779
- if (instance.webSocket) {
759
+ instance.remove = function () {
780
760
 
781
- instance.webSocket.close();
782
- instance.webSocket = null;
783
- delete instance.webSocket;
784
- }
761
+ instance.webSocketClosedByUser = true;
785
762
 
786
- instance.status = 'removed';
763
+ closeWebSocket();
764
+ closePeerConnection();
765
+ closeInputStream();
787
766
 
788
767
  console.info(logEventHeader, 'Removed');
789
768
 
790
769
  };
791
770
  }
792
771
 
772
+ OvenLiveKit.getVersion = function () {
773
+ return version;
774
+ }
775
+
793
776
  // static methods
794
777
  OvenLiveKit.create = function (options) {
795
778
 
796
- console.info(logEventHeader, 'Create WebRTC Input v1.0.2');
779
+ console.info(logEventHeader, 'Create WebRTC Input ' + version);
797
780
 
798
781
  let instance = {};
799
782
 
800
- instance.removing = false;
783
+ instance.webSocketClosedByUser = false;
801
784
 
802
785
  initConfig(instance, options);
803
786
  addMethod(instance);