ovenlivekit 1.0.2 → 1.0.3
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/.github/FUNDING.yml +2 -0
- package/dist/OvenLiveKit.js +1 -1
- package/dist/OvenLiveKit.min.js +1 -1
- package/dist/OvenLiveKit.min.js.map +1 -1
- package/package.json +31 -31
- package/src/OvenLiveKit.js +83 -16
package/dist/OvenLiveKit.js
CHANGED
|
@@ -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('\\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('\\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('\\n')\r\n}\r\n\r\nasync function getStreamForDeviceCheck() {\r\n\r\n // High resolution video constraints makes browser to get maximum resolution of video device.\r\n const constraints = {\r\n audio: { deviceId: undefined },\r\n video: { deviceId: undefined, width: 1920, height: 1080 }\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\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('\\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('\\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('\\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('\\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].replace('\\r', ''));\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] += '\\na=fmtp:' + payloads[i] + ' ' + fmtpStr;\r\n }\r\n }\r\n }\r\n }\r\n\r\n return lines.join('\\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 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 await getStreamForDeviceCheck();\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 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?");
|
|
30
30
|
|
|
31
31
|
/***/ })
|
|
32
32
|
|
package/dist/OvenLiveKit.min.js
CHANGED
|
@@ -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,
|
|
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})()}));
|
|
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('\\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('\\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('\\n')\r\n}\r\n\r\nasync function getStreamForDeviceCheck() {\r\n\r\n // High resolution video constraints makes browser to get maximum resolution of video device.\r\n const constraints = {\r\n audio: { deviceId: undefined },\r\n video: { deviceId: undefined, width: 1920, height: 1080 }\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\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('\\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('\\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('\\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('\\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].replace('\\r', ''));\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] += '\\na=fmtp:' + payloads[i] + ' ' + fmtpStr;\r\n }\r\n }\r\n }\r\n }\r\n\r\n return lines.join('\\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 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 await getStreamForDeviceCheck();\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","addMethod","instance","errorHandler","error","callbacks","appendFmtp","fmtpStr","connectionConfig","payloads","tokens","j","fmtpLineFound","attachMedia","videoElement","getUserMedia","constraints","video","deviceId","undefined","audio","console","info","mediaDevices","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","async","width","height","getStreamForDeviceCheck","deviceInfos","devices","deviceInfo","kind","label","audioinput","audiooutput","videoinput","other","gotDevices","enumerateDevices"],"sourceRoot":""}
|
|
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":""}
|
package/package.json
CHANGED
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "ovenlivekit",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "OvenLiveKit for Web is an open source JavaScript SDK suite for live streaming from web browsers to OvenMediaEngine.",
|
|
5
|
-
"main": "dist/OvenLiveKit.min.js",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"start": "webpack serve --open --config webpack.dev.js",
|
|
8
|
-
"watch": "webpack watch --config webpack.dev.js",
|
|
9
|
-
"build": "webpack --config webpack.prod.js"
|
|
10
|
-
},
|
|
11
|
-
"repository": {
|
|
12
|
-
"type": "git",
|
|
13
|
-
"url": "git+https://github.com/AirenSoft/OvenLiveKit-Web.git"
|
|
14
|
-
},
|
|
15
|
-
"keywords": [
|
|
16
|
-
"Sub-Second Latency Streaming",
|
|
17
|
-
"WebRTC",
|
|
18
|
-
"OvenMediaEngine",
|
|
19
|
-
"HTML5"
|
|
20
|
-
],
|
|
21
|
-
"author": "AirenSoft Co., Ltd.",
|
|
22
|
-
"license": "MIT",
|
|
23
|
-
"bugs": {
|
|
24
|
-
"url": "https://github.com/AirenSoft/OvenLiveKit-Web/issues"
|
|
25
|
-
},
|
|
26
|
-
"homepage": "https://github.com/AirenSoft/OvenLiveKit-Web#readme",
|
|
27
|
-
"devDependencies": {
|
|
28
|
-
"webpack": "^5.48.0",
|
|
29
|
-
"webpack-cli": "^4.7.2",
|
|
30
|
-
"webpack-dev-server": "^3.11.2"
|
|
31
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "ovenlivekit",
|
|
3
|
+
"version": "1.0.3",
|
|
4
|
+
"description": "OvenLiveKit for Web is an open source JavaScript SDK suite for live streaming from web browsers to OvenMediaEngine.",
|
|
5
|
+
"main": "dist/OvenLiveKit.min.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "webpack serve --open --config webpack.dev.js",
|
|
8
|
+
"watch": "webpack watch --config webpack.dev.js",
|
|
9
|
+
"build": "webpack --config webpack.prod.js"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/AirenSoft/OvenLiveKit-Web.git"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"Sub-Second Latency Streaming",
|
|
17
|
+
"WebRTC",
|
|
18
|
+
"OvenMediaEngine",
|
|
19
|
+
"HTML5"
|
|
20
|
+
],
|
|
21
|
+
"author": "AirenSoft Co., Ltd.",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/AirenSoft/OvenLiveKit-Web/issues"
|
|
25
|
+
},
|
|
26
|
+
"homepage": "https://github.com/AirenSoft/OvenLiveKit-Web#readme",
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"webpack": "^5.48.0",
|
|
29
|
+
"webpack-cli": "^4.7.2",
|
|
30
|
+
"webpack-dev-server": "^3.11.2"
|
|
31
|
+
}
|
|
32
32
|
}
|
package/src/OvenLiveKit.js
CHANGED
|
@@ -44,7 +44,7 @@ function checkIOSVersion() {
|
|
|
44
44
|
|
|
45
45
|
function getFormatNumber(sdp, format) {
|
|
46
46
|
|
|
47
|
-
const lines = sdp.split('\n');
|
|
47
|
+
const lines = sdp.split('\r\n');
|
|
48
48
|
let formatNumber = -1;
|
|
49
49
|
|
|
50
50
|
for (let i = 0; i < lines.length - 1; i++) {
|
|
@@ -63,7 +63,7 @@ function getFormatNumber(sdp, format) {
|
|
|
63
63
|
|
|
64
64
|
function removeFormat(sdp, formatNumber) {
|
|
65
65
|
let newLines = [];
|
|
66
|
-
let lines = sdp.split('\n');
|
|
66
|
+
let lines = sdp.split('\r\n');
|
|
67
67
|
|
|
68
68
|
for (let i = 0; i < lines.length; i++) {
|
|
69
69
|
|
|
@@ -76,25 +76,30 @@ function removeFormat(sdp, formatNumber) {
|
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
return newLines.join('\n')
|
|
79
|
+
return newLines.join('\r\n')
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
async function getStreamForDeviceCheck() {
|
|
82
|
+
async function getStreamForDeviceCheck(type) {
|
|
83
83
|
|
|
84
84
|
// High resolution video constraints makes browser to get maximum resolution of video device.
|
|
85
85
|
const constraints = {
|
|
86
|
-
audio: { deviceId: undefined },
|
|
87
|
-
video: { deviceId: undefined, width: 1920, height: 1080 }
|
|
88
86
|
};
|
|
89
87
|
|
|
88
|
+
if (type === 'both') {
|
|
89
|
+
constraints.audio = true;
|
|
90
|
+
constraints.video = true;
|
|
91
|
+
} else if (type === 'audio') {
|
|
92
|
+
constraints.audio = true;
|
|
93
|
+
} else if (type === 'video') {
|
|
94
|
+
constraints.video = true;
|
|
95
|
+
}
|
|
96
|
+
|
|
90
97
|
return await navigator.mediaDevices.getUserMedia(constraints);
|
|
91
98
|
}
|
|
92
99
|
|
|
93
100
|
async function getDevices() {
|
|
94
101
|
|
|
95
102
|
return await navigator.mediaDevices.enumerateDevices();
|
|
96
|
-
|
|
97
|
-
|
|
98
103
|
}
|
|
99
104
|
|
|
100
105
|
function gotDevices(deviceInfos) {
|
|
@@ -266,7 +271,7 @@ function addMethod(instance) {
|
|
|
266
271
|
// From https://webrtchacks.com/limit-webrtc-bandwidth-sdp/
|
|
267
272
|
function setBitrateLimit(sdp, media, bitrate) {
|
|
268
273
|
|
|
269
|
-
let lines = sdp.split('\n');
|
|
274
|
+
let lines = sdp.split('\r\n');
|
|
270
275
|
let line = -1;
|
|
271
276
|
|
|
272
277
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -294,7 +299,7 @@ function addMethod(instance) {
|
|
|
294
299
|
|
|
295
300
|
lines[line] = 'b=AS:' + bitrate;
|
|
296
301
|
|
|
297
|
-
return lines.join('\n');
|
|
302
|
+
return lines.join('\r\n');
|
|
298
303
|
}
|
|
299
304
|
|
|
300
305
|
// Add a new b line
|
|
@@ -303,7 +308,7 @@ function addMethod(instance) {
|
|
|
303
308
|
newLines.push('b=AS:' + bitrate)
|
|
304
309
|
newLines = newLines.concat(lines.slice(line, lines.length))
|
|
305
310
|
|
|
306
|
-
return newLines.join('\n')
|
|
311
|
+
return newLines.join('\r\n')
|
|
307
312
|
}
|
|
308
313
|
|
|
309
314
|
function initWebSocket(connectionUrl) {
|
|
@@ -381,7 +386,7 @@ function addMethod(instance) {
|
|
|
381
386
|
|
|
382
387
|
const fmtpStr = instance.connectionConfig.sdp.appendFmtp;
|
|
383
388
|
|
|
384
|
-
const lines = sdp.split('\n');
|
|
389
|
+
const lines = sdp.split('\r\n');
|
|
385
390
|
const payloads = [];
|
|
386
391
|
|
|
387
392
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -392,7 +397,7 @@ function addMethod(instance) {
|
|
|
392
397
|
|
|
393
398
|
for (let j = 3; j < tokens.length; j++) {
|
|
394
399
|
|
|
395
|
-
payloads.push(tokens[j]
|
|
400
|
+
payloads.push(tokens[j]);
|
|
396
401
|
}
|
|
397
402
|
|
|
398
403
|
break;
|
|
@@ -417,13 +422,47 @@ function addMethod(instance) {
|
|
|
417
422
|
|
|
418
423
|
if (lines[j].indexOf('a=rtpmap:' + payloads[i]) === 0) {
|
|
419
424
|
|
|
420
|
-
lines[j] += '\na=fmtp:' + payloads[i] + ' ' + fmtpStr;
|
|
425
|
+
lines[j] += '\r\na=fmtp:' + payloads[i] + ' ' + fmtpStr;
|
|
421
426
|
}
|
|
422
427
|
}
|
|
423
428
|
}
|
|
424
429
|
}
|
|
425
430
|
|
|
426
|
-
return lines.join('\n')
|
|
431
|
+
return lines.join('\r\n')
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
function appendOrientation(sdp) {
|
|
435
|
+
|
|
436
|
+
const lines = sdp.split('\r\n');
|
|
437
|
+
const payloads = [];
|
|
438
|
+
|
|
439
|
+
for (let i = 0; i < lines.length; i++) {
|
|
440
|
+
|
|
441
|
+
if (lines[i].indexOf('m=video') === 0) {
|
|
442
|
+
|
|
443
|
+
let tokens = lines[i].split(' ')
|
|
444
|
+
|
|
445
|
+
for (let j = 3; j < tokens.length; j++) {
|
|
446
|
+
|
|
447
|
+
payloads.push(tokens[j]);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
break;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
for (let i = 0; i < payloads.length; i++) {
|
|
455
|
+
|
|
456
|
+
for (let j = 0; j < lines.length; j++) {
|
|
457
|
+
|
|
458
|
+
if (lines[j].indexOf('a=rtpmap:' + payloads[i]) === 0) {
|
|
459
|
+
|
|
460
|
+
lines[j] += '\r\na=extmap:' + payloads[i] + ' urn:3gpp:video-orientation';
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
return lines.join('\r\n')
|
|
427
466
|
}
|
|
428
467
|
|
|
429
468
|
function createPeerConnection(id, peerId, offer, candidates, iceServers) {
|
|
@@ -552,6 +591,8 @@ function addMethod(instance) {
|
|
|
552
591
|
offer.sdp = appendFmtp(offer.sdp);
|
|
553
592
|
}
|
|
554
593
|
|
|
594
|
+
// offer.sdp = appendOrientation(offer.sdp);
|
|
595
|
+
|
|
555
596
|
peerConnection.setRemoteDescription(new RTCSessionDescription(offer))
|
|
556
597
|
.then(function () {
|
|
557
598
|
|
|
@@ -766,7 +807,33 @@ OvenLiveKit.create = function (options) {
|
|
|
766
807
|
|
|
767
808
|
OvenLiveKit.getDevices = async function () {
|
|
768
809
|
|
|
769
|
-
|
|
810
|
+
try {
|
|
811
|
+
// First check both audio and video sources are available.
|
|
812
|
+
await getStreamForDeviceCheck('both');
|
|
813
|
+
} catch (e) {
|
|
814
|
+
|
|
815
|
+
console.warn(logHeader, 'Can not find Video and Audio devices', e);
|
|
816
|
+
|
|
817
|
+
let videoFound = null;
|
|
818
|
+
let audioFound = null;
|
|
819
|
+
|
|
820
|
+
try {
|
|
821
|
+
videoFound = await getStreamForDeviceCheck('video');
|
|
822
|
+
} catch (e) {
|
|
823
|
+
console.warn(logHeader, 'Can not find Video devices', e);
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
try {
|
|
827
|
+
audioFound = await getStreamForDeviceCheck('audio');
|
|
828
|
+
} catch (e) {
|
|
829
|
+
console.warn(logHeader, 'Can not find Audio devices', e);
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
if (!videoFound && !audioFound) {
|
|
833
|
+
throw new Error('No input devices were found.');
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
|
|
770
837
|
const deviceInfos = await getDevices();
|
|
771
838
|
return gotDevices(deviceInfos)
|
|
772
839
|
};
|