diff --git a/.circleci/config.yml b/.circleci/config.yml
index ad480bf1d..7ead1f2bb 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -144,13 +144,6 @@ commands:
name: Running Network Tests (environment = << pipeline.parameters.environment >>)
command: scripts/circleci-run-tests.sh
- save-test-results
- framework-tests:
- steps:
- - build
- - run:
- name: Running Framework Tests
- command: scripts/circleci-run-tests.sh
- - save-test-results
umd-tests:
steps:
- build
@@ -237,12 +230,6 @@ jobs:
TEST_STABILITY: << parameters.test_stability >>
executor: machine-executor
steps: [network-tests]
- Framework-tests:
- environment:
- TEST_TYPE: "framework"
- BROWSER: "chrome"
- executor: docker-with-browser
- steps: [framework-tests]
UMD-tests:
environment:
BROWSER: "chrome"
@@ -435,10 +422,6 @@ workflows:
topology: ["group", "peer-to-peer"]
test_stability: ["stable", "unstable"]
requires: [Build, UnitTests]
- - Framework-tests:
- context: dockerhub-pulls
- name: "framework tests"
- requires: [Build, UnitTests]
- UMD-tests:
context: dockerhub-pulls
name: "umd tests"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 748d5bb92..fc88c2b8d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,24 @@ The Twilio Programmable Video SDKs use [Semantic Versioning](http://www.semver.o
**Version 1.x reached End of Life on September 8th, 2021.** See the changelog entry [here](https://www.twilio.com/changelog/end-of-life-complete-for-unsupported-versions-of-the-programmable-video-sdk). Support for the 1.x version ended on December 4th, 2020.
+2.21.0 (March 8, 2022)
+==========================
+
+New Features
+------------
+- twilio-video.js now supports WKWebView and SFSafariViewController on iOS version 14.3 or later. The [`isSupported` flag](https://sdk.twilio.com/js/video/releases/2.20.1/docs/module-twilio-video.html) relies partly on the [User-Agent string](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent) to determine if twilio-video.js officially supports the user's browser. If your application modifies the default value for the User-Agent string, the new value should follow the [correct format](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent#syntax).
+
+ Additionally, for [iOS applications](https://developer.apple.com/documentation/avfoundation/cameras_and_media_capture/requesting_authorization_for_media_capture_on_ios), your application will need to include the [camera usage description](https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/plist/info/NSCameraUsageDescription), [microphone usage description](https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW25) and [inline media playback](https://developer.apple.com/documentation/webkit/wkwebviewconfiguration/1614793-allowsinlinemediaplayback) in order for the SDK to work on WKWebView.
+
+ Note: As with Safari, WKWebViews only support only one local media track of each kind at a time.
+
+ We also would like to thank @cbxp for his [contribution](https://github.com/twilio/twilio-webrtc.js/pull/133). (VIDEO-8374)
+
+Known Issue
+-----------
+
+Some [common issues](https://github.com/twilio/twilio-video.js/blob/master/COMMON_ISSUES.md#safari-mobile) such as interruptions on mobile devices which includes, backgrounding the application, or switching between applications can sometimes cause VideoTracks to go black or AudioTracks to stop.
+
2.20.1 (Feb 17, 2022)
=====================
Bug Fixes
diff --git a/README.md b/README.md
index 39a42386a..af7ba0183 100644
--- a/README.md
+++ b/README.md
@@ -21,13 +21,13 @@ View [CHANGELOG.md](https://github.com/twilio/twilio-video.js/blob/master/CHANGE
Browser Support
---------------
-| | Chrome | Edge (Chromium) | Firefox | Safari |
-| ------------|--------|-----------------|---------|--------|
-| **Android** | ✓ | - | ✓ | - |
-| **iOS** | ✓ | - | * | ✓ |
-| **Linux** | ✓ | - | ✓ | - |
-| **macOS** | ✓ | ✓ ** | ✓ | ✓ |
-| **Windows** | ✓ | ✓ ** | ✓ | - |
+| | Chrome | Edge (Chromium) | Firefox | Safari | WebView |
+| ------------|--------|-----------------|---------|--------|---------|
+| **Android** | ✓ | - | ✓ | - | - |
+| **iOS** | ✓ | - | * | ✓ | ✓ |
+| **Linux** | ✓ | - | ✓ | - | - |
+| **macOS** | ✓ | ✓ ** | ✓ | ✓ | - |
+| **Windows** | ✓ | ✓ ** | ✓ | - | - |
\*\* twilio-video.js supports the [Chromium-based Edge](https://www.microsoftedgeinsider.com/) browser.
@@ -74,7 +74,7 @@ Releases of twilio-video.js are hosted on a CDN, and you can include these
directly in your web app using a <script> tag.
```html
-
+
```
@@ -235,4 +235,3 @@ License
-------
See [LICENSE.md](https://github.com/twilio/twilio-video.js/blob/master/LICENSE.md).
-
diff --git a/lib/connect.js b/lib/connect.js
index 99b9622ef..7444244ce 100644
--- a/lib/connect.js
+++ b/lib/connect.js
@@ -3,7 +3,6 @@
const { MediaStreamTrack } = require('@twilio/webrtc');
const { guessBrowser, guessBrowserVersion } = require('@twilio/webrtc/lib/util');
const createCancelableRoomPromise = require('./cancelableroompromise');
-const createLocalTracks = require('./createlocaltracks');
const EncodingParametersImpl = require('./encodingparameters');
const LocalParticipant = require('./localparticipant');
const InsightsPublisher = require('./util/insightspublisher');
@@ -235,7 +234,6 @@ function connect(token, options) {
options = Object.assign({
automaticSubscription: true,
- createLocalTracks,
dominantSpeaker: false,
enableDscp: false,
environment: DEFAULT_ENVIRONMENT,
diff --git a/lib/createlocaltrack.js b/lib/createlocaltrack.js
index 4cf0c43c3..e23aa6b4d 100644
--- a/lib/createlocaltrack.js
+++ b/lib/createlocaltrack.js
@@ -1,6 +1,5 @@
'use strict';
-const defaultCreateLocalTracks = require('./createlocaltracks');
const { DEFAULT_LOG_LEVEL, DEFAULT_LOGGER_NAME } = require('./util/constants');
/**
@@ -12,7 +11,6 @@ const { DEFAULT_LOG_LEVEL, DEFAULT_LOGGER_NAME } = require('./util/constants');
*/
function createLocalTrack(kind, options) {
options = Object.assign({
- createLocalTracks: defaultCreateLocalTracks,
loggerName: DEFAULT_LOGGER_NAME,
logLevel: DEFAULT_LOG_LEVEL,
}, options);
diff --git a/lib/createlocaltracks.js b/lib/createlocaltracks.ts
similarity index 60%
rename from lib/createlocaltracks.js
rename to lib/createlocaltracks.ts
index fcda77ac3..3b4dba6cd 100644
--- a/lib/createlocaltracks.js
+++ b/lib/createlocaltracks.ts
@@ -1,8 +1,9 @@
'use strict';
-const asLocalTrack = require('./util').asLocalTrack;
-const buildLogLevels = require('./util').buildLogLevels;
-const getUserMedia = require('@twilio/webrtc').getUserMedia;
+import { CreateLocalTrackOptions, CreateLocalTracksOptions, LocalTrack } from '../tsdef/types';
+
+const { asLocalTrack, buildLogLevels } = require('./util');
+const { getUserMedia, MediaStreamTrack } = require('@twilio/webrtc');
const {
LocalAudioTrack,
@@ -10,7 +11,6 @@ const {
LocalVideoTrack
} = require('./media/track/es5');
-const MediaStreamTrack = require('@twilio/webrtc').MediaStreamTrack;
const Log = require('./util/log');
const { DEFAULT_LOG_LEVEL, DEFAULT_LOGGER_NAME } = require('./util/constants');
const workaround180748 = require('./webaudio/workaround180748');
@@ -20,6 +20,19 @@ const workaround180748 = require('./webaudio/workaround180748');
// counter.
let createLocalTrackCalls = 0;
+
+type ExtraLocalTrackOption = CreateLocalTrackOptions & { isCreatedByCreateLocalTracks?: boolean };
+type ExtraLocalTrackOptions = { audio: ExtraLocalTrackOption; video: ExtraLocalTrackOption; };
+
+interface InternalOptions extends CreateLocalTracksOptions {
+ getUserMedia: any;
+ LocalAudioTrack: any;
+ LocalDataTrack: any;
+ LocalVideoTrack: any;
+ MediaStreamTrack: any;
+ Log: any;
+};
+
/**
* Request {@link LocalTrack}s. By default, it requests a
* {@link LocalAudioTrack} and a {@link LocalVideoTrack}.
@@ -77,11 +90,11 @@ let createLocalTrackCalls = 0;
* });
*
*/
-function createLocalTracks(options) {
+export async function createLocalTracks(options?: CreateLocalTracksOptions): Promise {
const isAudioVideoAbsent =
!(options && ('audio' in options || 'video' in options));
- options = Object.assign({
+ const fullOptions: InternalOptions = {
audio: isAudioVideoAbsent,
getUserMedia,
loggerName: DEFAULT_LOGGER_NAME,
@@ -91,80 +104,90 @@ function createLocalTracks(options) {
LocalVideoTrack,
MediaStreamTrack,
Log,
- video: isAudioVideoAbsent
- }, options);
+ video: isAudioVideoAbsent,
+ ...options,
+ };
const logComponentName = `[createLocalTracks #${++createLocalTrackCalls}]`;
- const logLevels = buildLogLevels(options.logLevel);
- const log = new options.Log('default', logComponentName, logLevels, options.loggerName);
+ const logLevels = buildLogLevels(fullOptions.logLevel);
+ const log = new fullOptions.Log('default', logComponentName, logLevels, fullOptions.loggerName);
+
+ const localTrackOptions = Object.assign({ log }, fullOptions);
// NOTE(mmalavalli): The Room "name" in "options" was being used
// as the LocalTrack name in asLocalTrack(). So we pass a copy of
// "options" without the "name".
- const localTrackOptions = Object.assign({ log }, options);
- delete localTrackOptions.name;
+ // NOTE(joma): CreateLocalTracksOptions type does not really have a "name" property when used publicly by customers.
+ // But we are passing this property when used internally by other JS files.
+ // We can update this "any" type once those JS files are converted to TS.
+ delete (localTrackOptions as any).name;
- if (options.audio === false && options.video === false) {
+ if (fullOptions.audio === false && fullOptions.video === false) {
log.info('Neither audio nor video requested, so returning empty LocalTracks');
- return Promise.resolve([]);
+ return [];
}
- if (options.tracks) {
+ if (fullOptions.tracks) {
log.info('Adding user-provided LocalTracks');
- log.debug('LocalTracks:', options.tracks);
- return Promise.resolve(options.tracks);
+ log.debug('LocalTracks:', fullOptions.tracks);
+ return fullOptions.tracks;
}
- const extraLocalTrackOptions = {
- audio: options.audio && options.audio.name
- ? { name: options.audio.name }
+ const extraLocalTrackOptions: ExtraLocalTrackOptions = {
+ audio: typeof fullOptions.audio === 'object' && fullOptions.audio.name
+ ? { name: fullOptions.audio.name }
: {},
- video: options.video && options.video.name
- ? { name: options.video.name }
+ video: typeof fullOptions.video === 'object' && fullOptions.video.name
+ ? { name: fullOptions.video.name }
: {}
};
extraLocalTrackOptions.audio.isCreatedByCreateLocalTracks = true;
extraLocalTrackOptions.video.isCreatedByCreateLocalTracks = true;
- if (options.audio && typeof options.audio.workaroundWebKitBug1208516 === 'boolean') {
- extraLocalTrackOptions.audio.workaroundWebKitBug1208516 = options.audio.workaroundWebKitBug1208516;
+ if (typeof fullOptions.audio === 'object' && typeof fullOptions.audio.workaroundWebKitBug1208516 === 'boolean') {
+ extraLocalTrackOptions.audio.workaroundWebKitBug1208516 = fullOptions.audio.workaroundWebKitBug1208516;
}
- if (options.video && typeof options.video.workaroundWebKitBug1208516 === 'boolean') {
- extraLocalTrackOptions.video.workaroundWebKitBug1208516 = options.video.workaroundWebKitBug1208516;
+ if (typeof fullOptions.video === 'object' && typeof fullOptions.video.workaroundWebKitBug1208516 === 'boolean') {
+ extraLocalTrackOptions.video.workaroundWebKitBug1208516 = fullOptions.video.workaroundWebKitBug1208516;
}
- if (options.audio) {
- delete options.audio.name;
+ if (typeof fullOptions.audio === 'object') {
+ delete fullOptions.audio.name;
}
- if (options.video) {
- delete options.video.name;
+ if (typeof fullOptions.video === 'object') {
+ delete fullOptions.video.name;
}
const mediaStreamConstraints = {
- audio: options.audio,
- video: options.video
+ audio: fullOptions.audio,
+ video: fullOptions.video
};
- const workaroundWebKitBug180748 = options.audio && options.audio.workaroundWebKitBug180748;
+ const workaroundWebKitBug180748 = typeof fullOptions.audio === 'object' && fullOptions.audio.workaroundWebKitBug180748;
- const mediaStreamPromise = workaroundWebKitBug180748
- ? workaround180748(log, options.getUserMedia, mediaStreamConstraints)
- : options.getUserMedia(mediaStreamConstraints);
+ try {
+ const mediaStream = await (workaroundWebKitBug180748
+ ? workaround180748(log, fullOptions.getUserMedia, mediaStreamConstraints)
+ : fullOptions.getUserMedia(mediaStreamConstraints));
- return mediaStreamPromise.then(mediaStream => {
- const mediaStreamTracks = mediaStream.getAudioTracks().concat(mediaStream.getVideoTracks());
+ const mediaStreamTracks = [
+ ...mediaStream.getAudioTracks(),
+ ...mediaStream.getVideoTracks(),
+ ];
log.info('Call to getUserMedia successful; got MediaStreamTracks:',
mediaStreamTracks);
- return mediaStreamTracks.map(mediaStreamTrack => asLocalTrack(mediaStreamTrack, Object.assign(
- extraLocalTrackOptions[mediaStreamTrack.kind], localTrackOptions)));
- }, error => {
+ return mediaStreamTracks.map(mediaStreamTrack => asLocalTrack(mediaStreamTrack, {
+ ...extraLocalTrackOptions[mediaStreamTrack.kind as 'audio' | 'video'],
+ ...localTrackOptions,
+ }));
+ } catch (error) {
log.warn('Call to getUserMedia failed:', error);
throw error;
- });
+ }
}
/**
@@ -185,5 +208,3 @@ function createLocalTracks(options) {
* get local video with getUserMedia
when tracks
* are not provided.
*/
-
-module.exports = createLocalTracks;
diff --git a/lib/index.ts b/lib/index.ts
index 3206f42e7..2b2e52037 100644
--- a/lib/index.ts
+++ b/lib/index.ts
@@ -1,15 +1,15 @@
'use strict';
-import type { ConnectOptions, CreateLocalTrackOptions, CreateLocalTracksOptions, LocalTrack } from '../tsdef/types';
+import type { ConnectOptions, CreateLocalTrackOptions } from '../tsdef/types';
import type { LocalAudioTrack as LocalAudioTrackType } from '../tsdef/LocalAudioTrack';
import type { LocalVideoTrack as LocalVideoTrackType } from '../tsdef/LocalVideoTrack';
import type { Log } from '../tsdef/loglevel';
import type { Room } from '../tsdef/Room';
+import { createLocalTracks } from './createlocaltracks';
import { runPreflight } from './preflight/preflighttest';
const internals = {
connect: require('./connect'),
createLocalAudioTrack: require('./createlocaltrack').audio,
- createLocalTracks: require('./createlocaltracks'),
createLocalVideoTrack: require('./createlocaltrack').video,
isSupported: require('./util/support')(),
version: require('../package.json').version,
@@ -20,19 +20,27 @@ const internals = {
};
function connect(token: string, options?: ConnectOptions): Promise {
- return internals.connect(token, options);
+ const internalOptions = {
+ createLocalTracks,
+ ...options
+ };
+ return internals.connect(token, internalOptions);
}
function createLocalAudioTrack(options?: CreateLocalTrackOptions): Promise {
- return internals.createLocalAudioTrack(options);
-}
-
-function createLocalTracks(options?: CreateLocalTracksOptions): Promise {
- return internals.createLocalTracks(options);
+ const internalOptions = {
+ createLocalTracks,
+ ...options
+ };
+ return internals.createLocalAudioTrack(internalOptions);
}
function createLocalVideoTrack(options?: CreateLocalTrackOptions): Promise {
- return internals.createLocalVideoTrack(options);
+ const internalOptions = {
+ createLocalTracks,
+ ...options
+ };
+ return internals.createLocalVideoTrack(internalOptions);
}
/**
@@ -61,8 +69,8 @@ const LocalDataTrack = internals.LocalDataTrack;
module.exports = {
connect,
createLocalAudioTrack,
- createLocalTracks,
createLocalVideoTrack,
+ createLocalTracks,
runPreflight,
isSupported,
version,
diff --git a/package.json b/package.json
index a63b39ca6..8b9e1d160 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
"name": "twilio-video",
"title": "Twilio Video",
"description": "Twilio Video JavaScript Library",
- "version": "2.20.2-dev",
+ "version": "2.21.0-dev",
"homepage": "https://twilio.com",
"author": "Mark Andrus Roberts ",
"contributors": [
@@ -98,9 +98,7 @@
"lint:ts": "eslint ./tsdef/*.ts ./lib/**/*.ts",
"lint": "npm-run-all lint:js lint:ts",
"printVersion": "node --version && npm --version",
- "test:unit": "npm-run-all printVersion build:es5 test:unit:js test:unit:ts",
- "test:unit:js": "nyc --report-dir=./coverage/js --extension=.js --include=lib/**/* --reporter=html --reporter=lcov --reporter=text mocha ./test/unit/index.js",
- "test:unit:ts": "nyc --report-dir=./coverage/ts --extension=.ts --include=lib/**/* --reporter=html --reporter=lcov --reporter=text mocha -r ts-node/register ./test/unit/index.ts",
+ "test:unit": "npm-run-all printVersion build:es5 && nyc --report-dir=./coverage --include=lib/**/* --reporter=html --reporter=lcov --reporter=text mocha -r ts-node/register ./test/unit/*",
"test:serversiderender": "mocha ./test/serversiderender/index.js",
"test:integration:adapter": "node ./scripts/karma.js karma/integration.adapter.conf.js",
"test:integration": "npm run build:es5 && node ./scripts/karma.js karma/integration.conf.js",
@@ -146,7 +144,7 @@
"clean": "rimraf ./coverage ./es5 ./dist"
},
"dependencies": {
- "@twilio/webrtc": "4.5.2",
+ "@twilio/webrtc": "4.6.0",
"backoff": "^2.5.0",
"ws": "^7.4.6",
"xmlhttprequest": "^1.8.0"
diff --git a/scripts/docs.js b/scripts/docs.js
index f19a9bd08..324ec5bf4 100755
--- a/scripts/docs.js
+++ b/scripts/docs.js
@@ -12,7 +12,6 @@ const docs = process.argv[2];
const publicClasses = [
'lib/connect.js',
'lib/createlocaltrack.js',
- 'lib/createlocaltracks.js',
'lib/room.js',
'lib/media/track/index.js',
'lib/media/track/audiotrack.js',
@@ -57,6 +56,7 @@ const publicClasses = [
'lib/util/twilioerror.js',
// TS Files
+ 'lib/createlocaltracks.ts',
'lib/index.ts',
'lib/preflight/preflighttest.ts',
];
diff --git a/test/integration/index.js b/test/integration/index.js
index d9b15e467..4935dbb37 100644
--- a/test/integration/index.js
+++ b/test/integration/index.js
@@ -2,7 +2,7 @@
require('./spec/browserbugs/chromium');
require('./spec/docker/reconnection');
require('./spec/docker/docker');
-require('./spec/bandwidthprofile/publisheerhints.js');
+require('./spec/bandwidthprofile/publisherhints.js');
require('./spec/bandwidthprofile/regressions');
require('./spec/bandwidthprofile/renderhints');
require('./spec/bandwidthprofile/video');
diff --git a/test/integration/spec/audioonlyrooms.js b/test/integration/spec/audioonlyrooms.js
index d98c45ef3..b52342db4 100644
--- a/test/integration/spec/audioonlyrooms.js
+++ b/test/integration/spec/audioonlyrooms.js
@@ -2,7 +2,7 @@
const assert = require('assert');
-const createLocalTracks = require('../../../es5/createlocaltracks');
+const createLocalTracks = require('../../../es5/index').createLocalTracks;
const { RoomTrackKindNotSupportedError } = require('../../../es5/util/twilio-video-errors');
const LocalDataTrack = require('../../../es5/media/track/es5/localdatatrack');
const LocalTrackPublication = require('../../../es5/media/track/localtrackpublication');
diff --git a/test/integration/spec/bandwidthprofile/publisherhints.js b/test/integration/spec/bandwidthprofile/publisherhints.js
index 73de7343a..591c7e266 100644
--- a/test/integration/spec/bandwidthprofile/publisherhints.js
+++ b/test/integration/spec/bandwidthprofile/publisherhints.js
@@ -3,10 +3,8 @@
'use strict';
const assert = require('assert');
-const { video: createLocalVideoTrack, audio: createLocalAudioTrack } = require('../../../../es5/createlocaltrack');
const defaults = require('../../../lib/defaults');
-const { Logger } = require('../../../../es5');
-const connect = require('../../../../es5/connect');
+const { Logger, connect, createLocalAudioTrack, createLocalVideoTrack } = require('../../../../es5');
const { createRoom, completeRoom } = require('../../../lib/rest');
const getToken = require('../../../lib/token');
const { isFirefox } = require('../../../lib/guessbrowser');
diff --git a/test/integration/spec/bandwidthprofile/regressions.js b/test/integration/spec/bandwidthprofile/regressions.js
index 5878e4ced..67933b9f7 100644
--- a/test/integration/spec/bandwidthprofile/regressions.js
+++ b/test/integration/spec/bandwidthprofile/regressions.js
@@ -3,10 +3,9 @@
'use strict';
const assert = require('assert');
-const { audio: createLocalAudioTrack, video: createLocalVideoTrack } = require('../../../../es5/createlocaltrack');
const defaults = require('../../../lib/defaults');
const { completeRoom } = require('../../../lib/rest');
-const { Logger } = require('../../../../es5');
+const { createLocalAudioTrack, createLocalVideoTrack, Logger } = require('../../../../es5');
const {
createSyntheticAudioStreamTrack,
@@ -115,4 +114,3 @@ describe('BandwidthProfileOptions: regressions', function() {
});
});
});
-
diff --git a/test/integration/spec/bandwidthprofile/renderhints.js b/test/integration/spec/bandwidthprofile/renderhints.js
index 25751a915..3d3229b6a 100644
--- a/test/integration/spec/bandwidthprofile/renderhints.js
+++ b/test/integration/spec/bandwidthprofile/renderhints.js
@@ -3,9 +3,8 @@
'use strict';
const assert = require('assert');
-const { video: createLocalVideoTrack } = require('../../../../es5/createlocaltrack');
const defaults = require('../../../lib/defaults');
-const { Logger } = require('../../../../es5');
+const { Logger, createLocalVideoTrack } = require('../../../../es5');
const {
tracksSubscribed,
@@ -382,4 +381,3 @@ describe('BandwidthProfileOptions: renderHints', function() {
});
});
});
-
diff --git a/test/integration/spec/bandwidthprofile/video.js b/test/integration/spec/bandwidthprofile/video.js
index 07b4ccbf8..57ca15aeb 100644
--- a/test/integration/spec/bandwidthprofile/video.js
+++ b/test/integration/spec/bandwidthprofile/video.js
@@ -3,12 +3,10 @@
'use strict';
const assert = require('assert');
-const connect = require('../../../../es5/connect');
-const { audio: createLocalAudioTrack, video: createLocalVideoTrack } = require('../../../../es5/createlocaltrack');
+const { Logger, connect, createLocalAudioTrack, createLocalVideoTrack } = require('../../../../es5');
const defaults = require('../../../lib/defaults');
const { createRoom, completeRoom } = require('../../../lib/rest');
const getToken = require('../../../lib/token');
-const { Logger } = require('../../../../es5');
const {
capitalize,
@@ -193,4 +191,3 @@ describe('BandwidthProfileOptions: video', function() {
});
});
});
-
diff --git a/test/integration/spec/connect.js b/test/integration/spec/connect.js
index 0444a1b9c..f583d169c 100644
--- a/test/integration/spec/connect.js
+++ b/test/integration/spec/connect.js
@@ -6,9 +6,7 @@ const { EventEmitter } = require('events');
const { getUserMedia } = require('@twilio/webrtc');
const sinon = require('sinon');
-const connect = require('../../../es5/connect');
-const { audio: createLocalAudioTrack, video: createLocalVideoTrack } = require('../../../es5/createlocaltrack');
-const createLocalTracks = require('../../../es5/createlocaltracks');
+const { connect, createLocalTracks, createLocalAudioTrack, createLocalVideoTrack } = require('../../../es5');
const LocalDataTrack = require('../../../es5/media/track/es5/localdatatrack');
const Room = require('../../../es5/room');
const { flatMap } = require('../../../es5/util');
diff --git a/test/integration/spec/leaktests.js b/test/integration/spec/leaktests.js
index ad3a8274b..ff3025816 100644
--- a/test/integration/spec/leaktests.js
+++ b/test/integration/spec/leaktests.js
@@ -4,8 +4,7 @@
const assert = require('assert');
const defaults = require('../../lib/defaults');
const { completeRoom, createRoom } = require('../../lib/rest');
-const { audio: createLocalAudioTrack, video: createLocalVideoTrack } = require('../../../lib/createlocaltrack');
-const connect = require('../../../lib/connect');
+const { connect, createLocalAudioTrack, createLocalVideoTrack } = require('../../../es5');
const getToken = require('../../lib/token');
const { isChrome } = require('../../lib/guessbrowser');
diff --git a/test/integration/spec/localtracks.js b/test/integration/spec/localtracks.js
index 3f22eb449..a9ca8ba5e 100644
--- a/test/integration/spec/localtracks.js
+++ b/test/integration/spec/localtracks.js
@@ -17,11 +17,10 @@ const {
waitForSometime
} = require('../../lib/util');
-const createLocalTracks = require('../../../es5/createlocaltrack');
-const connect = require('../../../es5/connect');
+const { connect, createLocalAudioTrack, createLocalVideoTrack } = require('../../../es5');
['audio', 'video'].forEach(kind => {
- const createLocalTrack = createLocalTracks[kind];
+ const createLocalTrack = kind === 'audio' ? createLocalAudioTrack : createLocalVideoTrack;
const description = 'Local' + kind[0].toUpperCase() + kind.slice(1) + 'Track';
const options = {
diff --git a/test/integration/spec/logger.js b/test/integration/spec/logger.js
index 9b4e0928a..c3e3cd3e0 100644
--- a/test/integration/spec/logger.js
+++ b/test/integration/spec/logger.js
@@ -6,7 +6,7 @@ const sinon = require('sinon');
const { Logger } = require('../../../es5');
const defaults = require('../../lib/defaults');
-const defaultConnect = require('../../../es5/connect');
+const defaultConnect = require('../../../es5').connect;
const getToken = require('../../lib/token');
const { createRoom, completeRoom } = require('../../lib/rest');
const { randomName } = require('../../lib/util');
diff --git a/test/integration/spec/remotetracks.js b/test/integration/spec/remotetracks.js
index a16f6cd2d..52746a0f5 100644
--- a/test/integration/spec/remotetracks.js
+++ b/test/integration/spec/remotetracks.js
@@ -6,8 +6,7 @@ const { trackPriority } = require('../../../es5/util/constants');
const LocalDataTrack = require('../../../es5/media/track/es5/localdatatrack');
const defaults = require('../../lib/defaults');
const { completeRoom, createRoom } = require('../../lib/rest');
-const { audio: createLocalAudioTrack, video: createLocalVideoTrack } = require('../../../es5/createlocaltrack');
-const connect = require('../../../es5/connect');
+const { connect, createLocalAudioTrack, createLocalVideoTrack } = require('../../../es5');
const getToken = require('../../lib/token');
const { isFirefox } = require('../../lib/guessbrowser');
diff --git a/test/integration/spec/rest.js b/test/integration/spec/rest.js
index c47b269fa..c9f45d6a9 100644
--- a/test/integration/spec/rest.js
+++ b/test/integration/spec/rest.js
@@ -23,7 +23,7 @@ const {
unsubscribeTrack
} = require('../../lib/rest');
-const connect = require('../../../es5/connect');
+const { connect } = require('../../../es5');
const { RoomMaxParticipantsExceededError } = require('../../../es5/util/twilio-video-errors');
describe('REST APIs', function() {
diff --git a/test/integration/spec/room.js b/test/integration/spec/room.js
index 19a237fa8..c0d9f94b1 100644
--- a/test/integration/spec/room.js
+++ b/test/integration/spec/room.js
@@ -6,6 +6,8 @@ const assert = require('assert');
const {
connect,
createLocalTracks,
+ createLocalAudioTrack,
+ createLocalVideoTrack,
LocalDataTrack
} = require('../../../es5');
@@ -15,7 +17,6 @@ const {
} = require('../../../es5/util/twilio-video-errors');
const { isChrome, isSafari } = require('../../lib/guessbrowser');
-const { audio: createLocalAudioTrack, video: createLocalVideoTrack } = require('../../../es5/createlocaltrack');
const RemoteParticipant = require('../../../es5/remoteparticipant');
const { flatMap, smallVideoConstraints } = require('../../../es5/util');
diff --git a/test/lib/util.js b/test/lib/util.js
index 4600ac51c..e637f658f 100644
--- a/test/lib/util.js
+++ b/test/lib/util.js
@@ -12,7 +12,7 @@ const defaults = require('../lib/defaults');
const getToken = require('../lib/token');
const { ecs } = require('../lib/post');
const { createRoom } = require('../lib/rest');
-const connect = require('../../es5/connect');
+const { connect } = require('../../es5');
const second = 1000;
const assert = require('assert');
diff --git a/test/unit/index.js b/test/unit/index.js
index 0de8be54d..6d528e378 100644
--- a/test/unit/index.js
+++ b/test/unit/index.js
@@ -6,7 +6,6 @@ if (typeof window === 'undefined') {
require('./spec/connect');
require('./spec/createlocaltrack');
-require('./spec/createlocaltracks');
require('./spec/encodingparameters');
require('./spec/localparticipant');
require('./spec/networkqualityconfiguration');
diff --git a/test/unit/index.ts b/test/unit/index.ts
index 80f958c65..49c1f8830 100644
--- a/test/unit/index.ts
+++ b/test/unit/index.ts
@@ -1,3 +1,4 @@
+import './spec/createlocaltracks';
+import './spec/mos';
import './spec/preflight';
import './spec/timer';
-import './spec/mos';
diff --git a/test/unit/spec/connect.js b/test/unit/spec/connect.js
index 47e73b29d..9797aacb2 100644
--- a/test/unit/spec/connect.js
+++ b/test/unit/spec/connect.js
@@ -504,6 +504,10 @@ describe('connect', () => {
it('does not set shouldStopLocalTracks on the LocalParticipant', async () => {
const stream = await fakeGetUserMedia({ audio: true, video: true });
const tracks = stream.getTracks().map(track => new FakeLocalTrack(track));
+ // eslint-disable-next-line require-await
+ async function createLocalTracks() {
+ return tracks;
+ }
const mockSignaling = new Signaling();
mockSignaling.connect = () => Promise.resolve(() => new RoomSignaling());
@@ -517,6 +521,7 @@ describe('connect', () => {
}
await connect(token, {
+ createLocalTracks,
LocalAudioTrack: FakeLocalTrack,
LocalParticipant,
LocalVideoTrack: FakeLocalTrack,
diff --git a/test/unit/spec/createlocaltracks.js b/test/unit/spec/createlocaltracks.ts
similarity index 95%
rename from test/unit/spec/createlocaltracks.js
rename to test/unit/spec/createlocaltracks.ts
index 1bfe7a435..46d4fb767 100644
--- a/test/unit/spec/createlocaltracks.js
+++ b/test/unit/spec/createlocaltracks.ts
@@ -1,11 +1,9 @@
'use strict';
-const assert = require('assert');
-const sinon = require('sinon');
-
-const createLocalTracks = require('../../../lib/createlocaltracks');
-
-const { FakeMediaStreamTrack, fakeGetUserMedia } = require('../../lib/fakemediastream');
+import * as assert from 'assert';
+import * as sinon from 'sinon';
+import { createLocalTracks } from '../../../lib/createlocaltracks';
+import { fakeGetUserMedia, FakeMediaStreamTrack } from '../../lib/fakemediastream';
describe('createLocalTracks', () => {
[
diff --git a/test/unit/spec/util/support.js b/test/unit/spec/util/support.js
index 493696406..be3e152a0 100644
--- a/test/unit/spec/util/support.js
+++ b/test/unit/spec/util/support.js
@@ -81,6 +81,29 @@ describe('isSupported', () => {
'Safari on Mac',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13 Safari/605.1.15'
],
+ [
+ 'Safari WKWebView - iPhone',
+ 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko)',
+ ],
+ [
+ 'Safari WKWebView - iPad',
+ 'Mozilla/5.0 (iPad; CPU OS 15_3 like Mac OS X) AppleWebkit/605.1.15 (KHTML, like Gecko) Mobile/15E148',
+ ],
+ [
+ 'Safari iOS - Instagram',
+ 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 Instagram 220.0.0.8.117 (iPhone12,3; iOS 15_3; en_US; en; scale=3.00; 1125x2436; 347566818) NW/3',
+ 'safari'
+ ],
+ [
+ 'Safari iOS - Snapchat',
+ 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.3 Mobile/15E148 Snapchat/11.64.0.38 (like Safari/8612.4.9.0.3, panda)',
+ 'safari'
+ ],
+ [
+ 'Safari iOS - Slack ',
+ 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.3 Mobile/15E148 Safari/604.1',
+ 'safari'
+ ],
[
'Edge (Chromium) on Mac',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36 Edg/90.0.818.66',
diff --git a/tsdef/ConnectOptionsInternal.d.ts b/tsdef/ConnectOptionsInternal.d.ts
new file mode 100644
index 000000000..a13dd92d0
--- /dev/null
+++ b/tsdef/ConnectOptionsInternal.d.ts
@@ -0,0 +1,5 @@
+import { ConnectOptions } from './types';
+
+export interface ConnectOptionsInternal extends ConnectOptions {
+ createLocalTracks?: any;
+}
diff --git a/tsdef/twilio-video-tests.ts b/tsdef/twilio-video-tests.ts
index 418bd4548..f09be8452 100644
--- a/tsdef/twilio-video-tests.ts
+++ b/tsdef/twilio-video-tests.ts
@@ -229,6 +229,7 @@ function LocalParticipant(localParticipant: Video.LocalParticipant) {
let room: Video.Room | null = null;
let localVideoTrack: Video.LocalVideoTrack | null = null;
let localAudioTrack: Video.LocalAudioTrack | null = null;
+let localTracks: Video.LocalTrack[] | null = null;
// Testing finally method
const maybeRoom = Video.connect('$TOKEN', {
@@ -293,6 +294,13 @@ async function initRoom() {
room.localParticipant.publishTrack(localAudioTrack);
room.participants.forEach(participantConnected);
+ localTracks = await Video.createLocalTracks({ audio: true, video: false });
+ await Video.createLocalTracks({ audio: true });
+ await Video.connect('$TOKEN', {
+ name: 'my-cool-room',
+ tracks: localTracks
+ });
+
room.on('participantConnected', participantConnected);
room.on('participantDisconnected', participantDisconnected);
room.once('disconnected', (room: Video.Room, error: Video.TwilioError) => {
diff --git a/tsdef/types.d.ts b/tsdef/types.d.ts
index 4595db98d..4f2e8bd15 100644
--- a/tsdef/types.d.ts
+++ b/tsdef/types.d.ts
@@ -161,6 +161,7 @@ export interface CreateLocalTrackOptions extends MediaTrackConstraints {
logLevel?: LogLevel | LogLevels;
name?: string;
workaroundWebKitBug180748?: boolean;
+ workaroundWebKitBug1208516?: boolean;
}
export interface ConnectOptions {
@@ -206,6 +207,8 @@ export interface CreateLocalTracksOptions {
* @deprecated
*/
logLevel?: LogLevel | LogLevels;
+ loggerName?: string;
+ tracks?: LocalTrack[];
video?: boolean | CreateLocalTrackOptions;
}