Compare commits

...

31 Commits

Author SHA1 Message Date
David Baker ffd9a01e2f v0.7.12-rc.1 2017-06-15 17:13:26 +01:00
David Baker 25a8c79951 Prepare changelog for v0.7.12-rc.1 2017-06-15 17:13:25 +01:00
Matthew Hodgson c8674ff104 Merge pull request #462 from t3chguy/t3chguy/voip/force_turn
allow setting iceTransportPolicy to relay through forceTURN option
2017-06-12 21:43:50 +01:00
Michael Telatynski a40b10f53c allow setting iceTransportPolicy to relay through forceTURN option
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2017-06-12 20:23:57 +01:00
David Baker 79fa944402 v0.7.11 2017-06-12 15:17:53 +01:00
David Baker ed3cdeec74 Prepare changelog for v0.7.11 2017-06-12 15:17:53 +01:00
David Baker 05d50d457c Merge remote-tracking branch 'origin/develop' into release-v0.7.11 2017-06-12 15:16:18 +01:00
David Baker 2531db84a6 Merge pull request #460 from matrix-org/rav/send_message_logging
Add a bunch of logging around sending messages
2017-06-12 13:37:50 +01:00
Richard van der Hoff 96c1126fe5 Add a bunch of logging around sending messages
In an attempt to diagnose https://github.com/vector-im/riot-web/issues/4278,
add some debug to make the rageshakes more useful.
2017-06-12 13:32:10 +01:00
David Baker bb5038b8b2 v0.7.11-rc.1 2017-06-09 20:23:30 +01:00
David Baker 0c65162349 Prepare changelog for v0.7.11-rc.1 2017-06-09 20:23:29 +01:00
David Baker 17cc12844d Merge pull request #458 from matrix-org/rav/resolve_timeline_window_quickly
Make TimelineWindow.load resolve quicker if we have the events
2017-06-09 20:06:28 +01:00
Richard van der Hoff 6cfcf92a28 Make TimelineWindow.load resolve quicker if we have the events
If we have the events in memory, let TimelineWindow.load() return
a resolved promise, so that the UI can show the view straight away instead
of showing the spinner.
2017-06-09 14:59:11 +01:00
Luke Barnard 6ed9a85dca Add API for POST /user_directory/search (#457)
* Add API for POST /user_directory/search

This takes a JSON body of the form:
```json
{
    "term": "search term",
    "limit": 42,
}
```
where "term" is the term to match against user IDs, display names and domains and "limit" is the maximum number of results to return (which is defaulted server-side).

The response body looks like
```json
{
    "results ": [
        { "user_id": "@someid:mydomain.com", "display_name": "Some Name", "avatar_url": "mx://..." },
        ...
    ],
    "limited": false
}
```
where "limited" indicates whether the "limit" was used to truncate the list.
2017-06-07 15:34:07 +01:00
Luke Barnard 9b188ca87d Use single room object for duration of peek (#453)
Use single room object for duration of peek

Instead of getting the room by ID every time the room is polled for events, which could cause issues if the state of the room is modified from under the peeking logic (if the user joined the room or registered etc.)
2017-06-06 12:15:30 +01:00
David Baker 38baa42ebb Merge pull request #451 from matrix-org/dbkr/stop_peeking
Stop peeking when a matrix client is stopped
2017-06-05 14:16:35 +01:00
David Baker 654322e896 Stop peeking when a matrix client is stopped
Otherwise we get very confused when the peek poll returns after
the client is stopped.
2017-06-05 14:04:41 +01:00
Richard van der Hoff 3f70f532b7 Update README.md
lack of olm is a warning, not an exception
2017-06-05 09:24:59 +01:00
Richard van der Hoff 6ba214a259 Merge pull request #450 from arxcode/develop
Update README: Clarify how to install libolm
2017-06-05 09:22:34 +01:00
arxcode caf73f387f Update README: Clarify how to install libolm 2017-06-04 23:24:11 +02:00
Matthew Hodgson 9a81ca9fab v0.7.10 2017-06-02 01:02:01 +01:00
Matthew Hodgson 0edf19a871 Prepare changelog for v0.7.10 2017-06-02 01:02:01 +01:00
Matthew Hodgson 6989f6c835 switch to using new media constraints to allow device selection to work 2017-06-01 21:57:58 +01:00
Richard van der Hoff de844f1a32 Merge pull request #447 from matrix-org/rav/fix_indexeddb_deletion
indexeddb-crypto-store: fix db deletion
2017-06-01 17:34:37 +01:00
Richard van der Hoff 97951e1c1a Merge pull request #446 from matrix-org/rav/load_olm_from_global
Load Olm from the global rather than requiring it.
2017-06-01 15:41:22 +01:00
Richard van der Hoff 2edbed8528 indexeddb-crypto-store: fix db deletion
Add an `onversionchange` listener to close the db, so that we can delete it
without blocking.
2017-06-01 15:37:27 +01:00
Richard van der Hoff 24937910c7 Merge remote-tracking branch 'origin/develop' into rav/load_olm_from_global 2017-06-01 15:31:27 +01:00
Richard van der Hoff 5cd441fb48 Add a warning to the changelog 2017-06-01 15:30:00 +01:00
Richard van der Hoff 06b956bd75 disable e2e test when there is no e2e 2017-06-01 13:16:10 +01:00
Richard van der Hoff 41864d46c3 Load Olm from the global rather than requiring it.
This means that we can avoid confusing everybody in the world about how to
webpack js-sdk apps.
2017-06-01 13:09:48 +01:00
Matthew Hodgson f6622e0bcd unbreak riot-web release process 2017-06-01 02:41:47 +01:00
15 changed files with 222 additions and 57 deletions
+39
View File
@@ -1,3 +1,42 @@
Changes in [0.7.12-rc.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v0.7.12-rc.1) (2017-06-15)
============================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v0.7.11...v0.7.12-rc.1)
* allow setting iceTransportPolicy to relay through forceTURN option
[\#462](https://github.com/matrix-org/matrix-js-sdk/pull/462)
Changes in [0.7.11](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v0.7.11) (2017-06-12)
==================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v0.7.11-rc.1...v0.7.11)
* Add a bunch of logging around sending messages
[\#460](https://github.com/matrix-org/matrix-js-sdk/pull/460)
Changes in [0.7.11-rc.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v0.7.11-rc.1) (2017-06-09)
============================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v0.7.10...v0.7.11-rc.1)
* Make TimelineWindow.load resolve quicker if we have the events
[\#458](https://github.com/matrix-org/matrix-js-sdk/pull/458)
* Stop peeking when a matrix client is stopped
[\#451](https://github.com/matrix-org/matrix-js-sdk/pull/451)
* Update README: Clarify how to install libolm
[\#450](https://github.com/matrix-org/matrix-js-sdk/pull/450)
Changes in [0.7.10](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v0.7.10) (2017-06-02)
==================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v0.7.9...v0.7.10)
* BREAKING CHANGE: The SDK no longer ``require``s ``olm`` - instead it expects
libolm to be provided as an ``Olm`` global. This will only affect
applications which use end-to-end encryption. See the
[README](README.md#end-to-end-encryption-support) for details.
* indexeddb-crypto-store: fix db deletion
[\#447](https://github.com/matrix-org/matrix-js-sdk/pull/447)
* Load Olm from the global rather than requiring it.
[\#446](https://github.com/matrix-org/matrix-js-sdk/pull/446)
Changes in [0.7.9](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v0.7.9) (2017-06-01)
================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v0.7.8...v0.7.9)
+38 -2
View File
@@ -13,7 +13,8 @@ In a browser
Download either the full or minified version from
https://github.com/matrix-org/matrix-js-sdk/releases/latest and add that as a
``<script>`` to your page. There will be a global variable ``matrixcs``
attached to ``window`` through which you can access the SDK.
attached to ``window`` through which you can access the SDK. See below for how to
include libolm to enable end-to-end-encryption.
Please check [the working browser example](examples/browser) for more information.
@@ -29,8 +30,9 @@ In Node.js
console.log("Public Rooms: %s", JSON.stringify(data));
});
```
See below for how to include libolm to enable end-to-end-encryption. Please check
[the Node.js terminal app](examples/node) for a more complex example.
Please check [the Node.js terminal app](examples/node) for a more complex example.
What does this SDK do?
----------------------
@@ -236,6 +238,40 @@ host the API reference from the source files like this:
Then visit ``http://localhost:8005`` to see the API docs.
End-to-end encryption support
=============================
The SDK supports end-to-end encryption via the Olm and Megolm protocols, using
[libolm](http://matrix.org/git/olm). It is left up to the application to make
libolm available, via the ``Olm`` global.
If the ``Olm`` global is not available, the SDK will show a warning:
```
Unable to load crypto module: crypto will be disabled: Error: global.Olm is not defined
```
The SDK will continue to work for unencrypted rooms, but it will not support
the E2E parts of the Matrix specification.
To enable E2E support in a browser application:
* download the transpiled libolm (from https://matrix.org/packages/npm/olm/).
* load ``olm.js`` as a ``<script>`` *before* ``browser-matrix.js``.
To enable E2E support in a node.js application:
* ``npm install https://matrix.org/packages/npm/olm/olm-2.2.2.tgz``
(replace the URL with the latest version you want to use from
https://matrix.org/packages/npm/olm/)
* ``global.Olm = require('olm');`` *before* loading ``matrix-js-sdk``.
If you want to package Olm as dependency for your node.js application, you
can use ``npm install https://matrix.org/packages/npm/olm/olm-2.2.2.tgz
--save-optional`` (if your application also works without e2e crypto enabled)
or ``--save`` (if it doesn't) to do so.
Contributing
============
*This section is for people who want to modify the SDK. If you just
+2 -9
View File
@@ -1,6 +1,6 @@
{
"name": "matrix-js-sdk",
"version": "0.7.9",
"version": "0.7.12-rc.1",
"description": "Matrix Client-Server SDK for Javascript",
"main": "index.js",
"scripts": {
@@ -73,16 +73,9 @@
"uglify-js": "^2.8.26",
"watchify": "^3.2.1"
},
"optionalDependencies": {
"olm": "https://matrix.org/packages/npm/olm/olm-2.2.1.tgz"
},
"browserify": {
"transform": [
"sourceify",
"browserify-shim"
"sourceify"
]
},
"browserify-shim": {
"olm": "global:Olm"
}
}
+3 -1
View File
@@ -206,7 +206,9 @@ if [ -n "$signing_id" ]; then
tarfile="$tag.tar.gz"
gh_project_url=$(git remote get-url origin |
sed -e 's#^git@github.com:#https://github.com/#' -e 's/\.git$//')
sed -e 's#^git@github\.com:#https://github.com/#' \
-e 's#^git\+ssh://git@github\.com/#https://github.com/#' \
-e 's/\.git$//')
project_name="${gh_project_url##*/}"
curl -L "${gh_project_url}/archive/${tarfile}" -o "${tarfile}"
+4
View File
@@ -299,6 +299,10 @@ describe("MatrixClient", function() {
describe("downloadKeys", function() {
if (!sdk.CRYPTO_ENABLED) {
return;
}
it("should do an HTTP request and then store the keys", function(done) {
const ed25519key = "7wG2lzAqbjcyEkOP7O4gU7ItYcn+chKzh5sT/5r2l78";
// ed25519key = client.getDeviceEd25519Key();
+25
View File
@@ -678,6 +678,31 @@ MatrixBaseApis.prototype.setRoomDirectoryVisibilityAppService =
);
};
// User Directory Operations
// =========================
/**
* Query the user directory with a term matching user IDs, display names and domains.
* @param {object} opts options
* @param {string} opts.term the term with which to search.
* @param {number} opts.limit the maximum number of results to return. The server will
* apply a limit if unspecified.
* @return {module:client.Promise} Resolves: an array of results.
*/
MatrixBaseApis.prototype.searchUserDirectory = function(opts) {
const body = {
search_term: opts.term,
};
if (opts.limit !== undefined) {
body.limit = opts.limit;
}
return this._http.authedRequest(
undefined, "POST", "/user_directory/search", undefined, body,
);
};
// Media operations
// ================
+12 -3
View File
@@ -47,8 +47,7 @@ try {
var Crypto = require("./crypto");
CRYPTO_ENABLED = true;
} catch (e) {
console.error("olm load error", e);
// Olm not installed.
console.warn("Unable to load crypto module: crypto will be disabled: " + e);
}
/**
@@ -942,6 +941,8 @@ MatrixClient.prototype.sendEvent = function(roomId, eventType, content, txnId,
txnId = this.makeTxnId();
}
console.log(`sendEvent of type ${eventType} in ${roomId} with txnId ${txnId}`);
// we always construct a MatrixEvent when sending because the store and
// scheduler use them. We'll extract the params back out if it turns out
// the client has no scheduler or store.
@@ -1066,7 +1067,12 @@ function _sendEventHttpRequest(client, event) {
return client._http.authedRequest(
undefined, "PUT", path, undefined, event.getWireContent(),
);
).then((res) => {
console.log(
`Event sent to ${event.getRoomId()} with event id ${res.event_id}`,
);
return res;
});
}
/**
@@ -2889,6 +2895,9 @@ MatrixClient.prototype.stopClient = function() {
this._syncApi.stop();
this._syncApi = null;
}
if (this._peekSync) {
this._peekSync.stopPeeking();
}
global.clearTimeout(this._checkTurnServersTimeoutID);
};
+8
View File
@@ -76,6 +76,10 @@ export default class DeviceList {
if (this._keyDownloadsInProgressByUser[u]) {
// already a key download in progress/queued for this user; its results
// will be good enough for us.
console.log(
`downloadKeys: already have a download in progress for ` +
`${u}: awaiting its result`,
);
promises.push(this._keyDownloadsInProgressByUser[u]);
} else if (forceDownload || trackingStatus != TRACKING_STATUS_UP_TO_DATE) {
usersToDownload.push(u);
@@ -88,6 +92,10 @@ export default class DeviceList {
promises.push(downloadPromise);
}
if (promises.length === 0) {
console.log("downloadKeys: already have all necessary keys");
}
return q.all(promises).then(() => {
return this._getDevicesFromStore(userIds);
});
+2 -4
View File
@@ -20,11 +20,9 @@ limitations under the License.
*
* @module crypto/OlmDevice
*/
const Olm = require("olm");
const Olm = global.Olm;
if (!Olm) {
// this happens if we were loaded via browserify and the Olm module was not
// loaded.
throw new Error("Olm is not defined");
throw new Error("global.Olm is not defined");
}
const utils = require("../utils");
+5
View File
@@ -183,6 +183,7 @@ MegolmEncryption.prototype._ensureOutboundSession = function(devicesInRoom) {
}
if (!session) {
console.log(`Starting new megolm session for room ${self._roomId}`);
session = self._prepareNewSession();
}
@@ -353,6 +354,8 @@ MegolmEncryption.prototype._shareKeyWithDevices = function(session, devicesByUse
// TODO: retries
return self._baseApis.sendToDevice("m.room.encrypted", contentMap);
}).then(function() {
console.log(`Completed megolm keyshare in ${self._roomId}`);
// Add the devices we have shared with to session.sharedWithDevices.
//
// we deliberately iterate over devicesByUser (ie, the devices we
@@ -387,6 +390,8 @@ MegolmEncryption.prototype._shareKeyWithDevices = function(session, devicesByUse
*/
MegolmEncryption.prototype.encryptMessage = function(room, eventType, content) {
const self = this;
console.log(`Starting to encrypt event for ${this._roomId}`);
return this._getDevicesInRoom(room).then(function(devicesInRoom) {
// check if any of these devices are not yet known to the user.
// if so, warn the user so they can verify or ignore.
+18 -1
View File
@@ -55,6 +55,7 @@ export default class IndexedDBCryptoStore {
}
this._dbPromise = new q.Promise((resolve, reject) => {
console.log(`connecting to indexeddb ${this._dbName}`);
const req = this._indexedDB.open(this._dbName, VERSION);
req.onupgradeneeded = (ev) => {
@@ -83,7 +84,16 @@ export default class IndexedDBCryptoStore {
};
req.onsuccess = (r) => {
resolve(r.target.result);
const db = r.target.result;
// make sure we close the db on `onversionchange` - otherwise
// attempts to delete the database will block (and subsequent
// attempts to re-create it will also block).
db.onversionchange = (ev) => {
db.close();
};
resolve(db);
};
});
return this._dbPromise;
@@ -98,6 +108,13 @@ export default class IndexedDBCryptoStore {
return new q.Promise((resolve, reject) => {
console.log(`Removing indexeddb instance: ${this._dbName}`);
const req = this._indexedDB.deleteDatabase(this._dbName);
req.onblocked = () => {
reject(new Error(
"unable to delete indexeddb because it is open elsewhere",
));
};
req.onerror = (ev) => {
reject(new Error(
"unable to delete indexeddb: " + ev.target.error,
+2
View File
@@ -752,6 +752,8 @@ ALLOWED_TRANSITIONS[EventStatus.CANCELLED] =
* @fires module:client~MatrixClient#event:"Room.localEchoUpdated"
*/
Room.prototype.updatePendingEvent = function(event, newStatus, newEventId) {
console.log(`setting pendingEvent status to ${newStatus} in ${event.getRoomId()}`);
// if the message was sent, we expect an event id
if (newStatus == EventStatus.SENT && !newEventId) {
throw new Error("updatePendingEvent called with status=SENT, " +
+16 -12
View File
@@ -298,7 +298,7 @@ SyncApi.prototype.peek = function(roomId) {
client.store.storeRoom(peekRoom);
client.emit("Room", peekRoom);
self._peekPoll(roomId);
self._peekPoll(peekRoom);
return peekRoom;
});
};
@@ -313,22 +313,26 @@ SyncApi.prototype.stopPeeking = function() {
/**
* Do a peek room poll.
* @param {string} roomId
* @param {Room} peekRoom
* @param {string} token from= token
*/
SyncApi.prototype._peekPoll = function(roomId, token) {
if (this._peekRoomId !== roomId) {
debuglog("Stopped peeking in room %s", roomId);
SyncApi.prototype._peekPoll = function(peekRoom, token) {
if (this._peekRoomId !== peekRoom.roomId) {
debuglog("Stopped peeking in room %s", peekRoom.roomId);
return;
}
const self = this;
// FIXME: gut wrenching; hard-coded timeout values
this.client._http.authedRequest(undefined, "GET", "/events", {
room_id: roomId,
room_id: peekRoom.roomId,
timeout: 30 * 1000,
from: token,
}, undefined, 50 * 1000).done(function(res) {
if (self._peekRoomId !== peekRoom.roomId) {
debuglog("Stopped peeking in room %s", peekRoom.roomId);
return;
}
// We have a problem that we get presence both from /events and /sync
// however, /sync only returns presence for users in rooms
// you're actually joined to.
@@ -354,15 +358,15 @@ SyncApi.prototype._peekPoll = function(roomId, token) {
// strip out events which aren't for the given room_id (e.g presence)
const events = res.chunk.filter(function(e) {
return e.room_id === roomId;
return e.room_id === peekRoom.roomId;
}).map(self.client.getEventMapper());
const room = self.client.getRoom(roomId);
room.addLiveEvents(events);
self._peekPoll(roomId, res.end);
peekRoom.addLiveEvents(events);
self._peekPoll(peekRoom, res.end);
}, function(err) {
console.error("[%s] Peek poll failed: %s", roomId, err);
console.error("[%s] Peek poll failed: %s", peekRoom.roomId, err);
setTimeout(function() {
self._peekPoll(roomId, token);
self._peekPoll(peekRoom, token);
}, 30 * 1000);
});
};
+33 -18
View File
@@ -95,10 +95,30 @@ TimelineWindow.prototype.load = function(initialEventId, initialWindowSize) {
const self = this;
initialWindowSize = initialWindowSize || 20;
// given an EventTimeline, and an event index within it, initialise our
// given an EventTimeline, find the event we were looking for, and initialise our
// fields so that the event in question is in the middle of the window.
const initFields = function(timeline, eventIndex) {
const endIndex = Math.min(timeline.getEvents().length,
const initFields = function(timeline) {
let eventIndex;
const events = timeline.getEvents();
if (!initialEventId) {
// we were looking for the live timeline: initialise to the end
eventIndex = events.length;
} else {
for (let i = 0; i < events.length; i++) {
if (events[i].getId() == initialEventId) {
eventIndex = i;
break;
}
}
if (eventIndex === undefined) {
throw new Error("getEventTimeline result didn't include requested event");
}
}
const endIndex = Math.min(events.length,
eventIndex + Math.ceil(initialWindowSize / 2));
const startIndex = Math.max(0, endIndex - initialWindowSize);
self._start = new TimelineIndex(timeline, startIndex - timeline.getBaseIndex());
@@ -110,24 +130,19 @@ TimelineWindow.prototype.load = function(initialEventId, initialWindowSize) {
// we already have the data we need, which is important to keep room-switching
// feeling snappy.
//
// TODO: ideally we'd spot getEventTimeline returning a resolved promise and
// skip straight to the find-event loop.
if (initialEventId) {
return this._client.getEventTimeline(this._timelineSet, initialEventId)
.then(function(tl) {
// make sure that our window includes the event
for (let i = 0; i < tl.getEvents().length; i++) {
if (tl.getEvents()[i].getId() == initialEventId) {
initFields(tl, i);
return;
}
}
throw new Error("getEventTimeline result didn't include requested event");
});
const prom = this._client.getEventTimeline(this._timelineSet, initialEventId);
const promState = prom.inspect();
if (promState.state == 'fulfilled') {
initFields(promState.value);
return q();
} else {
return prom.then(initFields);
}
} else {
// start with the most recent events
const tl = this._timelineSet.getLiveTimeline();
initFields(tl, tl.getEvents().length);
initFields(tl);
return q();
}
};
+15 -7
View File
@@ -71,6 +71,7 @@ const DEBUG = true; // set true to enable console logging.
* @param {Object} opts Config options.
* @param {string} opts.roomId The room ID for this call.
* @param {Object} opts.webRtc The WebRTC globals from the browser.
* @param {boolean} opts.forceTURN whether relay through TURN should be forced.
* @param {Object} opts.URL The URL global.
* @param {Array<Object>} opts.turnServers Optional. A list of TURN servers.
* @param {MatrixClient} opts.client The Matrix Client instance to send events to.
@@ -79,6 +80,7 @@ function MatrixCall(opts) {
this.roomId = opts.roomId;
this.client = opts.client;
this.webRtc = opts.webRtc;
this.forceTURN = opts.forceTURN;
this.URL = opts.URL;
// Array of Objects with urls, username, credential keys
this.turnServers = opts.turnServers || [];
@@ -1184,6 +1186,7 @@ const _createPeerConnection = function(self) {
}
const pc = new self.webRtc.RtcPeerConnection({
iceTransportPolicy: self.forceTURN ? 'relay' : undefined,
iceServers: servers,
});
pc.oniceconnectionstatechange = hookCallback(self, self._onIceConnectionStateChanged);
@@ -1219,6 +1222,8 @@ const _getScreenSharingConstraints = function(call) {
};
const _getUserMediaVideoContraints = function(callType) {
const isWebkit = !!global.window.navigator.webkitGetUserMedia;
switch (callType) {
case 'voice':
return {
@@ -1232,12 +1237,11 @@ const _getUserMediaVideoContraints = function(callType) {
deviceId: audioInput ? {exact: audioInput} : undefined,
}, video: {
deviceId: videoInput ? {exact: videoInput} : undefined,
mandatory: {
minWidth: 640,
maxWidth: 640,
minHeight: 360,
maxHeight: 360,
},
/* We want 640x360. Chrome will give it only if we ask exactly,
FF refuses entirely if we ask exactly, so have to ask for ideal
instead */
width: isWebkit ? { exact: 640 } : { ideal: 640 },
height: isWebkit ? { exact: 360 } : { ideal: 360 },
},
};
}
@@ -1292,9 +1296,11 @@ module.exports.setVideoInput = function(deviceId) { videoInput = deviceId; };
* Create a new Matrix call for the browser.
* @param {MatrixClient} client The client instance to use.
* @param {string} roomId The room the call is in.
* @param {Object?} options optional options map.
* @param {boolean} options.forceTURN whether relay through TURN should be forced.
* @return {MatrixCall} the call or null if the browser doesn't support calling.
*/
module.exports.createNewMatrixCall = function(client, roomId) {
module.exports.createNewMatrixCall = function(client, roomId, options) {
const w = global.window;
const doc = global.document;
if (!w || !doc) {
@@ -1350,6 +1356,8 @@ module.exports.createNewMatrixCall = function(client, roomId) {
URL: w.URL,
roomId: roomId,
turnServers: client.getTurnServers(),
// call level options
forceTURN: options ? options.forceTURN : false,
};
return new MatrixCall(opts);
};