ovenlivekit 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/FUNDING.yml +2 -0
- package/README.md +7 -4
- 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 +151 -101
package/README.md
CHANGED
|
@@ -40,7 +40,7 @@ import OvenLiveKit from 'ovenlivekit'
|
|
|
40
40
|
This is the simplest example of sending a device media stream such as a webcam to OvenMediaEngine's WebRTC Provider.
|
|
41
41
|
```JavaScript
|
|
42
42
|
// Initialize OvenLiveKit
|
|
43
|
-
|
|
43
|
+
const ovenLivekit = OvenLiveKit.create();
|
|
44
44
|
|
|
45
45
|
// Get media stream from user device
|
|
46
46
|
ovenLivekit.getUserMedia().then(function () {
|
|
@@ -104,7 +104,7 @@ var config = {
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
// Initialize ovenLivekit instance
|
|
107
|
-
|
|
107
|
+
const ovenLivekit = OvenLiveKit.create(config);
|
|
108
108
|
|
|
109
109
|
// Release all resources and destroy the instance
|
|
110
110
|
ovenLivekit.remove();
|
|
@@ -219,7 +219,7 @@ OvenLiveKit also provides APIs to control a media stream from a user device.
|
|
|
219
219
|
```
|
|
220
220
|
```JavaScript
|
|
221
221
|
// Create instance
|
|
222
|
-
|
|
222
|
+
const ovenLivekit = OvenLiveKit.create();
|
|
223
223
|
|
|
224
224
|
// Attaching video element for playing device stream
|
|
225
225
|
ovenLivekit.attachMedia(document.getElementById('myVideo'));
|
|
@@ -254,7 +254,7 @@ ovenLivekit.getUserMedia(constraints).then(function (stream) {
|
|
|
254
254
|
Congrats on getting the media stream from the user device and then ready to stream into OvenMediaEngine.
|
|
255
255
|
```JavaScript
|
|
256
256
|
// Create instance
|
|
257
|
-
|
|
257
|
+
const ovenLivekit = OvenLiveKit.create();
|
|
258
258
|
|
|
259
259
|
ovenLivekit.getUserMedia().then(function () {
|
|
260
260
|
|
|
@@ -293,6 +293,9 @@ ovenLivekit.getUserMedia().then(function () {
|
|
|
293
293
|
- String: String you want to append to a=fmtp of SDP.
|
|
294
294
|
- If set video format is appended to the a=fmtp sections of SDP.
|
|
295
295
|
|
|
296
|
+
#### `instance.stopStreaming()`
|
|
297
|
+
- Close peer connection and websocket associated with OvenMediaEngine.
|
|
298
|
+
|
|
296
299
|
## For more information
|
|
297
300
|
* [WebRTC Input in OvenPlayer Demo](https://demo.ovenplayer.com/demo_input.html)
|
|
298
301
|
* Test Player based on OvenPlayer.
|
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 version = '1.0.4';\r\nconst logHeader = 'OvenLiveKit.js :';\r\nconst logEventHeader = 'OvenLiveKit.js ====';\r\n\r\n// private methods\r\nfunction sendMessage(webSocket, message) {\r\n\r\n if (webSocket) {\r\n webSocket.send(JSON.stringify(message));\r\n }\r\n}\r\n\r\nfunction generateDomainFromUrl(url) {\r\n let result = '';\r\n let match;\r\n if (match = url.match(/^(?:wss?:\\/\\/)?(?:[^@\\n]+@)?(?:www\\.)?([^:\\/\\n\\?\\=]+)/im)) {\r\n result = match[1];\r\n }\r\n\r\n return result;\r\n}\r\n\r\nfunction findIp(string) {\r\n\r\n let result = '';\r\n let match;\r\n\r\n if (match = string.match(new RegExp('\\\\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\b', 'gi'))) {\r\n result = match[0];\r\n }\r\n\r\n return result;\r\n}\r\n\r\nfunction getFormatNumber(sdp, format) {\r\n\r\n const lines = sdp.split('\\r\\n');\r\n let formatNumber = -1;\r\n\r\n for (let i = 0; i < lines.length - 1; i++) {\r\n\r\n lines[i] = lines[i].toLowerCase();\r\n\r\n if (lines[i].indexOf('a=rtpmap') > -1 && lines[i].indexOf(format.toLowerCase()) > -1) {\r\n // parsing \"a=rtpmap:100 H264/90000\" line\r\n formatNumber = lines[i].split(' ')[0].split(':')[1];\r\n break;\r\n }\r\n }\r\n\r\n return formatNumber;\r\n}\r\n\r\nfunction removeFormat(sdp, formatNumber) {\r\n let newLines = [];\r\n let lines = sdp.split('\\r\\n');\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n\r\n if (lines[i].indexOf('m=video') === 0) {\r\n newLines.push(lines[i].replace(' ' + formatNumber + '', ''));\r\n } else if (lines[i].indexOf(formatNumber + '') > -1) {\r\n\r\n } else {\r\n newLines.push(lines[i]);\r\n }\r\n }\r\n\r\n return newLines.join('\\r\\n')\r\n}\r\n\r\nasync function getStreamForDeviceCheck(type) {\r\n\r\n // High resolution video constraints makes browser to get maximum resolution of video device.\r\n const constraints = {\r\n };\r\n\r\n if (type === 'both') {\r\n constraints.audio = true;\r\n constraints.video = true;\r\n } else if (type === 'audio') {\r\n constraints.audio = true;\r\n } else if (type === 'video') {\r\n constraints.video = true;\r\n }\r\n\r\n return await navigator.mediaDevices.getUserMedia(constraints);\r\n}\r\n\r\nasync function getDevices() {\r\n\r\n return await navigator.mediaDevices.enumerateDevices();\r\n}\r\n\r\nfunction gotDevices(deviceInfos) {\r\n\r\n let devices = {\r\n 'audioinput': [],\r\n 'audiooutput': [],\r\n 'videoinput': [],\r\n 'other': [],\r\n };\r\n\r\n for (let i = 0; i !== deviceInfos.length; ++i) {\r\n\r\n const deviceInfo = deviceInfos[i];\r\n\r\n let info = {};\r\n\r\n info.deviceId = deviceInfo.deviceId;\r\n\r\n if (deviceInfo.kind === 'audioinput') {\r\n\r\n info.label = deviceInfo.label || `microphone ${devices.audioinput.length + 1}`;\r\n devices.audioinput.push(info);\r\n } else if (deviceInfo.kind === 'audiooutput') {\r\n\r\n info.label = deviceInfo.label || `speaker ${devices.audiooutput.length + 1}`;\r\n devices.audiooutput.push(info);\r\n } else if (deviceInfo.kind === 'videoinput') {\r\n\r\n info.label = deviceInfo.label || `camera ${devices.videoinput.length + 1}`;\r\n devices.videoinput.push(info);\r\n } else {\r\n\r\n info.label = deviceInfo.label || `other ${devices.other.length + 1}`;\r\n devices.other.push(info);\r\n }\r\n }\r\n\r\n return devices;\r\n}\r\n\r\nfunction initConfig(instance, options) {\r\n\r\n instance.inputStream = null;\r\n instance.webSocket = null;\r\n instance.peerConnection = null;\r\n instance.connectionConfig = {};\r\n\r\n instance.videoElement = null;\r\n instance.connectionUrl = null;\r\n\r\n if (options && options.callbacks) {\r\n\r\n instance.callbacks = options.callbacks;\r\n } else {\r\n instance.callbacks = {};\r\n }\r\n}\r\n\r\nfunction addMethod(instance) {\r\n\r\n function errorHandler(error) {\r\n\r\n if (instance.callbacks.error) {\r\n\r\n instance.callbacks.error(error);\r\n }\r\n }\r\n\r\n function getUserMedia(constraints) {\r\n\r\n if (!constraints) {\r\n\r\n constraints = {\r\n video: {\r\n deviceId: undefined\r\n },\r\n audio: {\r\n deviceId: undefined\r\n }\r\n };\r\n }\r\n\r\n console.info(logHeader, 'Request Stream To Input Devices With Constraints', constraints);\r\n\r\n return navigator.mediaDevices.getUserMedia(constraints)\r\n .then(function (stream) {\r\n\r\n console.info(logHeader, 'Received Media Stream From Input Device', stream);\r\n\r\n instance.inputStream = stream;\r\n\r\n let elem = instance.videoElement;\r\n\r\n // Attach stream to video element when video element is provided.\r\n if (elem) {\r\n\r\n elem.srcObject = stream;\r\n\r\n elem.onloadedmetadata = function (e) {\r\n\r\n elem.play();\r\n };\r\n }\r\n\r\n return new Promise(function (resolve) {\r\n\r\n resolve(stream);\r\n });\r\n })\r\n .catch(function (error) {\r\n\r\n console.error(logHeader, 'Can\\'t Get Media Stream From Input Device', error);\r\n errorHandler(error);\r\n\r\n return new Promise(function (resolve, reject) {\r\n reject(error);\r\n });\r\n });\r\n }\r\n\r\n function getDisplayMedia(constraints) {\r\n\r\n if (!constraints) {\r\n constraints = {};\r\n }\r\n\r\n console.info(logHeader, 'Request Stream To Display With Constraints', constraints);\r\n\r\n return navigator.mediaDevices.getDisplayMedia(constraints)\r\n .then(function (stream) {\r\n\r\n console.info(logHeader, 'Received Media Stream From Display', stream);\r\n\r\n instance.inputStream = stream;\r\n\r\n let elem = instance.videoElement;\r\n\r\n // Attach stream to video element when video element is provided.\r\n if (elem) {\r\n\r\n elem.srcObject = stream;\r\n\r\n elem.onloadedmetadata = function (e) {\r\n\r\n elem.play();\r\n };\r\n }\r\n\r\n return new Promise(function (resolve) {\r\n\r\n resolve(stream);\r\n });\r\n })\r\n .catch(function (error) {\r\n\r\n console.error(logHeader, 'Can\\'t Get Media Stream From Display', error);\r\n errorHandler(error);\r\n\r\n return new Promise(function (resolve, reject) {\r\n reject(error);\r\n });\r\n });\r\n }\r\n\r\n // From https://webrtchacks.com/limit-webrtc-bandwidth-sdp/\r\n function setBitrateLimit(sdp, media, bitrate) {\r\n\r\n let lines = sdp.split('\\r\\n');\r\n let line = -1;\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n if (lines[i].indexOf('m=' + media) === 0) {\r\n line = i;\r\n break;\r\n }\r\n }\r\n if (line === -1) {\r\n // Could not find the m line for media\r\n return sdp;\r\n }\r\n\r\n // Pass the m line\r\n line++;\r\n\r\n // Skip i and c lines\r\n while (lines[line].indexOf('i=') === 0 || lines[line].indexOf('c=') === 0) {\r\n\r\n line++;\r\n }\r\n\r\n // If we're on a b line, replace it\r\n if (lines[line].indexOf('b') === 0) {\r\n\r\n lines[line] = 'b=AS:' + bitrate;\r\n\r\n return lines.join('\\r\\n');\r\n }\r\n\r\n // Add a new b line\r\n let newLines = lines.slice(0, line)\r\n\r\n newLines.push('b=AS:' + bitrate)\r\n newLines = newLines.concat(lines.slice(line, lines.length))\r\n\r\n return newLines.join('\\r\\n')\r\n }\r\n\r\n function initWebSocket(connectionUrl) {\r\n\r\n if (!connectionUrl) {\r\n errorHandler('connectionUrl is required');\r\n return;\r\n }\r\n\r\n instance.connectionUrl = connectionUrl;\r\n\r\n let webSocket = null;\r\n\r\n try {\r\n\r\n webSocket = new WebSocket(connectionUrl);\r\n } catch (error) {\r\n\r\n errorHandler(error);\r\n }\r\n\r\n\r\n instance.webSocket = webSocket;\r\n\r\n webSocket.onopen = function () {\r\n\r\n // Request offer at the first time.\r\n sendMessage(webSocket, {\r\n command: 'request_offer'\r\n });\r\n };\r\n\r\n webSocket.onmessage = function (e) {\r\n\r\n let message = JSON.parse(e.data);\r\n\r\n if (message.error) {\r\n console.error('webSocket.onmessage', message.error);\r\n errorHandler(message.error);\r\n }\r\n\r\n if (message.command === 'offer') {\r\n\r\n // OME returns offer. Start create peer connection.\r\n createPeerConnection(\r\n message.id,\r\n message.peer_id,\r\n message.sdp,\r\n message.candidates,\r\n message.ice_servers\r\n );\r\n }\r\n };\r\n\r\n webSocket.onerror = function (error) {\r\n\r\n console.error('webSocket.onerror', error);\r\n errorHandler(error);\r\n };\r\n\r\n webSocket.onclose = function (e) {\r\n\r\n if (!instance.webSocketClosedByUser) {\r\n\r\n if (instance.callbacks.connectionClosed) {\r\n instance.callbacks.connectionClosed('websocket', e);\r\n }\r\n }\r\n };\r\n\r\n }\r\n\r\n function appendFmtp(sdp) {\r\n\r\n const fmtpStr = instance.connectionConfig.sdp.appendFmtp;\r\n\r\n const lines = sdp.split('\\r\\n');\r\n const payloads = [];\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n\r\n if (lines[i].indexOf('m=video') === 0) {\r\n\r\n let tokens = lines[i].split(' ')\r\n\r\n for (let j = 3; j < tokens.length; j++) {\r\n\r\n payloads.push(tokens[j]);\r\n }\r\n\r\n break;\r\n }\r\n }\r\n\r\n for (let i = 0; i < payloads.length; i++) {\r\n\r\n let fmtpLineFound = false;\r\n\r\n for (let j = 0; j < lines.length; j++) {\r\n\r\n if (lines[j].indexOf('a=fmtp:' + payloads[i]) === 0) {\r\n fmtpLineFound = true;\r\n lines[j] += ';' + fmtpStr;\r\n }\r\n }\r\n\r\n if (!fmtpLineFound) {\r\n\r\n for (let j = 0; j < lines.length; j++) {\r\n\r\n if (lines[j].indexOf('a=rtpmap:' + payloads[i]) === 0) {\r\n\r\n lines[j] += '\\r\\na=fmtp:' + payloads[i] + ' ' + fmtpStr;\r\n }\r\n }\r\n }\r\n }\r\n\r\n return lines.join('\\r\\n')\r\n }\r\n\r\n function appendOrientation(sdp) {\r\n\r\n const lines = sdp.split('\\r\\n');\r\n const payloads = [];\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n\r\n if (lines[i].indexOf('m=video') === 0) {\r\n\r\n let tokens = lines[i].split(' ')\r\n\r\n for (let j = 3; j < tokens.length; j++) {\r\n\r\n payloads.push(tokens[j]);\r\n }\r\n\r\n break;\r\n }\r\n }\r\n\r\n for (let i = 0; i < payloads.length; i++) {\r\n\r\n for (let j = 0; j < lines.length; j++) {\r\n\r\n if (lines[j].indexOf('a=rtpmap:' + payloads[i]) === 0) {\r\n\r\n lines[j] += '\\r\\na=extmap:' + payloads[i] + ' urn:3gpp:video-orientation';\r\n }\r\n }\r\n }\r\n\r\n return lines.join('\\r\\n')\r\n }\r\n\r\n function createPeerConnection(id, peerId, offer, candidates, iceServers) {\r\n\r\n let peerConnectionConfig = {};\r\n\r\n if (instance.connectionConfig.iceServers) {\r\n\r\n // first priority using ice servers from local config.\r\n peerConnectionConfig.iceServers = instance.connectionConfig.iceServers;\r\n\r\n if (instance.connectionConfig.iceTransportPolicy) {\r\n\r\n peerConnectionConfig.iceTransportPolicy = instance.connectionConfig.iceTransportPolicy;\r\n }\r\n } else if (iceServers) {\r\n\r\n // second priority using ice servers from ome and force using TCP\r\n peerConnectionConfig.iceServers = [];\r\n\r\n for (let i = 0; i < iceServers.length; i++) {\r\n\r\n let iceServer = iceServers[i];\r\n\r\n let regIceServer = {};\r\n\r\n regIceServer.urls = iceServer.urls;\r\n\r\n let hasWebSocketUrl = false;\r\n let webSocketUrl = generateDomainFromUrl(instance.connectionUrl);\r\n\r\n for (let j = 0; j < regIceServer.urls.length; j++) {\r\n\r\n let serverUrl = regIceServer.urls[j];\r\n\r\n if (serverUrl.indexOf(webSocketUrl) > -1) {\r\n hasWebSocketUrl = true;\r\n break;\r\n }\r\n }\r\n\r\n if (!hasWebSocketUrl) {\r\n\r\n if (regIceServer.urls.length > 0) {\r\n\r\n let cloneIceServer = regIceServer.urls[0];\r\n let ip = findIp(cloneIceServer);\r\n\r\n if (webSocketUrl && ip) {\r\n regIceServer.urls.push(cloneIceServer.replace(ip, webSocketUrl));\r\n }\r\n }\r\n }\r\n\r\n regIceServer.username = iceServer.user_name;\r\n regIceServer.credential = iceServer.credential;\r\n\r\n peerConnectionConfig.iceServers.push(regIceServer);\r\n }\r\n\r\n peerConnectionConfig.iceTransportPolicy = 'relay';\r\n } else {\r\n // last priority using default ice servers.\r\n\r\n if (instance.iceTransportPolicy) {\r\n\r\n peerConnectionConfig.iceTransportPolicy = instance.iceTransportPolicy;\r\n }\r\n }\r\n\r\n let advancedSetting = {\r\n optional: [\r\n {\r\n googHighStartBitrate: {\r\n exact: !0\r\n }\r\n },\r\n {\r\n googPayloadPadding: {\r\n exact: !0\r\n }\r\n },\r\n {\r\n googScreencastMinBitrate: {\r\n exact: 500\r\n }\r\n },\r\n {\r\n enableDscp: {\r\n exact: true\r\n }\r\n }\r\n ]\r\n };\r\n\r\n console.info(logHeader, 'Create Peer Connection With Config', peerConnectionConfig);\r\n\r\n let peerConnection = new RTCPeerConnection(peerConnectionConfig);\r\n\r\n instance.peerConnection = peerConnection;\r\n\r\n // set local stream\r\n instance.inputStream.getTracks().forEach(function (track) {\r\n\r\n console.info(logHeader, 'Add Track To Peer Connection', track);\r\n peerConnection.addTrack(track, instance.inputStream);\r\n });\r\n\r\n if (instance.connectionConfig.maxVideoBitrate) {\r\n\r\n // if bandwith limit is set. modify sdp from ome to limit acceptable bandwidth of ome\r\n offer.sdp = setBitrateLimit(offer.sdp, 'video', instance.connectionConfig.maxVideoBitrate);\r\n }\r\n\r\n if (instance.connectionConfig.sdp && instance.connectionConfig.sdp.appendFmtp) {\r\n\r\n offer.sdp = appendFmtp(offer.sdp);\r\n }\r\n\r\n // offer.sdp = appendOrientation(offer.sdp);\r\n\r\n peerConnection.setRemoteDescription(new RTCSessionDescription(offer))\r\n .then(function () {\r\n\r\n peerConnection.createAnswer()\r\n .then(function (answer) {\r\n\r\n if (instance.connectionConfig.sdp && instance.connectionConfig.sdp.appendFmtp) {\r\n\r\n answer.sdp = appendFmtp(answer.sdp);\r\n }\r\n\r\n peerConnection.setLocalDescription(answer)\r\n .then(function () {\r\n\r\n sendMessage(instance.webSocket, {\r\n id: id,\r\n peer_id: peerId,\r\n command: 'answer',\r\n sdp: answer\r\n });\r\n })\r\n .catch(function (error) {\r\n\r\n console.error('peerConnection.setLocalDescription', error);\r\n errorHandler(error);\r\n });\r\n })\r\n .catch(function (error) {\r\n\r\n console.error('peerConnection.createAnswer', error);\r\n errorHandler(error);\r\n });\r\n })\r\n .catch(function (error) {\r\n\r\n console.error('peerConnection.setRemoteDescription', error);\r\n errorHandler(error);\r\n });\r\n\r\n if (candidates) {\r\n\r\n addIceCandidate(peerConnection, candidates);\r\n }\r\n\r\n peerConnection.onicecandidate = function (e) {\r\n\r\n if (e.candidate && e.candidate.candidate) {\r\n\r\n sendMessage(instance.webSocket, {\r\n id: id,\r\n peer_id: peerId,\r\n command: 'candidate',\r\n candidates: [e.candidate]\r\n });\r\n }\r\n };\r\n\r\n peerConnection.oniceconnectionstatechange = function (e) {\r\n\r\n let state = peerConnection.iceConnectionState;\r\n\r\n if (instance.callbacks.iceStateChange) {\r\n\r\n console.info(logHeader, 'ICE State', '[' + state + ']');\r\n instance.callbacks.iceStateChange(state);\r\n }\r\n\r\n if (state === 'connected') {\r\n\r\n if (instance.callbacks.connected) {\r\n instance.callbacks.connected(e);\r\n }\r\n }\r\n\r\n if (state === 'failed' || state === 'disconnected' || state === 'closed') {\r\n\r\n if (instance.callbacks.connectionClosed) {\r\n console.error(logHeader, 'Iceconnection Closed', e);\r\n instance.callbacks.connectionClosed('ice', e);\r\n }\r\n }\r\n }\r\n }\r\n\r\n function addIceCandidate(peerConnection, candidates) {\r\n\r\n for (let i = 0; i < candidates.length; i++) {\r\n\r\n if (candidates[i] && candidates[i].candidate) {\r\n\r\n let basicCandidate = candidates[i];\r\n\r\n peerConnection.addIceCandidate(new RTCIceCandidate(basicCandidate))\r\n .then(function () {\r\n\r\n })\r\n .catch(function (error) {\r\n\r\n console.error('peerConnection.addIceCandidate', error);\r\n errorHandler(error);\r\n });\r\n }\r\n }\r\n }\r\n\r\n function closePeerConnection() {\r\n if (instance.peerConnection) {\r\n\r\n // remove tracks from peer connection\r\n instance.peerConnection.getSenders().forEach(function (sender) {\r\n instance.peerConnection.removeTrack(sender);\r\n });\r\n\r\n instance.peerConnection.close();\r\n instance.peerConnection = null;\r\n delete instance.peerConnection;\r\n }\r\n }\r\n\r\n function closeWebSocket() {\r\n\r\n if (instance.webSocket) {\r\n\r\n instance.webSocket.close();\r\n instance.webSocket = null;\r\n delete instance.webSocket;\r\n }\r\n }\r\n\r\n function closeInputStream() {\r\n // release video, audio stream\r\n if (instance.inputStream) {\r\n\r\n instance.inputStream.getTracks().forEach(track => {\r\n\r\n track.stop();\r\n instance.inputStream.removeTrack(track);\r\n });\r\n\r\n if (instance.videoElement) {\r\n instance.videoElement.srcObject = null;\r\n }\r\n\r\n instance.inputStream = null;\r\n delete instance.inputStream;\r\n }\r\n }\r\n\r\n // instance methods\r\n instance.attachMedia = function (videoElement) {\r\n\r\n instance.videoElement = videoElement;\r\n };\r\n\r\n instance.getUserMedia = function (constraints) {\r\n\r\n return getUserMedia(constraints);\r\n };\r\n\r\n instance.getDisplayMedia = function (constraints) {\r\n\r\n return getDisplayMedia(constraints);\r\n };\r\n\r\n instance.startStreaming = function (connectionUrl, connectionConfig) {\r\n\r\n console.info(logEventHeader, 'Start Streaming');\r\n\r\n if (connectionConfig) {\r\n\r\n instance.connectionConfig = connectionConfig;\r\n }\r\n\r\n initWebSocket(connectionUrl);\r\n };\r\n\r\n instance.stopStreaming = function () {\r\n\r\n instance.webSocketClosedByUser = true;\r\n\r\n closeWebSocket();\r\n closePeerConnection();\r\n };\r\n\r\n instance.remove = function () {\r\n\r\n instance.webSocketClosedByUser = true;\r\n\r\n closeWebSocket();\r\n closePeerConnection();\r\n closeInputStream();\r\n\r\n console.info(logEventHeader, 'Removed');\r\n\r\n };\r\n}\r\n\r\nOvenLiveKit.getVersion = function () {\r\n return version;\r\n}\r\n\r\n// static methods\r\nOvenLiveKit.create = function (options) {\r\n\r\n console.info(logEventHeader, 'Create WebRTC Input ' + version);\r\n\r\n let instance = {};\r\n\r\n instance.webSocketClosedByUser = false;\r\n\r\n initConfig(instance, options);\r\n addMethod(instance);\r\n\r\n return instance;\r\n};\r\n\r\nOvenLiveKit.getDevices = async function () {\r\n\r\n try {\r\n // First check both audio and video sources are available.\r\n await getStreamForDeviceCheck('both');\r\n } catch (e) {\r\n\r\n console.warn(logHeader, 'Can not find Video and Audio devices', e);\r\n\r\n let videoFound = null;\r\n let audioFound = null;\r\n\r\n try {\r\n videoFound = await getStreamForDeviceCheck('video');\r\n } catch (e) {\r\n console.warn(logHeader, 'Can not find Video devices', e);\r\n }\r\n\r\n try {\r\n audioFound = await getStreamForDeviceCheck('audio');\r\n } catch (e) {\r\n console.warn(logHeader, 'Can not find Audio devices', e);\r\n }\r\n\r\n if (!videoFound && !audioFound) {\r\n throw new Error('No input devices were found.');\r\n }\r\n }\r\n\r\n const deviceInfos = await getDevices();\r\n return gotDevices(deviceInfos)\r\n};\r\n\r\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (OvenLiveKit);\n\n//# sourceURL=webpack://OvenLiveKit/./src/OvenLiveKit.js?");
|
|
30
30
|
|
|
31
31
|
/***/ })
|
|
32
32
|
|
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:()=>d});const o={},t="OvenLiveKit.js :",i="OvenLiveKit.js ====";function c(e,n){e&&e.send(JSON.stringify(n))}function r(e){let n,o="";return(n=e.match(/^(?:wss?:\/\/)?(?:[^@\n]+@)?(?:www\.)?([^:\/\n\?\=]+)/im))&&(o=n[1]),o}function a(e){let n,o="";return(n=e.match(new RegExp("\\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b","gi")))&&(o=n[0]),o}async function l(e){const n={};return"both"===e?(n.audio=!0,n.video=!0):"audio"===e?n.audio=!0:"video"===e&&(n.video=!0),await navigator.mediaDevices.getUserMedia(n)}function s(e){function n(n){e.callbacks.error&&e.callbacks.error(n)}function o(n){const o=e.connectionConfig.sdp.appendFmtp,t=n.split("\r\n"),i=[];for(let e=0;e<t.length;e++)if(0===t[e].indexOf("m=video")){let n=t[e].split(" ");for(let e=3;e<n.length;e++)i.push(n[e]);break}for(let e=0;e<i.length;e++){let n=!1;for(let c=0;c<t.length;c++)0===t[c].indexOf("a=fmtp:"+i[e])&&(n=!0,t[c]+=";"+o);if(!n)for(let n=0;n<t.length;n++)0===t[n].indexOf("a=rtpmap:"+i[e])&&(t[n]+="\r\na=fmtp:"+i[e]+" "+o)}return t.join("\r\n")}function l(){e.peerConnection&&(e.peerConnection.getSenders().forEach((function(n){e.peerConnection.removeTrack(n)})),e.peerConnection.close(),e.peerConnection=null,delete e.peerConnection)}function s(){e.webSocket&&(e.webSocket.close(),e.webSocket=null,delete e.webSocket)}e.attachMedia=function(n){e.videoElement=n},e.getUserMedia=function(o){return function(o){return o||(o={video:{deviceId:void 0},audio:{deviceId:void 0}}),console.info(t,"Request Stream To Input Devices With Constraints",o),navigator.mediaDevices.getUserMedia(o).then((function(n){console.info(t,"Received Media Stream From Input Device",n),e.inputStream=n;let o=e.videoElement;return o&&(o.srcObject=n,o.onloadedmetadata=function(e){o.play()}),new Promise((function(e){e(n)}))})).catch((function(e){return console.error(t,"Can't Get Media Stream From Input Device",e),n(e),new Promise((function(n,o){o(e)}))}))}(o)},e.getDisplayMedia=function(o){return function(o){return o||(o={}),console.info(t,"Request Stream To Display With Constraints",o),navigator.mediaDevices.getDisplayMedia(o).then((function(n){console.info(t,"Received Media Stream From Display",n),e.inputStream=n;let o=e.videoElement;return o&&(o.srcObject=n,o.onloadedmetadata=function(e){o.play()}),new Promise((function(e){e(n)}))})).catch((function(e){return console.error(t,"Can't Get Media Stream From Display",e),n(e),new Promise((function(n,o){o(e)}))}))}(o)},e.startStreaming=function(l,s){console.info(i,"Start Streaming"),s&&(e.connectionConfig=s),function(i){if(!i)return void n("connectionUrl is required");e.connectionUrl=i;let l=null;try{l=new WebSocket(i)}catch(e){n(e)}e.webSocket=l,l.onopen=function(){c(l,{command:"request_offer"})},l.onmessage=function(i){let l=JSON.parse(i.data);l.error&&(console.error("webSocket.onmessage",l.error),n(l.error)),"offer"===l.command&&function(i,l,s,d,u){let f={};if(e.connectionConfig.iceServers)f.iceServers=e.connectionConfig.iceServers,e.connectionConfig.iceTransportPolicy&&(f.iceTransportPolicy=e.connectionConfig.iceTransportPolicy);else if(u){f.iceServers=[];for(let n=0;n<u.length;n++){let o=u[n],t={};t.urls=o.urls;let i=!1,c=r(e.connectionUrl);for(let e=0;e<t.urls.length;e++)if(t.urls[e].indexOf(c)>-1){i=!0;break}if(!i&&t.urls.length>0){let e=t.urls[0],n=a(e);c&&n&&t.urls.push(e.replace(n,c))}t.username=o.user_name,t.credential=o.credential,f.iceServers.push(t)}f.iceTransportPolicy="relay"}else e.iceTransportPolicy&&(f.iceTransportPolicy=e.iceTransportPolicy);console.info(t,"Create Peer Connection With Config",f);let p=new RTCPeerConnection(f);e.peerConnection=p,e.inputStream.getTracks().forEach((function(n){console.info(t,"Add Track To Peer Connection",n),p.addTrack(n,e.inputStream)})),e.connectionConfig.maxVideoBitrate&&(s.sdp=function(e,n,o){let t=e.split("\r\n"),i=-1;for(let e=0;e<t.length;e++)if(0===t[e].indexOf("m=video")){i=e;break}if(-1===i)return e;for(i++;0===t[i].indexOf("i=")||0===t[i].indexOf("c=");)i++;if(0===t[i].indexOf("b"))return t[i]="b=AS:"+o,t.join("\r\n");let c=t.slice(0,i);return c.push("b=AS:"+o),c=c.concat(t.slice(i,t.length)),c.join("\r\n")}(s.sdp,0,e.connectionConfig.maxVideoBitrate)),e.connectionConfig.sdp&&e.connectionConfig.sdp.appendFmtp&&(s.sdp=o(s.sdp)),p.setRemoteDescription(new RTCSessionDescription(s)).then((function(){p.createAnswer().then((function(t){e.connectionConfig.sdp&&e.connectionConfig.sdp.appendFmtp&&(t.sdp=o(t.sdp)),p.setLocalDescription(t).then((function(){c(e.webSocket,{id:i,peer_id:l,command:"answer",sdp:t})})).catch((function(e){console.error("peerConnection.setLocalDescription",e),n(e)}))})).catch((function(e){console.error("peerConnection.createAnswer",e),n(e)}))})).catch((function(e){console.error("peerConnection.setRemoteDescription",e),n(e)})),d&&function(e,o){for(let t=0;t<o.length;t++)if(o[t]&&o[t].candidate){let i=o[t];e.addIceCandidate(new RTCIceCandidate(i)).then((function(){})).catch((function(e){console.error("peerConnection.addIceCandidate",e),n(e)}))}}(p,d),p.onicecandidate=function(n){n.candidate&&n.candidate.candidate&&c(e.webSocket,{id:i,peer_id:l,command:"candidate",candidates:[n.candidate]})},p.oniceconnectionstatechange=function(n){let o=p.iceConnectionState;e.callbacks.iceStateChange&&(console.info(t,"ICE State","["+o+"]"),e.callbacks.iceStateChange(o)),"connected"===o&&e.callbacks.connected&&e.callbacks.connected(n),"failed"!==o&&"disconnected"!==o&&"closed"!==o||e.callbacks.connectionClosed&&(console.error(t,"Iceconnection Closed",n),e.callbacks.connectionClosed("ice",n))}}(l.id,l.peer_id,l.sdp,l.candidates,l.ice_servers)},l.onerror=function(e){console.error("webSocket.onerror",e),n(e)},l.onclose=function(n){e.webSocketClosedByUser||e.callbacks.connectionClosed&&e.callbacks.connectionClosed("websocket",n)}}(l)},e.stopStreaming=function(){e.webSocketClosedByUser=!0,s(),l()},e.remove=function(){e.webSocketClosedByUser=!0,s(),l(),e.inputStream&&(e.inputStream.getTracks().forEach((n=>{n.stop(),e.inputStream.removeTrack(n)})),e.videoElement&&(e.videoElement.srcObject=null),e.inputStream=null,delete e.inputStream),console.info(i,"Removed")}}o.getVersion=function(){return"1.0.4"},o.create=function(e){console.info(i,"Create WebRTC Input 1.0.4");let n={webSocketClosedByUser:!1};return function(e,n){e.inputStream=null,e.webSocket=null,e.peerConnection=null,e.connectionConfig={},e.videoElement=null,e.connectionUrl=null,n&&n.callbacks?e.callbacks=n.callbacks:e.callbacks={}}(n,e),s(n),n},o.getDevices=async function(){try{await l("both")}catch(e){console.warn(t,"Can not find Video and Audio devices",e);let n=null,o=null;try{n=await l("video")}catch(e){console.warn(t,"Can not find Video devices",e)}try{o=await l("audio")}catch(e){console.warn(t,"Can not find Audio devices",e)}if(!n&&!o)throw new Error("No input devices were found.")}return function(e){let n={audioinput:[],audiooutput:[],videoinput:[],other:[]};for(let o=0;o!==e.length;++o){const t=e[o];let i={};i.deviceId=t.deviceId,"audioinput"===t.kind?(i.label=t.label||`microphone ${n.audioinput.length+1}`,n.audioinput.push(i)):"audiooutput"===t.kind?(i.label=t.label||`speaker ${n.audiooutput.length+1}`,n.audiooutput.push(i)):"videoinput"===t.kind?(i.label=t.label||`camera ${n.videoinput.length+1}`,n.videoinput.push(i)):(i.label=t.label||`other ${n.other.length+1}`,n.other.push(i))}return n}(await async function(){return await navigator.mediaDevices.enumerateDevices()}())};const d=o;return n.default})()}));
|
|
2
2
|
//# sourceMappingURL=OvenLiveKit.min.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OvenLiveKit.min.js","mappings":"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","sources":["webpack://OvenLiveKit/webpack/universalModuleDefinition","webpack://OvenLiveKit/webpack/bootstrap","webpack://OvenLiveKit/webpack/runtime/define property getters","webpack://OvenLiveKit/webpack/runtime/hasOwnProperty shorthand","webpack://OvenLiveKit/./src/OvenLiveKit.js"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"OvenLiveKit\"] = factory();\n\telse\n\t\troot[\"OvenLiveKit\"] = factory();\n})(self, function() {\nreturn ","// The require scope\nvar __webpack_require__ = {};\n\n","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","const OvenLiveKit = {};\r\n\r\nconst logHeader = 'OvenLiveKit.js :';\r\nconst logEventHeader = 'OvenLiveKit.js ====';\r\n\r\n// private methods\r\nfunction sendMessage(webSocket, message) {\r\n\r\n if (webSocket) {\r\n webSocket.send(JSON.stringify(message));\r\n }\r\n}\r\n\r\nfunction generateDomainFromUrl(url) {\r\n let result = '';\r\n let match;\r\n if (match = url.match(/^(?:wss?:\\/\\/)?(?:[^@\\n]+@)?(?:www\\.)?([^:\\/\\n\\?\\=]+)/im)) {\r\n result = match[1];\r\n }\r\n\r\n return result;\r\n}\r\n\r\nfunction findIp(string) {\r\n\r\n let result = '';\r\n let match;\r\n\r\n if (match = string.match(new RegExp('\\\\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\b', 'gi'))) {\r\n result = match[0];\r\n }\r\n\r\n return result;\r\n}\r\n\r\nfunction checkIOSVersion() {\r\n var agent = window.navigator.userAgent,\r\n start = agent.indexOf('OS ');\r\n if ((agent.indexOf('iPhone') > -1 || agent.indexOf('iPad') > -1) && start > -1) {\r\n return window.Number(agent.substr(start + 3, 3).replace('_', '.'));\r\n }\r\n return 0;\r\n}\r\n\r\nfunction getFormatNumber(sdp, format) {\r\n\r\n const lines = sdp.split('\\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 version = '1.0.4';\r\nconst logHeader = 'OvenLiveKit.js :';\r\nconst logEventHeader = 'OvenLiveKit.js ====';\r\n\r\n// private methods\r\nfunction sendMessage(webSocket, message) {\r\n\r\n if (webSocket) {\r\n webSocket.send(JSON.stringify(message));\r\n }\r\n}\r\n\r\nfunction generateDomainFromUrl(url) {\r\n let result = '';\r\n let match;\r\n if (match = url.match(/^(?:wss?:\\/\\/)?(?:[^@\\n]+@)?(?:www\\.)?([^:\\/\\n\\?\\=]+)/im)) {\r\n result = match[1];\r\n }\r\n\r\n return result;\r\n}\r\n\r\nfunction findIp(string) {\r\n\r\n let result = '';\r\n let match;\r\n\r\n if (match = string.match(new RegExp('\\\\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\b', 'gi'))) {\r\n result = match[0];\r\n }\r\n\r\n return result;\r\n}\r\n\r\nfunction getFormatNumber(sdp, format) {\r\n\r\n const lines = sdp.split('\\r\\n');\r\n let formatNumber = -1;\r\n\r\n for (let i = 0; i < lines.length - 1; i++) {\r\n\r\n lines[i] = lines[i].toLowerCase();\r\n\r\n if (lines[i].indexOf('a=rtpmap') > -1 && lines[i].indexOf(format.toLowerCase()) > -1) {\r\n // parsing \"a=rtpmap:100 H264/90000\" line\r\n formatNumber = lines[i].split(' ')[0].split(':')[1];\r\n break;\r\n }\r\n }\r\n\r\n return formatNumber;\r\n}\r\n\r\nfunction removeFormat(sdp, formatNumber) {\r\n let newLines = [];\r\n let lines = sdp.split('\\r\\n');\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n\r\n if (lines[i].indexOf('m=video') === 0) {\r\n newLines.push(lines[i].replace(' ' + formatNumber + '', ''));\r\n } else if (lines[i].indexOf(formatNumber + '') > -1) {\r\n\r\n } else {\r\n newLines.push(lines[i]);\r\n }\r\n }\r\n\r\n return newLines.join('\\r\\n')\r\n}\r\n\r\nasync function getStreamForDeviceCheck(type) {\r\n\r\n // High resolution video constraints makes browser to get maximum resolution of video device.\r\n const constraints = {\r\n };\r\n\r\n if (type === 'both') {\r\n constraints.audio = true;\r\n constraints.video = true;\r\n } else if (type === 'audio') {\r\n constraints.audio = true;\r\n } else if (type === 'video') {\r\n constraints.video = true;\r\n }\r\n\r\n return await navigator.mediaDevices.getUserMedia(constraints);\r\n}\r\n\r\nasync function getDevices() {\r\n\r\n return await navigator.mediaDevices.enumerateDevices();\r\n}\r\n\r\nfunction gotDevices(deviceInfos) {\r\n\r\n let devices = {\r\n 'audioinput': [],\r\n 'audiooutput': [],\r\n 'videoinput': [],\r\n 'other': [],\r\n };\r\n\r\n for (let i = 0; i !== deviceInfos.length; ++i) {\r\n\r\n const deviceInfo = deviceInfos[i];\r\n\r\n let info = {};\r\n\r\n info.deviceId = deviceInfo.deviceId;\r\n\r\n if (deviceInfo.kind === 'audioinput') {\r\n\r\n info.label = deviceInfo.label || `microphone ${devices.audioinput.length + 1}`;\r\n devices.audioinput.push(info);\r\n } else if (deviceInfo.kind === 'audiooutput') {\r\n\r\n info.label = deviceInfo.label || `speaker ${devices.audiooutput.length + 1}`;\r\n devices.audiooutput.push(info);\r\n } else if (deviceInfo.kind === 'videoinput') {\r\n\r\n info.label = deviceInfo.label || `camera ${devices.videoinput.length + 1}`;\r\n devices.videoinput.push(info);\r\n } else {\r\n\r\n info.label = deviceInfo.label || `other ${devices.other.length + 1}`;\r\n devices.other.push(info);\r\n }\r\n }\r\n\r\n return devices;\r\n}\r\n\r\nfunction initConfig(instance, options) {\r\n\r\n instance.inputStream = null;\r\n instance.webSocket = null;\r\n instance.peerConnection = null;\r\n instance.connectionConfig = {};\r\n\r\n instance.videoElement = null;\r\n instance.connectionUrl = null;\r\n\r\n if (options && options.callbacks) {\r\n\r\n instance.callbacks = options.callbacks;\r\n } else {\r\n instance.callbacks = {};\r\n }\r\n}\r\n\r\nfunction addMethod(instance) {\r\n\r\n function errorHandler(error) {\r\n\r\n if (instance.callbacks.error) {\r\n\r\n instance.callbacks.error(error);\r\n }\r\n }\r\n\r\n function getUserMedia(constraints) {\r\n\r\n if (!constraints) {\r\n\r\n constraints = {\r\n video: {\r\n deviceId: undefined\r\n },\r\n audio: {\r\n deviceId: undefined\r\n }\r\n };\r\n }\r\n\r\n console.info(logHeader, 'Request Stream To Input Devices With Constraints', constraints);\r\n\r\n return navigator.mediaDevices.getUserMedia(constraints)\r\n .then(function (stream) {\r\n\r\n console.info(logHeader, 'Received Media Stream From Input Device', stream);\r\n\r\n instance.inputStream = stream;\r\n\r\n let elem = instance.videoElement;\r\n\r\n // Attach stream to video element when video element is provided.\r\n if (elem) {\r\n\r\n elem.srcObject = stream;\r\n\r\n elem.onloadedmetadata = function (e) {\r\n\r\n elem.play();\r\n };\r\n }\r\n\r\n return new Promise(function (resolve) {\r\n\r\n resolve(stream);\r\n });\r\n })\r\n .catch(function (error) {\r\n\r\n console.error(logHeader, 'Can\\'t Get Media Stream From Input Device', error);\r\n errorHandler(error);\r\n\r\n return new Promise(function (resolve, reject) {\r\n reject(error);\r\n });\r\n });\r\n }\r\n\r\n function getDisplayMedia(constraints) {\r\n\r\n if (!constraints) {\r\n constraints = {};\r\n }\r\n\r\n console.info(logHeader, 'Request Stream To Display With Constraints', constraints);\r\n\r\n return navigator.mediaDevices.getDisplayMedia(constraints)\r\n .then(function (stream) {\r\n\r\n console.info(logHeader, 'Received Media Stream From Display', stream);\r\n\r\n instance.inputStream = stream;\r\n\r\n let elem = instance.videoElement;\r\n\r\n // Attach stream to video element when video element is provided.\r\n if (elem) {\r\n\r\n elem.srcObject = stream;\r\n\r\n elem.onloadedmetadata = function (e) {\r\n\r\n elem.play();\r\n };\r\n }\r\n\r\n return new Promise(function (resolve) {\r\n\r\n resolve(stream);\r\n });\r\n })\r\n .catch(function (error) {\r\n\r\n console.error(logHeader, 'Can\\'t Get Media Stream From Display', error);\r\n errorHandler(error);\r\n\r\n return new Promise(function (resolve, reject) {\r\n reject(error);\r\n });\r\n });\r\n }\r\n\r\n // From https://webrtchacks.com/limit-webrtc-bandwidth-sdp/\r\n function setBitrateLimit(sdp, media, bitrate) {\r\n\r\n let lines = sdp.split('\\r\\n');\r\n let line = -1;\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n if (lines[i].indexOf('m=' + media) === 0) {\r\n line = i;\r\n break;\r\n }\r\n }\r\n if (line === -1) {\r\n // Could not find the m line for media\r\n return sdp;\r\n }\r\n\r\n // Pass the m line\r\n line++;\r\n\r\n // Skip i and c lines\r\n while (lines[line].indexOf('i=') === 0 || lines[line].indexOf('c=') === 0) {\r\n\r\n line++;\r\n }\r\n\r\n // If we're on a b line, replace it\r\n if (lines[line].indexOf('b') === 0) {\r\n\r\n lines[line] = 'b=AS:' + bitrate;\r\n\r\n return lines.join('\\r\\n');\r\n }\r\n\r\n // Add a new b line\r\n let newLines = lines.slice(0, line)\r\n\r\n newLines.push('b=AS:' + bitrate)\r\n newLines = newLines.concat(lines.slice(line, lines.length))\r\n\r\n return newLines.join('\\r\\n')\r\n }\r\n\r\n function initWebSocket(connectionUrl) {\r\n\r\n if (!connectionUrl) {\r\n errorHandler('connectionUrl is required');\r\n return;\r\n }\r\n\r\n instance.connectionUrl = connectionUrl;\r\n\r\n let webSocket = null;\r\n\r\n try {\r\n\r\n webSocket = new WebSocket(connectionUrl);\r\n } catch (error) {\r\n\r\n errorHandler(error);\r\n }\r\n\r\n\r\n instance.webSocket = webSocket;\r\n\r\n webSocket.onopen = function () {\r\n\r\n // Request offer at the first time.\r\n sendMessage(webSocket, {\r\n command: 'request_offer'\r\n });\r\n };\r\n\r\n webSocket.onmessage = function (e) {\r\n\r\n let message = JSON.parse(e.data);\r\n\r\n if (message.error) {\r\n console.error('webSocket.onmessage', message.error);\r\n errorHandler(message.error);\r\n }\r\n\r\n if (message.command === 'offer') {\r\n\r\n // OME returns offer. Start create peer connection.\r\n createPeerConnection(\r\n message.id,\r\n message.peer_id,\r\n message.sdp,\r\n message.candidates,\r\n message.ice_servers\r\n );\r\n }\r\n };\r\n\r\n webSocket.onerror = function (error) {\r\n\r\n console.error('webSocket.onerror', error);\r\n errorHandler(error);\r\n };\r\n\r\n webSocket.onclose = function (e) {\r\n\r\n if (!instance.webSocketClosedByUser) {\r\n\r\n if (instance.callbacks.connectionClosed) {\r\n instance.callbacks.connectionClosed('websocket', e);\r\n }\r\n }\r\n };\r\n\r\n }\r\n\r\n function appendFmtp(sdp) {\r\n\r\n const fmtpStr = instance.connectionConfig.sdp.appendFmtp;\r\n\r\n const lines = sdp.split('\\r\\n');\r\n const payloads = [];\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n\r\n if (lines[i].indexOf('m=video') === 0) {\r\n\r\n let tokens = lines[i].split(' ')\r\n\r\n for (let j = 3; j < tokens.length; j++) {\r\n\r\n payloads.push(tokens[j]);\r\n }\r\n\r\n break;\r\n }\r\n }\r\n\r\n for (let i = 0; i < payloads.length; i++) {\r\n\r\n let fmtpLineFound = false;\r\n\r\n for (let j = 0; j < lines.length; j++) {\r\n\r\n if (lines[j].indexOf('a=fmtp:' + payloads[i]) === 0) {\r\n fmtpLineFound = true;\r\n lines[j] += ';' + fmtpStr;\r\n }\r\n }\r\n\r\n if (!fmtpLineFound) {\r\n\r\n for (let j = 0; j < lines.length; j++) {\r\n\r\n if (lines[j].indexOf('a=rtpmap:' + payloads[i]) === 0) {\r\n\r\n lines[j] += '\\r\\na=fmtp:' + payloads[i] + ' ' + fmtpStr;\r\n }\r\n }\r\n }\r\n }\r\n\r\n return lines.join('\\r\\n')\r\n }\r\n\r\n function appendOrientation(sdp) {\r\n\r\n const lines = sdp.split('\\r\\n');\r\n const payloads = [];\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n\r\n if (lines[i].indexOf('m=video') === 0) {\r\n\r\n let tokens = lines[i].split(' ')\r\n\r\n for (let j = 3; j < tokens.length; j++) {\r\n\r\n payloads.push(tokens[j]);\r\n }\r\n\r\n break;\r\n }\r\n }\r\n\r\n for (let i = 0; i < payloads.length; i++) {\r\n\r\n for (let j = 0; j < lines.length; j++) {\r\n\r\n if (lines[j].indexOf('a=rtpmap:' + payloads[i]) === 0) {\r\n\r\n lines[j] += '\\r\\na=extmap:' + payloads[i] + ' urn:3gpp:video-orientation';\r\n }\r\n }\r\n }\r\n\r\n return lines.join('\\r\\n')\r\n }\r\n\r\n function createPeerConnection(id, peerId, offer, candidates, iceServers) {\r\n\r\n let peerConnectionConfig = {};\r\n\r\n if (instance.connectionConfig.iceServers) {\r\n\r\n // first priority using ice servers from local config.\r\n peerConnectionConfig.iceServers = instance.connectionConfig.iceServers;\r\n\r\n if (instance.connectionConfig.iceTransportPolicy) {\r\n\r\n peerConnectionConfig.iceTransportPolicy = instance.connectionConfig.iceTransportPolicy;\r\n }\r\n } else if (iceServers) {\r\n\r\n // second priority using ice servers from ome and force using TCP\r\n peerConnectionConfig.iceServers = [];\r\n\r\n for (let i = 0; i < iceServers.length; i++) {\r\n\r\n let iceServer = iceServers[i];\r\n\r\n let regIceServer = {};\r\n\r\n regIceServer.urls = iceServer.urls;\r\n\r\n let hasWebSocketUrl = false;\r\n let webSocketUrl = generateDomainFromUrl(instance.connectionUrl);\r\n\r\n for (let j = 0; j < regIceServer.urls.length; j++) {\r\n\r\n let serverUrl = regIceServer.urls[j];\r\n\r\n if (serverUrl.indexOf(webSocketUrl) > -1) {\r\n hasWebSocketUrl = true;\r\n break;\r\n }\r\n }\r\n\r\n if (!hasWebSocketUrl) {\r\n\r\n if (regIceServer.urls.length > 0) {\r\n\r\n let cloneIceServer = regIceServer.urls[0];\r\n let ip = findIp(cloneIceServer);\r\n\r\n if (webSocketUrl && ip) {\r\n regIceServer.urls.push(cloneIceServer.replace(ip, webSocketUrl));\r\n }\r\n }\r\n }\r\n\r\n regIceServer.username = iceServer.user_name;\r\n regIceServer.credential = iceServer.credential;\r\n\r\n peerConnectionConfig.iceServers.push(regIceServer);\r\n }\r\n\r\n peerConnectionConfig.iceTransportPolicy = 'relay';\r\n } else {\r\n // last priority using default ice servers.\r\n\r\n if (instance.iceTransportPolicy) {\r\n\r\n peerConnectionConfig.iceTransportPolicy = instance.iceTransportPolicy;\r\n }\r\n }\r\n\r\n let advancedSetting = {\r\n optional: [\r\n {\r\n googHighStartBitrate: {\r\n exact: !0\r\n }\r\n },\r\n {\r\n googPayloadPadding: {\r\n exact: !0\r\n }\r\n },\r\n {\r\n googScreencastMinBitrate: {\r\n exact: 500\r\n }\r\n },\r\n {\r\n enableDscp: {\r\n exact: true\r\n }\r\n }\r\n ]\r\n };\r\n\r\n console.info(logHeader, 'Create Peer Connection With Config', peerConnectionConfig);\r\n\r\n let peerConnection = new RTCPeerConnection(peerConnectionConfig);\r\n\r\n instance.peerConnection = peerConnection;\r\n\r\n // set local stream\r\n instance.inputStream.getTracks().forEach(function (track) {\r\n\r\n console.info(logHeader, 'Add Track To Peer Connection', track);\r\n peerConnection.addTrack(track, instance.inputStream);\r\n });\r\n\r\n if (instance.connectionConfig.maxVideoBitrate) {\r\n\r\n // if bandwith limit is set. modify sdp from ome to limit acceptable bandwidth of ome\r\n offer.sdp = setBitrateLimit(offer.sdp, 'video', instance.connectionConfig.maxVideoBitrate);\r\n }\r\n\r\n if (instance.connectionConfig.sdp && instance.connectionConfig.sdp.appendFmtp) {\r\n\r\n offer.sdp = appendFmtp(offer.sdp);\r\n }\r\n\r\n // offer.sdp = appendOrientation(offer.sdp);\r\n\r\n peerConnection.setRemoteDescription(new RTCSessionDescription(offer))\r\n .then(function () {\r\n\r\n peerConnection.createAnswer()\r\n .then(function (answer) {\r\n\r\n if (instance.connectionConfig.sdp && instance.connectionConfig.sdp.appendFmtp) {\r\n\r\n answer.sdp = appendFmtp(answer.sdp);\r\n }\r\n\r\n peerConnection.setLocalDescription(answer)\r\n .then(function () {\r\n\r\n sendMessage(instance.webSocket, {\r\n id: id,\r\n peer_id: peerId,\r\n command: 'answer',\r\n sdp: answer\r\n });\r\n })\r\n .catch(function (error) {\r\n\r\n console.error('peerConnection.setLocalDescription', error);\r\n errorHandler(error);\r\n });\r\n })\r\n .catch(function (error) {\r\n\r\n console.error('peerConnection.createAnswer', error);\r\n errorHandler(error);\r\n });\r\n })\r\n .catch(function (error) {\r\n\r\n console.error('peerConnection.setRemoteDescription', error);\r\n errorHandler(error);\r\n });\r\n\r\n if (candidates) {\r\n\r\n addIceCandidate(peerConnection, candidates);\r\n }\r\n\r\n peerConnection.onicecandidate = function (e) {\r\n\r\n if (e.candidate && e.candidate.candidate) {\r\n\r\n sendMessage(instance.webSocket, {\r\n id: id,\r\n peer_id: peerId,\r\n command: 'candidate',\r\n candidates: [e.candidate]\r\n });\r\n }\r\n };\r\n\r\n peerConnection.oniceconnectionstatechange = function (e) {\r\n\r\n let state = peerConnection.iceConnectionState;\r\n\r\n if (instance.callbacks.iceStateChange) {\r\n\r\n console.info(logHeader, 'ICE State', '[' + state + ']');\r\n instance.callbacks.iceStateChange(state);\r\n }\r\n\r\n if (state === 'connected') {\r\n\r\n if (instance.callbacks.connected) {\r\n instance.callbacks.connected(e);\r\n }\r\n }\r\n\r\n if (state === 'failed' || state === 'disconnected' || state === 'closed') {\r\n\r\n if (instance.callbacks.connectionClosed) {\r\n console.error(logHeader, 'Iceconnection Closed', e);\r\n instance.callbacks.connectionClosed('ice', e);\r\n }\r\n }\r\n }\r\n }\r\n\r\n function addIceCandidate(peerConnection, candidates) {\r\n\r\n for (let i = 0; i < candidates.length; i++) {\r\n\r\n if (candidates[i] && candidates[i].candidate) {\r\n\r\n let basicCandidate = candidates[i];\r\n\r\n peerConnection.addIceCandidate(new RTCIceCandidate(basicCandidate))\r\n .then(function () {\r\n\r\n })\r\n .catch(function (error) {\r\n\r\n console.error('peerConnection.addIceCandidate', error);\r\n errorHandler(error);\r\n });\r\n }\r\n }\r\n }\r\n\r\n function closePeerConnection() {\r\n if (instance.peerConnection) {\r\n\r\n // remove tracks from peer connection\r\n instance.peerConnection.getSenders().forEach(function (sender) {\r\n instance.peerConnection.removeTrack(sender);\r\n });\r\n\r\n instance.peerConnection.close();\r\n instance.peerConnection = null;\r\n delete instance.peerConnection;\r\n }\r\n }\r\n\r\n function closeWebSocket() {\r\n\r\n if (instance.webSocket) {\r\n\r\n instance.webSocket.close();\r\n instance.webSocket = null;\r\n delete instance.webSocket;\r\n }\r\n }\r\n\r\n function closeInputStream() {\r\n // release video, audio stream\r\n if (instance.inputStream) {\r\n\r\n instance.inputStream.getTracks().forEach(track => {\r\n\r\n track.stop();\r\n instance.inputStream.removeTrack(track);\r\n });\r\n\r\n if (instance.videoElement) {\r\n instance.videoElement.srcObject = null;\r\n }\r\n\r\n instance.inputStream = null;\r\n delete instance.inputStream;\r\n }\r\n }\r\n\r\n // instance methods\r\n instance.attachMedia = function (videoElement) {\r\n\r\n instance.videoElement = videoElement;\r\n };\r\n\r\n instance.getUserMedia = function (constraints) {\r\n\r\n return getUserMedia(constraints);\r\n };\r\n\r\n instance.getDisplayMedia = function (constraints) {\r\n\r\n return getDisplayMedia(constraints);\r\n };\r\n\r\n instance.startStreaming = function (connectionUrl, connectionConfig) {\r\n\r\n console.info(logEventHeader, 'Start Streaming');\r\n\r\n if (connectionConfig) {\r\n\r\n instance.connectionConfig = connectionConfig;\r\n }\r\n\r\n initWebSocket(connectionUrl);\r\n };\r\n\r\n instance.stopStreaming = function () {\r\n\r\n instance.webSocketClosedByUser = true;\r\n\r\n closeWebSocket();\r\n closePeerConnection();\r\n };\r\n\r\n instance.remove = function () {\r\n\r\n instance.webSocketClosedByUser = true;\r\n\r\n closeWebSocket();\r\n closePeerConnection();\r\n closeInputStream();\r\n\r\n console.info(logEventHeader, 'Removed');\r\n\r\n };\r\n}\r\n\r\nOvenLiveKit.getVersion = function () {\r\n return version;\r\n}\r\n\r\n// static methods\r\nOvenLiveKit.create = function (options) {\r\n\r\n console.info(logEventHeader, 'Create WebRTC Input ' + version);\r\n\r\n let instance = {};\r\n\r\n instance.webSocketClosedByUser = false;\r\n\r\n initConfig(instance, options);\r\n addMethod(instance);\r\n\r\n return instance;\r\n};\r\n\r\nOvenLiveKit.getDevices = async function () {\r\n\r\n try {\r\n // First check both audio and video sources are available.\r\n await getStreamForDeviceCheck('both');\r\n } catch (e) {\r\n\r\n console.warn(logHeader, 'Can not find Video and Audio devices', e);\r\n\r\n let videoFound = null;\r\n let audioFound = null;\r\n\r\n try {\r\n videoFound = await getStreamForDeviceCheck('video');\r\n } catch (e) {\r\n console.warn(logHeader, 'Can not find Video devices', e);\r\n }\r\n\r\n try {\r\n audioFound = await getStreamForDeviceCheck('audio');\r\n } catch (e) {\r\n console.warn(logHeader, 'Can not find Audio devices', e);\r\n }\r\n\r\n if (!videoFound && !audioFound) {\r\n throw new Error('No input devices were found.');\r\n }\r\n }\r\n\r\n const deviceInfos = await getDevices();\r\n return gotDevices(deviceInfos)\r\n};\r\n\r\nexport default OvenLiveKit;"],"names":["root","factory","exports","module","define","amd","self","__webpack_require__","definition","key","o","Object","defineProperty","enumerable","get","obj","prop","prototype","hasOwnProperty","call","OvenLiveKit","logHeader","logEventHeader","sendMessage","webSocket","message","send","JSON","stringify","generateDomainFromUrl","url","match","result","findIp","string","RegExp","async","getStreamForDeviceCheck","type","constraints","audio","video","navigator","mediaDevices","getUserMedia","addMethod","instance","errorHandler","error","callbacks","appendFmtp","sdp","fmtpStr","connectionConfig","lines","split","payloads","i","length","indexOf","tokens","j","push","fmtpLineFound","join","closePeerConnection","peerConnection","getSenders","forEach","sender","removeTrack","close","closeWebSocket","attachMedia","videoElement","deviceId","undefined","console","info","then","stream","inputStream","elem","srcObject","onloadedmetadata","e","play","Promise","resolve","catch","reject","getDisplayMedia","startStreaming","connectionUrl","WebSocket","onopen","command","onmessage","parse","data","id","peerId","offer","candidates","iceServers","peerConnectionConfig","iceTransportPolicy","iceServer","regIceServer","urls","hasWebSocketUrl","webSocketUrl","cloneIceServer","ip","replace","username","user_name","credential","RTCPeerConnection","getTracks","track","addTrack","maxVideoBitrate","media","bitrate","line","newLines","slice","concat","setBitrateLimit","setRemoteDescription","RTCSessionDescription","createAnswer","answer","setLocalDescription","peer_id","candidate","basicCandidate","addIceCandidate","RTCIceCandidate","onicecandidate","oniceconnectionstatechange","state","iceConnectionState","iceStateChange","connected","connectionClosed","createPeerConnection","ice_servers","onerror","onclose","webSocketClosedByUser","initWebSocket","stopStreaming","remove","stop","getVersion","create","options","initConfig","getDevices","warn","videoFound","audioFound","Error","deviceInfos","devices","deviceInfo","kind","label","audioinput","audiooutput","videoinput","other","gotDevices","enumerateDevices"],"sourceRoot":""}
|
package/package.json
CHANGED
|
@@ -1,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.4",
|
|
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
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const OvenLiveKit = {};
|
|
2
2
|
|
|
3
|
+
const version = '1.0.4';
|
|
3
4
|
const logHeader = 'OvenLiveKit.js :';
|
|
4
5
|
const logEventHeader = 'OvenLiveKit.js ====';
|
|
5
6
|
|
|
@@ -33,18 +34,9 @@ function findIp(string) {
|
|
|
33
34
|
return result;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
function checkIOSVersion() {
|
|
37
|
-
var agent = window.navigator.userAgent,
|
|
38
|
-
start = agent.indexOf('OS ');
|
|
39
|
-
if ((agent.indexOf('iPhone') > -1 || agent.indexOf('iPad') > -1) && start > -1) {
|
|
40
|
-
return window.Number(agent.substr(start + 3, 3).replace('_', '.'));
|
|
41
|
-
}
|
|
42
|
-
return 0;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
37
|
function getFormatNumber(sdp, format) {
|
|
46
38
|
|
|
47
|
-
const lines = sdp.split('\n');
|
|
39
|
+
const lines = sdp.split('\r\n');
|
|
48
40
|
let formatNumber = -1;
|
|
49
41
|
|
|
50
42
|
for (let i = 0; i < lines.length - 1; i++) {
|
|
@@ -63,7 +55,7 @@ function getFormatNumber(sdp, format) {
|
|
|
63
55
|
|
|
64
56
|
function removeFormat(sdp, formatNumber) {
|
|
65
57
|
let newLines = [];
|
|
66
|
-
let lines = sdp.split('\n');
|
|
58
|
+
let lines = sdp.split('\r\n');
|
|
67
59
|
|
|
68
60
|
for (let i = 0; i < lines.length; i++) {
|
|
69
61
|
|
|
@@ -76,25 +68,30 @@ function removeFormat(sdp, formatNumber) {
|
|
|
76
68
|
}
|
|
77
69
|
}
|
|
78
70
|
|
|
79
|
-
return newLines.join('\n')
|
|
71
|
+
return newLines.join('\r\n')
|
|
80
72
|
}
|
|
81
73
|
|
|
82
|
-
async function getStreamForDeviceCheck() {
|
|
74
|
+
async function getStreamForDeviceCheck(type) {
|
|
83
75
|
|
|
84
76
|
// High resolution video constraints makes browser to get maximum resolution of video device.
|
|
85
77
|
const constraints = {
|
|
86
|
-
audio: { deviceId: undefined },
|
|
87
|
-
video: { deviceId: undefined, width: 1920, height: 1080 }
|
|
88
78
|
};
|
|
89
79
|
|
|
80
|
+
if (type === 'both') {
|
|
81
|
+
constraints.audio = true;
|
|
82
|
+
constraints.video = true;
|
|
83
|
+
} else if (type === 'audio') {
|
|
84
|
+
constraints.audio = true;
|
|
85
|
+
} else if (type === 'video') {
|
|
86
|
+
constraints.video = true;
|
|
87
|
+
}
|
|
88
|
+
|
|
90
89
|
return await navigator.mediaDevices.getUserMedia(constraints);
|
|
91
90
|
}
|
|
92
91
|
|
|
93
92
|
async function getDevices() {
|
|
94
93
|
|
|
95
94
|
return await navigator.mediaDevices.enumerateDevices();
|
|
96
|
-
|
|
97
|
-
|
|
98
95
|
}
|
|
99
96
|
|
|
100
97
|
function gotDevices(deviceInfos) {
|
|
@@ -138,13 +135,11 @@ function gotDevices(deviceInfos) {
|
|
|
138
135
|
|
|
139
136
|
function initConfig(instance, options) {
|
|
140
137
|
|
|
141
|
-
instance.
|
|
138
|
+
instance.inputStream = null;
|
|
142
139
|
instance.webSocket = null;
|
|
143
140
|
instance.peerConnection = null;
|
|
144
141
|
instance.connectionConfig = {};
|
|
145
142
|
|
|
146
|
-
instance.status = 'creating';
|
|
147
|
-
|
|
148
143
|
instance.videoElement = null;
|
|
149
144
|
instance.connectionUrl = null;
|
|
150
145
|
|
|
@@ -154,7 +149,6 @@ function initConfig(instance, options) {
|
|
|
154
149
|
} else {
|
|
155
150
|
instance.callbacks = {};
|
|
156
151
|
}
|
|
157
|
-
|
|
158
152
|
}
|
|
159
153
|
|
|
160
154
|
function addMethod(instance) {
|
|
@@ -181,14 +175,14 @@ function addMethod(instance) {
|
|
|
181
175
|
};
|
|
182
176
|
}
|
|
183
177
|
|
|
184
|
-
console.info(logHeader, '
|
|
178
|
+
console.info(logHeader, 'Request Stream To Input Devices With Constraints', constraints);
|
|
185
179
|
|
|
186
180
|
return navigator.mediaDevices.getUserMedia(constraints)
|
|
187
181
|
.then(function (stream) {
|
|
188
182
|
|
|
189
183
|
console.info(logHeader, 'Received Media Stream From Input Device', stream);
|
|
190
184
|
|
|
191
|
-
instance.
|
|
185
|
+
instance.inputStream = stream;
|
|
192
186
|
|
|
193
187
|
let elem = instance.videoElement;
|
|
194
188
|
|
|
@@ -225,14 +219,14 @@ function addMethod(instance) {
|
|
|
225
219
|
constraints = {};
|
|
226
220
|
}
|
|
227
221
|
|
|
228
|
-
console.info(logHeader, '
|
|
222
|
+
console.info(logHeader, 'Request Stream To Display With Constraints', constraints);
|
|
229
223
|
|
|
230
224
|
return navigator.mediaDevices.getDisplayMedia(constraints)
|
|
231
225
|
.then(function (stream) {
|
|
232
226
|
|
|
233
227
|
console.info(logHeader, 'Received Media Stream From Display', stream);
|
|
234
228
|
|
|
235
|
-
instance.
|
|
229
|
+
instance.inputStream = stream;
|
|
236
230
|
|
|
237
231
|
let elem = instance.videoElement;
|
|
238
232
|
|
|
@@ -266,7 +260,7 @@ function addMethod(instance) {
|
|
|
266
260
|
// From https://webrtchacks.com/limit-webrtc-bandwidth-sdp/
|
|
267
261
|
function setBitrateLimit(sdp, media, bitrate) {
|
|
268
262
|
|
|
269
|
-
let lines = sdp.split('\n');
|
|
263
|
+
let lines = sdp.split('\r\n');
|
|
270
264
|
let line = -1;
|
|
271
265
|
|
|
272
266
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -294,7 +288,7 @@ function addMethod(instance) {
|
|
|
294
288
|
|
|
295
289
|
lines[line] = 'b=AS:' + bitrate;
|
|
296
290
|
|
|
297
|
-
return lines.join('\n');
|
|
291
|
+
return lines.join('\r\n');
|
|
298
292
|
}
|
|
299
293
|
|
|
300
294
|
// Add a new b line
|
|
@@ -303,7 +297,7 @@ function addMethod(instance) {
|
|
|
303
297
|
newLines.push('b=AS:' + bitrate)
|
|
304
298
|
newLines = newLines.concat(lines.slice(line, lines.length))
|
|
305
299
|
|
|
306
|
-
return newLines.join('\n')
|
|
300
|
+
return newLines.join('\r\n')
|
|
307
301
|
}
|
|
308
302
|
|
|
309
303
|
function initWebSocket(connectionUrl) {
|
|
@@ -366,10 +360,9 @@ function addMethod(instance) {
|
|
|
366
360
|
|
|
367
361
|
webSocket.onclose = function (e) {
|
|
368
362
|
|
|
369
|
-
if (!instance.
|
|
363
|
+
if (!instance.webSocketClosedByUser) {
|
|
370
364
|
|
|
371
365
|
if (instance.callbacks.connectionClosed) {
|
|
372
|
-
|
|
373
366
|
instance.callbacks.connectionClosed('websocket', e);
|
|
374
367
|
}
|
|
375
368
|
}
|
|
@@ -381,7 +374,7 @@ function addMethod(instance) {
|
|
|
381
374
|
|
|
382
375
|
const fmtpStr = instance.connectionConfig.sdp.appendFmtp;
|
|
383
376
|
|
|
384
|
-
const lines = sdp.split('\n');
|
|
377
|
+
const lines = sdp.split('\r\n');
|
|
385
378
|
const payloads = [];
|
|
386
379
|
|
|
387
380
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -392,7 +385,7 @@ function addMethod(instance) {
|
|
|
392
385
|
|
|
393
386
|
for (let j = 3; j < tokens.length; j++) {
|
|
394
387
|
|
|
395
|
-
payloads.push(tokens[j]
|
|
388
|
+
payloads.push(tokens[j]);
|
|
396
389
|
}
|
|
397
390
|
|
|
398
391
|
break;
|
|
@@ -417,13 +410,47 @@ function addMethod(instance) {
|
|
|
417
410
|
|
|
418
411
|
if (lines[j].indexOf('a=rtpmap:' + payloads[i]) === 0) {
|
|
419
412
|
|
|
420
|
-
lines[j] += '\na=fmtp:' + payloads[i] + ' ' + fmtpStr;
|
|
413
|
+
lines[j] += '\r\na=fmtp:' + payloads[i] + ' ' + fmtpStr;
|
|
421
414
|
}
|
|
422
415
|
}
|
|
423
416
|
}
|
|
424
417
|
}
|
|
425
418
|
|
|
426
|
-
return lines.join('\n')
|
|
419
|
+
return lines.join('\r\n')
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
function appendOrientation(sdp) {
|
|
423
|
+
|
|
424
|
+
const lines = sdp.split('\r\n');
|
|
425
|
+
const payloads = [];
|
|
426
|
+
|
|
427
|
+
for (let i = 0; i < lines.length; i++) {
|
|
428
|
+
|
|
429
|
+
if (lines[i].indexOf('m=video') === 0) {
|
|
430
|
+
|
|
431
|
+
let tokens = lines[i].split(' ')
|
|
432
|
+
|
|
433
|
+
for (let j = 3; j < tokens.length; j++) {
|
|
434
|
+
|
|
435
|
+
payloads.push(tokens[j]);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
break;
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
for (let i = 0; i < payloads.length; i++) {
|
|
443
|
+
|
|
444
|
+
for (let j = 0; j < lines.length; j++) {
|
|
445
|
+
|
|
446
|
+
if (lines[j].indexOf('a=rtpmap:' + payloads[i]) === 0) {
|
|
447
|
+
|
|
448
|
+
lines[j] += '\r\na=extmap:' + payloads[i] + ' urn:3gpp:video-orientation';
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
return lines.join('\r\n')
|
|
427
454
|
}
|
|
428
455
|
|
|
429
456
|
function createPeerConnection(id, peerId, offer, candidates, iceServers) {
|
|
@@ -526,21 +553,12 @@ function addMethod(instance) {
|
|
|
526
553
|
instance.peerConnection = peerConnection;
|
|
527
554
|
|
|
528
555
|
// set local stream
|
|
529
|
-
instance.
|
|
556
|
+
instance.inputStream.getTracks().forEach(function (track) {
|
|
530
557
|
|
|
531
558
|
console.info(logHeader, 'Add Track To Peer Connection', track);
|
|
532
|
-
peerConnection.addTrack(track, instance.
|
|
559
|
+
peerConnection.addTrack(track, instance.inputStream);
|
|
533
560
|
});
|
|
534
561
|
|
|
535
|
-
|
|
536
|
-
if (checkIOSVersion() >= 15) {
|
|
537
|
-
const formatNumber = getFormatNumber(offer.sdp, 'H264');
|
|
538
|
-
|
|
539
|
-
if (formatNumber > 0) {
|
|
540
|
-
offer.sdp = removeFormat(offer.sdp, formatNumber);
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
|
|
544
562
|
if (instance.connectionConfig.maxVideoBitrate) {
|
|
545
563
|
|
|
546
564
|
// if bandwith limit is set. modify sdp from ome to limit acceptable bandwidth of ome
|
|
@@ -552,22 +570,14 @@ function addMethod(instance) {
|
|
|
552
570
|
offer.sdp = appendFmtp(offer.sdp);
|
|
553
571
|
}
|
|
554
572
|
|
|
573
|
+
// offer.sdp = appendOrientation(offer.sdp);
|
|
574
|
+
|
|
555
575
|
peerConnection.setRemoteDescription(new RTCSessionDescription(offer))
|
|
556
576
|
.then(function () {
|
|
557
577
|
|
|
558
578
|
peerConnection.createAnswer()
|
|
559
579
|
.then(function (answer) {
|
|
560
580
|
|
|
561
|
-
if (checkIOSVersion() >= 15) {
|
|
562
|
-
|
|
563
|
-
const formatNumber = getFormatNumber(answer.sdp, 'H264');
|
|
564
|
-
|
|
565
|
-
if (formatNumber > 0) {
|
|
566
|
-
|
|
567
|
-
answer.sdp = removeFormat(answer.sdp, formatNumber);
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
|
|
571
581
|
if (instance.connectionConfig.sdp && instance.connectionConfig.sdp.appendFmtp) {
|
|
572
582
|
|
|
573
583
|
answer.sdp = appendFmtp(answer.sdp);
|
|
@@ -610,8 +620,6 @@ function addMethod(instance) {
|
|
|
610
620
|
|
|
611
621
|
if (e.candidate && e.candidate.candidate) {
|
|
612
622
|
|
|
613
|
-
console.info(logHeader, 'Candidate Sent', '\n', e.candidate.candidate, '\n', e);
|
|
614
|
-
|
|
615
623
|
sendMessage(instance.webSocket, {
|
|
616
624
|
id: id,
|
|
617
625
|
peer_id: peerId,
|
|
@@ -634,8 +642,6 @@ function addMethod(instance) {
|
|
|
634
642
|
if (state === 'connected') {
|
|
635
643
|
|
|
636
644
|
if (instance.callbacks.connected) {
|
|
637
|
-
|
|
638
|
-
console.info(logHeader, 'Iceconnection Connected', e);
|
|
639
645
|
instance.callbacks.connected(e);
|
|
640
646
|
}
|
|
641
647
|
}
|
|
@@ -643,7 +649,6 @@ function addMethod(instance) {
|
|
|
643
649
|
if (state === 'failed' || state === 'disconnected' || state === 'closed') {
|
|
644
650
|
|
|
645
651
|
if (instance.callbacks.connectionClosed) {
|
|
646
|
-
|
|
647
652
|
console.error(logHeader, 'Iceconnection Closed', e);
|
|
648
653
|
instance.callbacks.connectionClosed('ice', e);
|
|
649
654
|
}
|
|
@@ -672,6 +677,49 @@ function addMethod(instance) {
|
|
|
672
677
|
}
|
|
673
678
|
}
|
|
674
679
|
|
|
680
|
+
function closePeerConnection() {
|
|
681
|
+
if (instance.peerConnection) {
|
|
682
|
+
|
|
683
|
+
// remove tracks from peer connection
|
|
684
|
+
instance.peerConnection.getSenders().forEach(function (sender) {
|
|
685
|
+
instance.peerConnection.removeTrack(sender);
|
|
686
|
+
});
|
|
687
|
+
|
|
688
|
+
instance.peerConnection.close();
|
|
689
|
+
instance.peerConnection = null;
|
|
690
|
+
delete instance.peerConnection;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
function closeWebSocket() {
|
|
695
|
+
|
|
696
|
+
if (instance.webSocket) {
|
|
697
|
+
|
|
698
|
+
instance.webSocket.close();
|
|
699
|
+
instance.webSocket = null;
|
|
700
|
+
delete instance.webSocket;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
function closeInputStream() {
|
|
705
|
+
// release video, audio stream
|
|
706
|
+
if (instance.inputStream) {
|
|
707
|
+
|
|
708
|
+
instance.inputStream.getTracks().forEach(track => {
|
|
709
|
+
|
|
710
|
+
track.stop();
|
|
711
|
+
instance.inputStream.removeTrack(track);
|
|
712
|
+
});
|
|
713
|
+
|
|
714
|
+
if (instance.videoElement) {
|
|
715
|
+
instance.videoElement.srcObject = null;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
instance.inputStream = null;
|
|
719
|
+
delete instance.inputStream;
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
|
|
675
723
|
// instance methods
|
|
676
724
|
instance.attachMedia = function (videoElement) {
|
|
677
725
|
|
|
@@ -700,63 +748,39 @@ function addMethod(instance) {
|
|
|
700
748
|
initWebSocket(connectionUrl);
|
|
701
749
|
};
|
|
702
750
|
|
|
703
|
-
instance.
|
|
704
|
-
|
|
705
|
-
instance.removing = true;
|
|
706
|
-
|
|
707
|
-
// first release peer connection with ome
|
|
708
|
-
if (instance.peerConnection) {
|
|
709
|
-
|
|
710
|
-
// remove tracks from peer connection
|
|
711
|
-
instance.peerConnection.getSenders().forEach(function (sender) {
|
|
712
|
-
instance.peerConnection.removeTrack(sender);
|
|
713
|
-
});
|
|
714
|
-
|
|
715
|
-
instance.peerConnection.close();
|
|
716
|
-
instance.peerConnection = null;
|
|
717
|
-
delete instance.peerConnection;
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
// release video, audio stream
|
|
721
|
-
if (instance.stream) {
|
|
751
|
+
instance.stopStreaming = function () {
|
|
722
752
|
|
|
723
|
-
|
|
753
|
+
instance.webSocketClosedByUser = true;
|
|
724
754
|
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
755
|
+
closeWebSocket();
|
|
756
|
+
closePeerConnection();
|
|
757
|
+
};
|
|
728
758
|
|
|
729
|
-
|
|
730
|
-
instance.videoElement.srcObject = null;
|
|
731
|
-
}
|
|
759
|
+
instance.remove = function () {
|
|
732
760
|
|
|
733
|
-
|
|
734
|
-
delete instance.stream;
|
|
735
|
-
}
|
|
761
|
+
instance.webSocketClosedByUser = true;
|
|
736
762
|
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
instance.webSocket.close();
|
|
741
|
-
instance.webSocket = null;
|
|
742
|
-
delete instance.webSocket;
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
instance.status = 'removed';
|
|
763
|
+
closeWebSocket();
|
|
764
|
+
closePeerConnection();
|
|
765
|
+
closeInputStream();
|
|
746
766
|
|
|
747
767
|
console.info(logEventHeader, 'Removed');
|
|
748
768
|
|
|
749
769
|
};
|
|
750
770
|
}
|
|
751
771
|
|
|
772
|
+
OvenLiveKit.getVersion = function () {
|
|
773
|
+
return version;
|
|
774
|
+
}
|
|
775
|
+
|
|
752
776
|
// static methods
|
|
753
777
|
OvenLiveKit.create = function (options) {
|
|
754
778
|
|
|
755
|
-
console.info(logEventHeader, 'Create WebRTC Input
|
|
779
|
+
console.info(logEventHeader, 'Create WebRTC Input ' + version);
|
|
756
780
|
|
|
757
781
|
let instance = {};
|
|
758
782
|
|
|
759
|
-
instance.
|
|
783
|
+
instance.webSocketClosedByUser = false;
|
|
760
784
|
|
|
761
785
|
initConfig(instance, options);
|
|
762
786
|
addMethod(instance);
|
|
@@ -766,7 +790,33 @@ OvenLiveKit.create = function (options) {
|
|
|
766
790
|
|
|
767
791
|
OvenLiveKit.getDevices = async function () {
|
|
768
792
|
|
|
769
|
-
|
|
793
|
+
try {
|
|
794
|
+
// First check both audio and video sources are available.
|
|
795
|
+
await getStreamForDeviceCheck('both');
|
|
796
|
+
} catch (e) {
|
|
797
|
+
|
|
798
|
+
console.warn(logHeader, 'Can not find Video and Audio devices', e);
|
|
799
|
+
|
|
800
|
+
let videoFound = null;
|
|
801
|
+
let audioFound = null;
|
|
802
|
+
|
|
803
|
+
try {
|
|
804
|
+
videoFound = await getStreamForDeviceCheck('video');
|
|
805
|
+
} catch (e) {
|
|
806
|
+
console.warn(logHeader, 'Can not find Video devices', e);
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
try {
|
|
810
|
+
audioFound = await getStreamForDeviceCheck('audio');
|
|
811
|
+
} catch (e) {
|
|
812
|
+
console.warn(logHeader, 'Can not find Audio devices', e);
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
if (!videoFound && !audioFound) {
|
|
816
|
+
throw new Error('No input devices were found.');
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
|
|
770
820
|
const deviceInfos = await getDevices();
|
|
771
821
|
return gotDevices(deviceInfos)
|
|
772
822
|
};
|