@campoint/vxwebrtc 0.0.2

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.
Files changed (40) hide show
  1. package/.eslintignore +1 -0
  2. package/.eslintrc.js +22 -0
  3. package/.gitlab-ci.yml +42 -0
  4. package/README.md +1 -0
  5. package/dist/MungeSdp.d.ts +2 -0
  6. package/dist/Types/CodecsOptions.d.ts +8 -0
  7. package/dist/Types/CommonConnectionTypes.d.ts +48 -0
  8. package/dist/Types/EnumCodecContentType.d.ts +13 -0
  9. package/dist/Types/WebRTCStreamConfig.d.ts +26 -0
  10. package/dist/WebRtcInputConnection.d.ts +19 -0
  11. package/dist/WebRtcOutputConnection.d.ts +20 -0
  12. package/dist/WebRtcPeerConnection.d.ts +23 -0
  13. package/dist/browserSupportedAudioCodec.d.ts +13 -0
  14. package/dist/browserSupportedVideoCodec.d.ts +7 -0
  15. package/dist/stats.json +10326 -0
  16. package/dist/utils.d.ts +6 -0
  17. package/dist/version.d.ts +1 -0
  18. package/dist/vxwebrtc.d.ts +6 -0
  19. package/dist/vxwebrtc.js +3 -0
  20. package/dist/vxwebrtc.js.LICENSE.txt +8 -0
  21. package/dist/vxwebrtc.js.map +1 -0
  22. package/package.json +53 -0
  23. package/src/MungeSdp.ts +323 -0
  24. package/src/Types/CodecsOptions.ts +9 -0
  25. package/src/Types/CommonConnectionTypes.ts +57 -0
  26. package/src/Types/EnumCodecContentType.ts +13 -0
  27. package/src/Types/WebRTCStreamConfig.ts +59 -0
  28. package/src/WebRtcInputConnection.ts +152 -0
  29. package/src/WebRtcOutputConnection.ts +122 -0
  30. package/src/WebRtcPeerConnection.ts +91 -0
  31. package/src/browserSupportedAudioCodec.ts +49 -0
  32. package/src/browserSupportedVideoCodec.ts +39 -0
  33. package/src/utils.ts +18 -0
  34. package/src/version.ts +1 -0
  35. package/src/vxwebrtc.ts +8 -0
  36. package/tsconfig.json +15 -0
  37. package/tslint.json +18 -0
  38. package/webpack.common.js +43 -0
  39. package/webpack.dev.js +7 -0
  40. package/webpack.prod.js +7 -0
@@ -0,0 +1,122 @@
1
+ import adapter from 'webrtc-adapter';
2
+ import { mungeSdpPublish } from './MungeSdp';
3
+ import {
4
+ EnumMediaStreamTrackKind,
5
+ EnumWebSocketConnectionCommand,
6
+ EnumWebSocketConnectionDirection,
7
+ EnumWebSocketConnectionStatus,
8
+ MediaInfo,
9
+ WebSocketReply,
10
+ } from './Types/CommonConnectionTypes';
11
+ import WebRtcPeerConnection, { IWebRtcPeerConnectionOptions } from './WebRtcPeerConnection';
12
+
13
+ export class WebRtcOutputConnection extends WebRtcPeerConnection {
14
+ protected connectionOptions: IWebRtcOutputConnection;
15
+ protected wsConnection?: WebSocket = undefined;
16
+ protected peerConnection?: RTCPeerConnection = undefined;
17
+ private peerConnectionConfig?: RTCConfiguration = undefined;
18
+ private videoSender?: RTCRtpSender = undefined;
19
+ private audioSender?: RTCRtpSender = undefined;
20
+
21
+ constructor(connectionOptions: IWebRtcOutputConnection) {
22
+ super(connectionOptions);
23
+
24
+ this.onError = this.onError.bind(this);
25
+ this.onRtcDescription = this.onRtcDescription.bind(this);
26
+ this.onWsOpen = this.onWsOpen.bind(this);
27
+ this.onWsMessage = this.onWsMessage.bind(this);
28
+ this.connectionOptions = connectionOptions;
29
+ }
30
+
31
+ protected onRtcDescription(description: RTCSessionDescriptionInit) {
32
+ if (!this.peerConnection) {
33
+ return this.onError(new Error('RTC got description, but no RTC'));
34
+ }
35
+
36
+ if (description.sdp && adapter.browserDetails.browser !== 'safari') {
37
+ description.sdp = mungeSdpPublish(
38
+ description.sdp ? description.sdp : '',
39
+ this.connectionOptions.mediaInfo
40
+ );
41
+ }
42
+
43
+ this.peerConnection
44
+ .setLocalDescription(description)
45
+ .then(() => {
46
+ this.sendResponse(
47
+ EnumWebSocketConnectionDirection.PUBLISH,
48
+ EnumWebSocketConnectionCommand.SEND_OFFER,
49
+ description
50
+ );
51
+ })
52
+ .catch(this.onError);
53
+ }
54
+
55
+ protected onWsOpen() {
56
+ this.peerConnection = new RTCPeerConnection(this.peerConnectionConfig);
57
+ this.videoSender = undefined;
58
+ this.audioSender = undefined;
59
+
60
+ this.peerConnection.onnegotiationneeded = () => {
61
+ if (this.peerConnection) {
62
+ this.peerConnection.createOffer().then(this.onRtcDescription, this.onError);
63
+ }
64
+ };
65
+
66
+ const localTracks = this.connectionOptions.localStream.getTracks();
67
+
68
+ for (const localTrack of localTracks) {
69
+ const sender = this.peerConnection.addTrack(localTrack, this.connectionOptions.localStream);
70
+
71
+ if (localTrack.kind === EnumMediaStreamTrackKind.AUDIO) {
72
+ this.audioSender = sender;
73
+ } else if (localTrack.kind === EnumMediaStreamTrackKind.VIDEO) {
74
+ this.videoSender = sender;
75
+ }
76
+ }
77
+ }
78
+
79
+ protected onWsMessage(evt: MessageEvent) {
80
+ const msgJson: WebSocketReply = JSON.parse(evt.data);
81
+ const msgStatus = parseInt(msgJson.status, 10);
82
+
83
+ if (msgStatus !== EnumWebSocketConnectionStatus.OK) {
84
+ return this.onError(new Error(msgJson.statusDescription));
85
+ }
86
+
87
+ const sdpData = msgJson.sdp;
88
+
89
+ if (sdpData && this.peerConnection) {
90
+ this.peerConnection
91
+ .setRemoteDescription(new RTCSessionDescription(sdpData))
92
+ .catch(this.onError);
93
+ }
94
+
95
+ const iceCandidates = msgJson.iceCandidates;
96
+
97
+ if (iceCandidates !== undefined && this.peerConnection) {
98
+ for (const iceCandidate of iceCandidates) {
99
+ this.peerConnection.addIceCandidate(new RTCIceCandidate(iceCandidate)).catch(this.onError);
100
+ }
101
+ }
102
+ }
103
+
104
+ public start() {
105
+ super.start();
106
+ if (this.wsConnection) {
107
+ this.wsConnection.onopen = this.onWsOpen;
108
+ this.wsConnection.onmessage = this.onWsMessage;
109
+ }
110
+ }
111
+
112
+ public stop() {
113
+ super.stop();
114
+ this.videoSender = undefined;
115
+ this.audioSender = undefined;
116
+ }
117
+ }
118
+
119
+ export interface IWebRtcOutputConnection extends IWebRtcPeerConnectionOptions {
120
+ localStream: MediaStream;
121
+ mediaInfo: MediaInfo;
122
+ }
@@ -0,0 +1,91 @@
1
+ import {
2
+ OnErrorCallback,
3
+ OnStopCallback,
4
+ StreamInfo,
5
+ EnumWebSocketConnectionCommand,
6
+ EnumWebSocketConnectionDirection,
7
+ } from './Types/CommonConnectionTypes';
8
+
9
+ abstract class WebRtcPeerConnection {
10
+ protected wsConnection?: WebSocket = undefined;
11
+ protected peerConnection?: RTCPeerConnection = undefined;
12
+
13
+ protected abstract onRtcDescription(description: RTCSessionDescriptionInit): void;
14
+ protected abstract onWsOpen(): void;
15
+ protected abstract onWsMessage(evt: MessageEvent): void;
16
+
17
+ protected constructor(protected connectionOptions: IWebRtcPeerConnectionOptions) {
18
+ this.connectionOptions = connectionOptions;
19
+ this.connectToWebSocket = this.connectToWebSocket.bind(this);
20
+ this.onError = this.onError.bind(this);
21
+ }
22
+
23
+ protected sendResponse(
24
+ direction: EnumWebSocketConnectionDirection,
25
+ command: EnumWebSocketConnectionCommand,
26
+ description?: RTCSessionDescriptionInit
27
+ ) {
28
+ if (this.wsConnection) {
29
+ let json = {
30
+ direction: direction,
31
+ command: command,
32
+ streamInfo: this.connectionOptions.streamInfo,
33
+ userData: this.connectionOptions.userData,
34
+ };
35
+
36
+ if (description !== undefined) {
37
+ json = { ...json, ...{ sdp: description } };
38
+ }
39
+
40
+ this.wsConnection.send(JSON.stringify(json));
41
+ }
42
+ }
43
+
44
+ protected connectToWebSocket() {
45
+ this.wsConnection = new WebSocket(this.connectionOptions.wsUrl);
46
+ this.wsConnection.binaryType = 'arraybuffer';
47
+ this.wsConnection.onerror = () => this.onError(new Error('WsConnection failed'));
48
+ }
49
+
50
+ protected onError(error: Error) {
51
+ this.stop();
52
+ this.connectionOptions.onError(error);
53
+ }
54
+
55
+ public start() {
56
+ if (!this.peerConnection) {
57
+ if (this.wsConnection) {
58
+ this.wsConnection.close();
59
+ this.wsConnection = undefined;
60
+ }
61
+
62
+ this.connectToWebSocket();
63
+ }
64
+ }
65
+
66
+ public stop() {
67
+ if (this.peerConnection) {
68
+ this.peerConnection.close();
69
+ }
70
+
71
+ this.peerConnection = undefined;
72
+
73
+ if (this.wsConnection) {
74
+ this.wsConnection.close();
75
+ }
76
+
77
+ this.wsConnection = undefined;
78
+
79
+ this.connectionOptions.onStop();
80
+ }
81
+ }
82
+
83
+ export interface IWebRtcPeerConnectionOptions {
84
+ wsUrl: string;
85
+ streamInfo: StreamInfo;
86
+ userData?: object;
87
+ onStop: OnStopCallback;
88
+ onError: OnErrorCallback;
89
+ }
90
+
91
+ export default WebRtcPeerConnection;
@@ -0,0 +1,49 @@
1
+ import adapter from 'webrtc-adapter';
2
+ import { EnumCodecContentType } from './Types/EnumCodecContentType';
3
+ import { supportsCodec } from './utils';
4
+
5
+ export enum EnumAudioCodecs {
6
+ OPUS = 'opus',
7
+ VORBIS = 'vorbis',
8
+ PCMU = 'pcmu',
9
+ PCMA = 'pcma',
10
+ }
11
+
12
+ /** @see CanPlayTypeResult */
13
+ export enum EnumMediaCodecSupported {
14
+ UNKNOWN = '',
15
+ PROBABLY = 'probably',
16
+ MAYBE = 'maybe',
17
+ }
18
+
19
+ export const browserSupportedAudioCodec = (codecs: string[]) => {
20
+ const isSafari = adapter.browserDetails.browser === 'safari';
21
+
22
+ for (let i = 0; i < codecs.length; i++) {
23
+ const codec = codecs[i];
24
+
25
+ switch (codec) {
26
+ case EnumAudioCodecs.OPUS:
27
+ if (
28
+ isSafari ||
29
+ supportsCodec(EnumCodecContentType.OPUS) === EnumMediaCodecSupported.PROBABLY
30
+ ) {
31
+ return EnumAudioCodecs.OPUS;
32
+ }
33
+ break;
34
+
35
+ case EnumAudioCodecs.VORBIS:
36
+ if (supportsCodec(EnumCodecContentType.VORBIS) === EnumMediaCodecSupported.PROBABLY) {
37
+ return EnumAudioCodecs.VORBIS;
38
+ }
39
+ break;
40
+
41
+ // could not find a way to check the support of this codec in the browser
42
+ case EnumAudioCodecs.PCMU:
43
+ case EnumAudioCodecs.PCMA:
44
+ break;
45
+ }
46
+ }
47
+
48
+ return '';
49
+ };
@@ -0,0 +1,39 @@
1
+ import * as _ from 'lodash';
2
+ import { EnumCodecContentType } from './Types/EnumCodecContentType';
3
+ import { EnumVideoCodec } from './Types/CommonConnectionTypes';
4
+ import { supportsCodec } from './utils';
5
+
6
+ export enum EnumVideoCodecs {
7
+ H264 = 'h264',
8
+ VP9 = 'VP9',
9
+ VP8 = 'VP8',
10
+ }
11
+
12
+ export const browserSupportedVideoCodec = (codecs: string[]) => {
13
+ for (let i = 0; i < codecs.length; i++) {
14
+ const codec = codecs[i];
15
+
16
+ switch (codec) {
17
+ case EnumVideoCodecs.H264:
18
+ /** @note codec is re-named here on purpose to make Wowza server happy */
19
+ if (!_.isEmpty(supportsCodec(EnumCodecContentType.H264))) {
20
+ return EnumVideoCodec.H264;
21
+ }
22
+ break;
23
+
24
+ case EnumVideoCodecs.VP9:
25
+ if (!_.isEmpty(supportsCodec(EnumCodecContentType.VP9))) {
26
+ return EnumVideoCodecs.VP9;
27
+ }
28
+ break;
29
+
30
+ case EnumVideoCodecs.VP8:
31
+ if (!_.isEmpty(supportsCodec(EnumCodecContentType.VP8))) {
32
+ return EnumVideoCodecs.VP8;
33
+ }
34
+ break;
35
+ }
36
+ }
37
+
38
+ return '';
39
+ };
package/src/utils.ts ADDED
@@ -0,0 +1,18 @@
1
+ import * as _ from 'lodash';
2
+ import { EnumCodecContentType } from './Types/EnumCodecContentType';
3
+
4
+ export enum EnumSupportedMediaType {
5
+ VIDEO = 'video',
6
+ AUDIO = 'audio',
7
+ }
8
+
9
+ export const supportsCodec = (codecType: EnumCodecContentType): CanPlayTypeResult => {
10
+ const mediaType = codecType.split('/');
11
+
12
+ if (!_.includes(Object.values(EnumSupportedMediaType), mediaType[0])) {
13
+ return '';
14
+ }
15
+
16
+ const v = window.document.createElement(mediaType[0]) as HTMLMediaElement;
17
+ return v.canPlayType(codecType);
18
+ };
package/src/version.ts ADDED
@@ -0,0 +1 @@
1
+ export const VERSION = '__VERSION__';
@@ -0,0 +1,8 @@
1
+ export { WebRtcInputConnection, IWebRtcInputConnection } from './WebRtcInputConnection';
2
+ export { WebRtcOutputConnection, IWebRtcOutputConnection } from './WebRtcOutputConnection';
3
+
4
+ export { TWebRtcH264CodecOptions, TWebRtcVP9CodecOptions } from './Types/CodecsOptions';
5
+ export { TConstrainULongRange } from './Types/WebRTCStreamConfig';
6
+
7
+ export {browserSupportedAudioCodec} from './browserSupportedAudioCodec'
8
+ export {browserSupportedVideoCodec} from './browserSupportedVideoCodec'
package/tsconfig.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "lib": ["dom", "es5", "scripthost", "ES2015", "es2016.array.include"],
4
+ "target": "es5",
5
+ "moduleResolution": "node",
6
+ "sourceMap": true,
7
+ "declaration": true,
8
+ "newLine": "LF",
9
+ "outDir": "./dist",
10
+ "rootDirs": ["src"],
11
+ "allowJs": true
12
+ },
13
+ "include": ["src/**/*"],
14
+ "exclude": ["node_modules", "**/*.spec.ts"]
15
+ }
package/tslint.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "defaultSeverity": "warning",
3
+ "extends": [
4
+ "tslint:recommended"
5
+ ],
6
+ "jsRules": {},
7
+ "rules": {
8
+ "interface-name": [false],
9
+ "max-line-length": [false],
10
+ "no-empty": [false],
11
+ "object-literal-shorthand": [false],
12
+ "object-literal-sort-keys": [true, "match-declaration-order"],
13
+ "quotemark": [true, "single", "avoid-escape", "avoid-template"],
14
+ "trailing-comma": [true, {"multiline": "never", "singleline": "never"}],
15
+ "variable-name": { "options": [ "check-format", "allow-leading-underscore", "allow-pascal-case", "ban-keywords" ] }
16
+ },
17
+ "rulesDirectory": []
18
+ }
@@ -0,0 +1,43 @@
1
+ const path = require('path');
2
+ const { CleanWebpackPlugin } = require('clean-webpack-plugin');
3
+ const DuplicatePackageCheckerPlugin = require('duplicate-package-checker-webpack-plugin');
4
+ const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
5
+
6
+ module.exports = {
7
+ entry: {
8
+ 'vxwebrtc': './src/vxwebrtc.ts',
9
+ },
10
+ plugins: [
11
+ new CleanWebpackPlugin(),
12
+ new DuplicatePackageCheckerPlugin(),
13
+ new BundleAnalyzerPlugin({
14
+ analyzerMode: 'disabled',
15
+ generateStatsFile: true,
16
+ }),
17
+ ],
18
+ module: {
19
+ rules: [
20
+ {
21
+ test: /version.ts$/,
22
+ loader: 'string-replace-loader',
23
+ options: {
24
+ search: '__VERSION__',
25
+ replace: require('./package.json').version,
26
+ },
27
+ },
28
+ {
29
+ test: /\.tsx?$/,
30
+ use: 'ts-loader',
31
+ exclude: /node_modules/,
32
+ },
33
+ ],
34
+ },
35
+ resolve: {
36
+ extensions: ['.tsx', '.ts', '.js'],
37
+ },
38
+ output: {
39
+ filename: '[name].js',
40
+ library: 'webRTC',
41
+ path: path.resolve(__dirname, 'dist'),
42
+ }
43
+ };
package/webpack.dev.js ADDED
@@ -0,0 +1,7 @@
1
+ const { merge } = require('webpack-merge');
2
+ const common = require('./webpack.common.js');
3
+
4
+ module.exports = merge(common, {
5
+ mode: 'development',
6
+ devtool: 'inline-source-map'
7
+ });
@@ -0,0 +1,7 @@
1
+ const { merge } = require('webpack-merge');
2
+ const common = require('./webpack.common.js');
3
+
4
+ module.exports = merge(common, {
5
+ mode: 'production',
6
+ devtool: 'source-map'
7
+ });