Compare commits
1 Commits
main
...
v2.8.2-rc.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
65fbea6729 |
Binary file not shown.
Binary file not shown.
Binary file not shown.
2
dist/index.d.ts
vendored
2
dist/index.d.ts
vendored
@ -1,4 +1,4 @@
|
||||
export { AudioDevice, BandwidthMode, Call, CallId, CallEndedReason, CallLogLevel, CallState, CallingMessage, CallSettings, ConnectionState, DeviceId, GroupCall, GroupCallEndReason, GroupCallObserver, GroupMemberInfo, HangupMessage, HangupType, HttpMethod, JoinState, LocalDeviceState, OfferType, OpaqueMessage, RemoteDeviceState, RenderedResolution, RingRTCType, UserId, VideoCapturer, VideoRenderer } from './ringrtc/Service';
|
||||
export { AudioDevice, BandwidthMode, Call, CallId, CallEndedReason, CallLogLevel, CallState, CallingMessage, CallSettings, ConnectionState, DeviceId, GroupCall, GroupCallEndReason, GroupCallObserver, GroupMemberInfo, HangupMessage, HangupType, HttpMethod, JoinState, LocalDeviceState, OfferType, OpaqueMessage, RemoteDeviceState, RingRTCType, UserId, VideoCapturer, VideoRenderer, VideoRequest } from './ringrtc/Service';
|
||||
export { CanvasVideoRenderer, GumVideoCapturer, VideoFrameSource, } from './ringrtc/VideoSupport';
|
||||
import { RingRTCType } from './ringrtc/Service';
|
||||
export declare const RingRTC: RingRTCType;
|
||||
|
||||
2
dist/index.js
vendored
2
dist/index.js
vendored
@ -25,8 +25,8 @@ exports.LocalDeviceState = Service_1.LocalDeviceState;
|
||||
exports.OfferType = Service_1.OfferType;
|
||||
exports.OpaqueMessage = Service_1.OpaqueMessage;
|
||||
exports.RemoteDeviceState = Service_1.RemoteDeviceState;
|
||||
exports.RenderedResolution = Service_1.RenderedResolution;
|
||||
exports.RingRTCType = Service_1.RingRTCType;
|
||||
exports.VideoRequest = Service_1.VideoRequest;
|
||||
var VideoSupport_1 = require("./ringrtc/VideoSupport");
|
||||
exports.CanvasVideoRenderer = VideoSupport_1.CanvasVideoRenderer;
|
||||
exports.GumVideoCapturer = VideoSupport_1.GumVideoCapturer;
|
||||
|
||||
51
dist/ringrtc/Service.d.ts
vendored
51
dist/ringrtc/Service.d.ts
vendored
@ -1,7 +1,17 @@
|
||||
declare type GroupCallUserId = ArrayBuffer;
|
||||
export declare class PeekInfo {
|
||||
joinedMembers: Array<GroupCallUserId>;
|
||||
creator?: GroupCallUserId;
|
||||
eraId?: string;
|
||||
maxDevices?: number;
|
||||
deviceCount: number;
|
||||
constructor();
|
||||
}
|
||||
export declare class RingRTCType {
|
||||
private readonly callManager;
|
||||
private _call;
|
||||
private _groupCallByClientId;
|
||||
private _peekRequests;
|
||||
handleOutgoingSignaling: ((remoteUserId: UserId, message: CallingMessage) => Promise<boolean>) | null;
|
||||
handleIncomingCall: ((call: Call) => Promise<CallSettings | null>) | null;
|
||||
handleAutoEndedIncomingCallRequest: ((remoteUserId: UserId, reason: CallEndedReason) => void) | null;
|
||||
@ -29,13 +39,15 @@ export declare class RingRTCType {
|
||||
private sendSignaling;
|
||||
receivedHttpResponse(requestId: number, status: number, body: ArrayBuffer): void;
|
||||
httpRequestFailed(requestId: number, debugInfo: string | undefined): void;
|
||||
getGroupCall(groupId: ArrayBuffer, observer: GroupCallObserver): GroupCall | undefined;
|
||||
getGroupCall(groupId: ArrayBuffer, sfuUrl: string, observer: GroupCallObserver): GroupCall | undefined;
|
||||
peekGroupCall(sfu_url: string, membership_proof: ArrayBuffer, group_members: Array<GroupMemberInfo>): Promise<PeekInfo>;
|
||||
requestMembershipProof(clientId: GroupCallClientId): void;
|
||||
requestGroupMembers(clientId: GroupCallClientId): void;
|
||||
handleConnectionStateChanged(clientId: GroupCallClientId, connectionState: ConnectionState): void;
|
||||
handleJoinStateChanged(clientId: GroupCallClientId, joinState: JoinState): void;
|
||||
handleRemoteDevicesChanged(clientId: GroupCallClientId, remoteDeviceStates: Array<RemoteDeviceState>): void;
|
||||
handleJoinedMembersChanged(clientId: GroupCallClientId, members: Array<ArrayBuffer>): void;
|
||||
handlePeekChanged(clientId: GroupCallClientId, info: PeekInfo): void;
|
||||
handlePeekResponse(request_id: number, info: PeekInfo): void;
|
||||
handleEnded(clientId: GroupCallClientId, reason: GroupCallEndReason): void;
|
||||
onLogMessage(level: number, fileName: string, line: number, message: string): void;
|
||||
handleCallingMessage(remoteUserId: UserId, remoteUuid: ArrayBuffer | null, remoteDeviceId: DeviceId, localDeviceId: DeviceId, messageAgeSec: number, message: CallingMessage, senderIdentityKey: ArrayBuffer, receiverIdentityKey: ArrayBuffer): void;
|
||||
@ -159,7 +171,8 @@ export declare enum GroupCallEndReason {
|
||||
export declare enum HttpMethod {
|
||||
Get = 0,
|
||||
Put = 1,
|
||||
Post = 2
|
||||
Post = 2,
|
||||
Delete = 3
|
||||
}
|
||||
export declare class LocalDeviceState {
|
||||
connectionState: ConnectionState;
|
||||
@ -171,19 +184,20 @@ export declare class LocalDeviceState {
|
||||
export declare class RemoteDeviceState {
|
||||
demuxId: number;
|
||||
userId: ArrayBuffer;
|
||||
mediaKeysReceived: boolean;
|
||||
audioMuted: boolean | undefined;
|
||||
videoMuted: boolean | undefined;
|
||||
speakerIndex: number | undefined;
|
||||
videoAspectRatio: number | undefined;
|
||||
audioLevel: number | undefined;
|
||||
constructor(demuxId: number, userId: ArrayBuffer);
|
||||
constructor(demuxId: number, userId: ArrayBuffer, mediaKeysReceived: boolean);
|
||||
}
|
||||
export declare class GroupMemberInfo {
|
||||
userId: ArrayBuffer;
|
||||
userIdCipherText: ArrayBuffer;
|
||||
constructor(userId: ArrayBuffer, userIdCipherText: ArrayBuffer);
|
||||
}
|
||||
export declare class RenderedResolution {
|
||||
export declare class VideoRequest {
|
||||
demuxId: number;
|
||||
width: number;
|
||||
height: number;
|
||||
@ -195,7 +209,7 @@ export interface GroupCallObserver {
|
||||
requestGroupMembers(groupCall: GroupCall): void;
|
||||
onLocalDeviceStateChanged(groupCall: GroupCall): void;
|
||||
onRemoteDeviceStatesChanged(groupCall: GroupCall): void;
|
||||
onJoinedMembersChanged(groupCall: GroupCall): void;
|
||||
onPeekChanged(groupCall: GroupCall): void;
|
||||
onEnded(groupCall: GroupCall, reason: GroupCallEndReason): void;
|
||||
}
|
||||
export declare class GroupCall {
|
||||
@ -205,19 +219,20 @@ export declare class GroupCall {
|
||||
get clientId(): GroupCallClientId;
|
||||
private _localDeviceState;
|
||||
private _remoteDeviceStates;
|
||||
private _joinedGroupMembers;
|
||||
constructor(callManager: CallManager, groupId: ArrayBuffer, observer: GroupCallObserver);
|
||||
private _peekInfo;
|
||||
constructor(callManager: CallManager, groupId: ArrayBuffer, sfuUrl: string, observer: GroupCallObserver);
|
||||
connect(): void;
|
||||
join(): void;
|
||||
leave(): void;
|
||||
disconnect(): void;
|
||||
getLocalDeviceState(): LocalDeviceState;
|
||||
getRemoteDeviceStates(): Array<RemoteDeviceState> | undefined;
|
||||
getJoinedGroupMembers(): Array<ArrayBuffer> | undefined;
|
||||
getPeekInfo(): PeekInfo | undefined;
|
||||
setOutgoingAudioMuted(muted: boolean): void;
|
||||
setOutgoingVideoMuted(muted: boolean): void;
|
||||
resendMediaKeys(): void;
|
||||
setBandwidthMode(bandwidthMode: BandwidthMode): void;
|
||||
setRenderedResolutions(resolutions: Array<RenderedResolution>): void;
|
||||
requestVideo(resolutions: Array<VideoRequest>): void;
|
||||
setGroupMembers(members: Array<GroupMemberInfo>): void;
|
||||
setMembershipProof(proof: ArrayBuffer): void;
|
||||
requestMembershipProof(): void;
|
||||
@ -225,16 +240,17 @@ export declare class GroupCall {
|
||||
handleConnectionStateChanged(connectionState: ConnectionState): void;
|
||||
handleJoinStateChanged(joinState: JoinState): void;
|
||||
handleRemoteDevicesChanged(remoteDeviceStates: Array<RemoteDeviceState>): void;
|
||||
handleJoinedMembersChanged(members: Array<ArrayBuffer>): void;
|
||||
handlePeekChanged(info: PeekInfo): void;
|
||||
handleEnded(reason: GroupCallEndReason): void;
|
||||
sendVideoFrame(width: number, height: number, rgbaBuffer: ArrayBuffer): void;
|
||||
getVideoSource(remoteDemuxId: number): GroupCallVideoFrameSource;
|
||||
setRemoteAspectRatio(remoteDemuxId: number, aspectRatio: number): void;
|
||||
}
|
||||
declare class GroupCallVideoFrameSource {
|
||||
private readonly _callManager;
|
||||
private readonly _clientId;
|
||||
private readonly _groupCall;
|
||||
private readonly _remoteDemuxId;
|
||||
constructor(callManager: CallManager, clientId: GroupCallClientId, remoteDemuxId: number);
|
||||
constructor(callManager: CallManager, groupCall: GroupCall, remoteDemuxId: number);
|
||||
receiveVideoFrame(buffer: ArrayBuffer): [number, number] | undefined;
|
||||
}
|
||||
declare type ProtobufArrayBuffer = ArrayBuffer | {
|
||||
@ -315,7 +331,7 @@ export interface CallManager {
|
||||
receivedCallMessage(remoteUserId: ArrayBuffer, remoteDeviceId: DeviceId, localDeviceId: DeviceId, data: ArrayBuffer, messageAgeSec: number): void;
|
||||
receivedHttpResponse(requestId: number, status: number, body: ArrayBuffer): void;
|
||||
httpRequestFailed(requestId: number, debugInfo: string | undefined): void;
|
||||
createGroupCallClient(groupId: ArrayBuffer): GroupCallClientId;
|
||||
createGroupCallClient(groupId: ArrayBuffer, sfuUrl: string): GroupCallClientId;
|
||||
deleteGroupCallClient(clientId: GroupCallClientId): void;
|
||||
connect(clientId: GroupCallClientId): void;
|
||||
join(clientId: GroupCallClientId): void;
|
||||
@ -323,11 +339,13 @@ export interface CallManager {
|
||||
disconnect(clientId: GroupCallClientId): void;
|
||||
setOutgoingAudioMuted(clientId: GroupCallClientId, muted: boolean): void;
|
||||
setOutgoingVideoMuted(clientId: GroupCallClientId, muted: boolean): void;
|
||||
resendMediaKeys(clientId: GroupCallClientId): void;
|
||||
setBandwidthMode(clientId: GroupCallClientId, bandwidthMode: BandwidthMode): void;
|
||||
setRenderedResolutions(clientId: GroupCallClientId, resolutions: Array<RenderedResolution>): void;
|
||||
requestVideo(clientId: GroupCallClientId, resolutions: Array<VideoRequest>): void;
|
||||
setGroupMembers(clientId: GroupCallClientId, members: Array<GroupMemberInfo>): void;
|
||||
setMembershipProof(clientId: GroupCallClientId, proof: ArrayBuffer): void;
|
||||
receiveGroupCallVideoFrame(clientId: GroupCallClientId, remoteDemuxId: number, buffer: ArrayBuffer): [number, number] | undefined;
|
||||
peekGroupCall(requestId: number, sfu_url: string, membership_proof: ArrayBuffer, group_members: Array<GroupMemberInfo>): Promise<PeekInfo>;
|
||||
getAudioInputs(): AudioDevice[];
|
||||
setAudioInput(index: number): void;
|
||||
getAudioOutputs(): AudioDevice[];
|
||||
@ -355,7 +373,8 @@ export interface CallManagerCallbacks {
|
||||
handleConnectionStateChanged(clientId: GroupCallClientId, connectionState: ConnectionState): void;
|
||||
handleJoinStateChanged(clientId: GroupCallClientId, joinState: JoinState): void;
|
||||
handleRemoteDevicesChanged(clientId: GroupCallClientId, remoteDeviceStates: Array<RemoteDeviceState>): void;
|
||||
handleJoinedMembersChanged(clientId: GroupCallClientId, members: Array<ArrayBuffer>): void;
|
||||
handlePeekChanged(clientId: GroupCallClientId, info: PeekInfo): void;
|
||||
handlePeekResponse(request_id: number, info: PeekInfo): void;
|
||||
handleEnded(clientId: GroupCallClientId, reason: GroupCallEndReason): void;
|
||||
onLogMessage(level: number, fileName: string, line: number, message: string): void;
|
||||
}
|
||||
|
||||
221
dist/ringrtc/Service.js
vendored
221
dist/ringrtc/Service.js
vendored
@ -19,6 +19,35 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const os = require('os');
|
||||
// tslint:disable-next-line no-var-requires no-require-imports
|
||||
const Native = require('../../build/' + os.platform() + '/libringrtc.node');
|
||||
class PeekInfo {
|
||||
constructor() {
|
||||
this.joinedMembers = [];
|
||||
this.deviceCount = 0;
|
||||
}
|
||||
}
|
||||
exports.PeekInfo = PeekInfo;
|
||||
class Requests {
|
||||
constructor() {
|
||||
this._resolveById = new Map();
|
||||
this._nextId = 1;
|
||||
}
|
||||
add() {
|
||||
const id = this._nextId++;
|
||||
const promise = new Promise((resolve, _reject) => {
|
||||
this._resolveById.set(id, resolve);
|
||||
});
|
||||
return [id, promise];
|
||||
}
|
||||
resolve(id, response) {
|
||||
const resolve = this._resolveById.get(id);
|
||||
if (!resolve) {
|
||||
return false;
|
||||
}
|
||||
resolve(response);
|
||||
this._resolveById.delete(id);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class RingRTCType {
|
||||
constructor() {
|
||||
// Set by UX
|
||||
@ -31,6 +60,7 @@ class RingRTCType {
|
||||
this.callManager = new Native.CallManager();
|
||||
this._call = null;
|
||||
this._groupCallByClientId = new Map();
|
||||
this._peekRequests = new Requests();
|
||||
this.pollEvery(50);
|
||||
}
|
||||
pollEvery(intervalMs) {
|
||||
@ -90,13 +120,9 @@ class RingRTCType {
|
||||
}))();
|
||||
}
|
||||
proceed(callId, settings) {
|
||||
// tslint:disable no-floating-promises
|
||||
(() => __awaiter(this, void 0, void 0, function* () {
|
||||
// This is a silly way of causing a deadlock.
|
||||
// tslint:disable-next-line await-promise
|
||||
yield 0;
|
||||
silly_deadlock_protection(() => {
|
||||
this.callManager.proceed(callId, settings.iceServer.username || '', settings.iceServer.password || '', settings.iceServer.urls, settings.hideIp);
|
||||
}))();
|
||||
});
|
||||
}
|
||||
// Called by Rust
|
||||
onCallState(remoteUserId, state) {
|
||||
@ -232,22 +258,47 @@ class RingRTCType {
|
||||
}))();
|
||||
}
|
||||
receivedHttpResponse(requestId, status, body) {
|
||||
this.callManager.receivedHttpResponse(requestId, status, body);
|
||||
silly_deadlock_protection(() => {
|
||||
try {
|
||||
this.callManager.receivedHttpResponse(requestId, status, body);
|
||||
}
|
||||
catch (_a) {
|
||||
// We may not have an active connection any more.
|
||||
// In which case it doesn't matter
|
||||
}
|
||||
});
|
||||
}
|
||||
httpRequestFailed(requestId, debugInfo) {
|
||||
this.callManager.httpRequestFailed(requestId, debugInfo);
|
||||
silly_deadlock_protection(() => {
|
||||
try {
|
||||
this.callManager.httpRequestFailed(requestId, debugInfo);
|
||||
}
|
||||
catch (_a) {
|
||||
// We may not have an active connection any more.
|
||||
// In which case it doesn't matter
|
||||
}
|
||||
});
|
||||
}
|
||||
// Group Calls
|
||||
// Called by UX
|
||||
getGroupCall(groupId, observer) {
|
||||
const groupCall = new GroupCall(this.callManager, groupId, observer);
|
||||
getGroupCall(groupId, sfuUrl, observer) {
|
||||
const groupCall = new GroupCall(this.callManager, groupId, sfuUrl, observer);
|
||||
this._groupCallByClientId.set(groupCall.clientId, groupCall);
|
||||
return groupCall;
|
||||
}
|
||||
// Called by UX
|
||||
// Returns a list of user IDs
|
||||
peekGroupCall(sfu_url, membership_proof, group_members) {
|
||||
let [requestId, promise] = this._peekRequests.add();
|
||||
// Response comes back via handlePeekResponse
|
||||
silly_deadlock_protection(() => {
|
||||
this.callManager.peekGroupCall(requestId, sfu_url, membership_proof, group_members);
|
||||
});
|
||||
return promise;
|
||||
}
|
||||
// Called by Rust
|
||||
requestMembershipProof(clientId) {
|
||||
(() => __awaiter(this, void 0, void 0, function* () {
|
||||
yield 0;
|
||||
silly_deadlock_protection(() => {
|
||||
let groupCall = this._groupCallByClientId.get(clientId);
|
||||
if (!groupCall) {
|
||||
let error = new Error();
|
||||
@ -255,12 +306,11 @@ class RingRTCType {
|
||||
return;
|
||||
}
|
||||
groupCall.requestMembershipProof();
|
||||
}))();
|
||||
});
|
||||
}
|
||||
// Called by Rust
|
||||
requestGroupMembers(clientId) {
|
||||
(() => __awaiter(this, void 0, void 0, function* () {
|
||||
yield 0;
|
||||
silly_deadlock_protection(() => {
|
||||
let groupCall = this._groupCallByClientId.get(clientId);
|
||||
if (!groupCall) {
|
||||
let error = new Error();
|
||||
@ -268,12 +318,11 @@ class RingRTCType {
|
||||
return;
|
||||
}
|
||||
groupCall.requestGroupMembers();
|
||||
}))();
|
||||
});
|
||||
}
|
||||
// Called by Rust
|
||||
handleConnectionStateChanged(clientId, connectionState) {
|
||||
(() => __awaiter(this, void 0, void 0, function* () {
|
||||
yield 0;
|
||||
silly_deadlock_protection(() => {
|
||||
let groupCall = this._groupCallByClientId.get(clientId);
|
||||
if (!groupCall) {
|
||||
let error = new Error();
|
||||
@ -281,12 +330,11 @@ class RingRTCType {
|
||||
return;
|
||||
}
|
||||
groupCall.handleConnectionStateChanged(connectionState);
|
||||
}))();
|
||||
});
|
||||
}
|
||||
// Called by Rust
|
||||
handleJoinStateChanged(clientId, joinState) {
|
||||
(() => __awaiter(this, void 0, void 0, function* () {
|
||||
yield 0;
|
||||
silly_deadlock_protection(() => {
|
||||
let groupCall = this._groupCallByClientId.get(clientId);
|
||||
if (!groupCall) {
|
||||
let error = new Error();
|
||||
@ -294,12 +342,11 @@ class RingRTCType {
|
||||
return;
|
||||
}
|
||||
groupCall.handleJoinStateChanged(joinState);
|
||||
}))();
|
||||
});
|
||||
}
|
||||
// Called by Rust
|
||||
handleRemoteDevicesChanged(clientId, remoteDeviceStates) {
|
||||
(() => __awaiter(this, void 0, void 0, function* () {
|
||||
yield 0;
|
||||
silly_deadlock_protection(() => {
|
||||
let groupCall = this._groupCallByClientId.get(clientId);
|
||||
if (!groupCall) {
|
||||
let error = new Error();
|
||||
@ -307,25 +354,31 @@ class RingRTCType {
|
||||
return;
|
||||
}
|
||||
groupCall.handleRemoteDevicesChanged(remoteDeviceStates);
|
||||
}))();
|
||||
});
|
||||
}
|
||||
// Called by Rust
|
||||
handleJoinedMembersChanged(clientId, members) {
|
||||
(() => __awaiter(this, void 0, void 0, function* () {
|
||||
yield 0;
|
||||
handlePeekChanged(clientId, info) {
|
||||
silly_deadlock_protection(() => {
|
||||
let groupCall = this._groupCallByClientId.get(clientId);
|
||||
if (!groupCall) {
|
||||
let error = new Error();
|
||||
this.onLogMessage(CallLogLevel.Error, 'Service.ts', 0, 'handleJoinedMembersChanged(): GroupCall not found in map!');
|
||||
this.onLogMessage(CallLogLevel.Error, 'Service.ts', 0, 'handlePeekChanged(): GroupCall not found in map!');
|
||||
return;
|
||||
}
|
||||
groupCall.handleJoinedMembersChanged(members);
|
||||
}))();
|
||||
groupCall.handlePeekChanged(info);
|
||||
});
|
||||
}
|
||||
// Called by Rust
|
||||
handlePeekResponse(request_id, info) {
|
||||
silly_deadlock_protection(() => {
|
||||
if (!this._peekRequests.resolve(request_id, info)) {
|
||||
this.onLogMessage(CallLogLevel.Warn, 'Service.ts', 0, `Invalid request ID for handlePeekResponse: ${request_id}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
// Called by Rust
|
||||
handleEnded(clientId, reason) {
|
||||
(() => __awaiter(this, void 0, void 0, function* () {
|
||||
yield 0;
|
||||
silly_deadlock_protection(() => {
|
||||
let groupCall = this._groupCallByClientId.get(clientId);
|
||||
if (!groupCall) {
|
||||
let error = new Error();
|
||||
@ -334,7 +387,7 @@ class RingRTCType {
|
||||
}
|
||||
this._groupCallByClientId.delete(clientId);
|
||||
groupCall.handleEnded(reason);
|
||||
}))();
|
||||
});
|
||||
}
|
||||
// Called by Rust
|
||||
onLogMessage(level, fileName, line, message) {
|
||||
@ -576,12 +629,9 @@ class Call {
|
||||
this._videoRenderer.disable();
|
||||
}
|
||||
// This assumes we only have one active all.
|
||||
(() => __awaiter(this, void 0, void 0, function* () {
|
||||
// This is a silly way of causing a deadlock.
|
||||
// tslint:disable-next-line await-promise
|
||||
yield 0;
|
||||
silly_deadlock_protection(() => {
|
||||
this._callManager.hangup();
|
||||
}))();
|
||||
});
|
||||
}
|
||||
get outgoingAudioEnabled() {
|
||||
return this._outgoingAudioEnabled;
|
||||
@ -589,12 +639,9 @@ class Call {
|
||||
set outgoingAudioEnabled(enabled) {
|
||||
this._outgoingAudioEnabled = enabled;
|
||||
// This assumes we only have one active all.
|
||||
(() => __awaiter(this, void 0, void 0, function* () {
|
||||
// This is a silly way of not causing a deadlock.
|
||||
// tslint:disable-next-line await-promise
|
||||
yield 0;
|
||||
silly_deadlock_protection(() => {
|
||||
this._callManager.setOutgoingAudioEnabled(enabled);
|
||||
}))();
|
||||
});
|
||||
}
|
||||
get outgoingVideoEnabled() {
|
||||
return this._outgoingVideoEnabled;
|
||||
@ -651,11 +698,7 @@ class Call {
|
||||
}
|
||||
}
|
||||
setOutgoingVideoEnabled(enabled) {
|
||||
// tslint:disable no-floating-promises
|
||||
(() => __awaiter(this, void 0, void 0, function* () {
|
||||
// This is a silly way of causing a deadlock.
|
||||
// tslint:disable-next-line await-promise
|
||||
yield 0;
|
||||
silly_deadlock_protection(() => {
|
||||
try {
|
||||
this._callManager.setOutgoingVideoEnabled(enabled);
|
||||
}
|
||||
@ -663,14 +706,10 @@ class Call {
|
||||
// We may not have an active connection any more.
|
||||
// In which case it doesn't matter
|
||||
}
|
||||
}))();
|
||||
});
|
||||
}
|
||||
setLowBandwidthMode(enabled) {
|
||||
// tslint:disable no-floating-promises
|
||||
(() => __awaiter(this, void 0, void 0, function* () {
|
||||
// This is a silly way of causing a deadlock.
|
||||
// tslint:disable-next-line await-promise
|
||||
yield 0;
|
||||
silly_deadlock_protection(() => {
|
||||
try {
|
||||
this._callManager.setLowBandwidthMode(enabled);
|
||||
}
|
||||
@ -678,7 +717,7 @@ class Call {
|
||||
// We may not have an active connection any more.
|
||||
// In which case it doesn't matter
|
||||
}
|
||||
}))();
|
||||
});
|
||||
}
|
||||
enableOrDisableRenderer() {
|
||||
if (!this._videoRenderer) {
|
||||
@ -752,6 +791,7 @@ var HttpMethod;
|
||||
HttpMethod[HttpMethod["Get"] = 0] = "Get";
|
||||
HttpMethod[HttpMethod["Put"] = 1] = "Put";
|
||||
HttpMethod[HttpMethod["Post"] = 2] = "Post";
|
||||
HttpMethod[HttpMethod["Delete"] = 3] = "Delete";
|
||||
})(HttpMethod = exports.HttpMethod || (exports.HttpMethod = {}));
|
||||
// The local device state for a group call.
|
||||
class LocalDeviceState {
|
||||
@ -766,9 +806,10 @@ class LocalDeviceState {
|
||||
exports.LocalDeviceState = LocalDeviceState;
|
||||
// All remote devices in a group call and their associated state.
|
||||
class RemoteDeviceState {
|
||||
constructor(demuxId, userId) {
|
||||
constructor(demuxId, userId, mediaKeysReceived) {
|
||||
this.demuxId = demuxId;
|
||||
this.userId = userId;
|
||||
this.mediaKeysReceived = mediaKeysReceived;
|
||||
}
|
||||
}
|
||||
exports.RemoteDeviceState = RemoteDeviceState;
|
||||
@ -782,7 +823,7 @@ class GroupMemberInfo {
|
||||
exports.GroupMemberInfo = GroupMemberInfo;
|
||||
// Used for the application to communicate the actual resolutions of
|
||||
// each device in a group call to RingRTC and the SFU.
|
||||
class RenderedResolution {
|
||||
class VideoRequest {
|
||||
constructor(demuxId, width, height, framerate) {
|
||||
this.demuxId = demuxId;
|
||||
this.width = width;
|
||||
@ -790,14 +831,14 @@ class RenderedResolution {
|
||||
this.framerate = framerate;
|
||||
}
|
||||
}
|
||||
exports.RenderedResolution = RenderedResolution;
|
||||
exports.VideoRequest = VideoRequest;
|
||||
class GroupCall {
|
||||
// Called by UI via RingRTC object
|
||||
constructor(callManager, groupId, observer) {
|
||||
constructor(callManager, groupId, sfuUrl, observer) {
|
||||
this._callManager = callManager;
|
||||
this._observer = observer;
|
||||
this._localDeviceState = new LocalDeviceState();
|
||||
this._clientId = this._callManager.createGroupCallClient(groupId);
|
||||
this._clientId = this._callManager.createGroupCallClient(groupId, sfuUrl);
|
||||
}
|
||||
get clientId() {
|
||||
return this._clientId;
|
||||
@ -827,26 +868,32 @@ class GroupCall {
|
||||
return this._remoteDeviceStates;
|
||||
}
|
||||
// Called by UI
|
||||
getJoinedGroupMembers() {
|
||||
return this._joinedGroupMembers;
|
||||
getPeekInfo() {
|
||||
return this._peekInfo;
|
||||
}
|
||||
// Called by UI
|
||||
setOutgoingAudioMuted(muted) {
|
||||
this._localDeviceState.audioMuted = muted;
|
||||
this._callManager.setOutgoingAudioMuted(this._clientId, muted);
|
||||
this._observer.onLocalDeviceStateChanged(this);
|
||||
}
|
||||
// Called by UI
|
||||
setOutgoingVideoMuted(muted) {
|
||||
this._localDeviceState.videoMuted = muted;
|
||||
this._callManager.setOutgoingVideoMuted(this._clientId, muted);
|
||||
this._observer.onLocalDeviceStateChanged(this);
|
||||
}
|
||||
// Called by UI
|
||||
resendMediaKeys() {
|
||||
this._callManager.resendMediaKeys(this._clientId);
|
||||
}
|
||||
// Called by UI
|
||||
setBandwidthMode(bandwidthMode) {
|
||||
this._callManager.setBandwidthMode(this._clientId, bandwidthMode);
|
||||
}
|
||||
// Called by UI
|
||||
setRenderedResolutions(resolutions) {
|
||||
this._callManager.setRenderedResolutions(this._clientId, resolutions);
|
||||
requestVideo(resolutions) {
|
||||
this._callManager.requestVideo(this._clientId, resolutions);
|
||||
}
|
||||
// Called by UI
|
||||
setGroupMembers(members) {
|
||||
@ -876,13 +923,19 @@ class GroupCall {
|
||||
}
|
||||
// Called by Rust via RingRTC object
|
||||
handleRemoteDevicesChanged(remoteDeviceStates) {
|
||||
var _a, _b;
|
||||
// We don't get aspect ratios from RingRTC, so make sure to copy them over.
|
||||
for (const noo of remoteDeviceStates) {
|
||||
const old = (_a = this._remoteDeviceStates) === null || _a === void 0 ? void 0 : _a.find((old) => old.demuxId == noo.demuxId);
|
||||
noo.videoAspectRatio = (_b = old) === null || _b === void 0 ? void 0 : _b.videoAspectRatio;
|
||||
}
|
||||
this._remoteDeviceStates = remoteDeviceStates;
|
||||
this._observer.onRemoteDeviceStatesChanged(this);
|
||||
}
|
||||
// Called by Rust via RingRTC object
|
||||
handleJoinedMembersChanged(members) {
|
||||
this._joinedGroupMembers = members;
|
||||
this._observer.onJoinedMembersChanged(this);
|
||||
handlePeekChanged(info) {
|
||||
this._peekInfo = info;
|
||||
this._observer.onPeekChanged(this);
|
||||
}
|
||||
// Called by Rust via RingRTC object
|
||||
handleEnded(reason) {
|
||||
@ -896,19 +949,34 @@ class GroupCall {
|
||||
}
|
||||
// With this, a GroupCall can provide a VideoFrameSource for each remote device.
|
||||
getVideoSource(remoteDemuxId) {
|
||||
return new GroupCallVideoFrameSource(this._callManager, this._clientId, remoteDemuxId);
|
||||
return new GroupCallVideoFrameSource(this._callManager, this, remoteDemuxId);
|
||||
}
|
||||
// Called by the GroupCallVideoFrameSource when it receives a video frame.
|
||||
setRemoteAspectRatio(remoteDemuxId, aspectRatio) {
|
||||
var _a;
|
||||
const remoteDevice = (_a = this._remoteDeviceStates) === null || _a === void 0 ? void 0 : _a.find((device) => device.demuxId == remoteDemuxId);
|
||||
if (!!remoteDevice && remoteDevice.videoAspectRatio != aspectRatio) {
|
||||
remoteDevice.videoAspectRatio = aspectRatio;
|
||||
this._observer.onRemoteDeviceStatesChanged(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.GroupCall = GroupCall;
|
||||
// Implements VideoSource for use in CanvasVideoRenderer
|
||||
class GroupCallVideoFrameSource {
|
||||
constructor(callManager, clientId, remoteDemuxId) {
|
||||
constructor(callManager, groupCall, remoteDemuxId) {
|
||||
this._callManager = callManager;
|
||||
this._clientId = clientId;
|
||||
this._groupCall = groupCall;
|
||||
this._remoteDemuxId = remoteDemuxId;
|
||||
}
|
||||
receiveVideoFrame(buffer) {
|
||||
return this._callManager.receiveGroupCallVideoFrame(this._clientId, this._remoteDemuxId, buffer);
|
||||
// This assumes we only have one active all.
|
||||
const frame = this._callManager.receiveGroupCallVideoFrame(this._groupCall.clientId, this._remoteDemuxId, buffer);
|
||||
if (!!frame) {
|
||||
const [width, height] = frame;
|
||||
this._groupCall.setRemoteAspectRatio(this._remoteDemuxId, width / height);
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
function to_array_buffer(pbab) {
|
||||
@ -991,3 +1059,12 @@ var CallLogLevel;
|
||||
CallLogLevel[CallLogLevel["Debug"] = 4] = "Debug";
|
||||
CallLogLevel[CallLogLevel["Trace"] = 5] = "Trace";
|
||||
})(CallLogLevel = exports.CallLogLevel || (exports.CallLogLevel = {}));
|
||||
function silly_deadlock_protection(f) {
|
||||
// tslint:disable no-floating-promises
|
||||
(() => __awaiter(this, void 0, void 0, function* () {
|
||||
// This is a silly way of preventing a deadlock.
|
||||
// tslint:disable-next-line await-promise
|
||||
yield 0;
|
||||
f();
|
||||
}))();
|
||||
}
|
||||
|
||||
5
dist/ringrtc/VideoSupport.js
vendored
5
dist/ringrtc/VideoSupport.js
vendored
@ -244,8 +244,9 @@ class CanvasVideoRenderer {
|
||||
if (!!this.source) {
|
||||
// If we're replacing an existing source, make sure we stop the
|
||||
// current rAF loop before starting another one.
|
||||
// And blanking the video is nice as well.
|
||||
this.disable();
|
||||
if (this.rafId) {
|
||||
window.cancelAnimationFrame(this.rafId);
|
||||
}
|
||||
}
|
||||
this.source = source;
|
||||
this.requestAnimationFrameCallback();
|
||||
|
||||
4
index.ts
4
index.ts
@ -29,11 +29,11 @@ export {
|
||||
OfferType,
|
||||
OpaqueMessage,
|
||||
RemoteDeviceState,
|
||||
RenderedResolution,
|
||||
RingRTCType,
|
||||
UserId,
|
||||
VideoCapturer,
|
||||
VideoRenderer
|
||||
VideoRenderer,
|
||||
VideoRequest
|
||||
} from './ringrtc/Service';
|
||||
|
||||
export {
|
||||
|
||||
1812
package-lock.json
generated
1812
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -12,10 +12,50 @@ const os = require('os');
|
||||
// tslint:disable-next-line no-var-requires no-require-imports
|
||||
const Native = require('../../build/' + os.platform() + '/libringrtc.node');
|
||||
|
||||
type GroupId = ArrayBuffer;
|
||||
type GroupCallUserId = ArrayBuffer;
|
||||
|
||||
export class PeekInfo {
|
||||
joinedMembers: Array<GroupCallUserId>;
|
||||
creator?: GroupCallUserId;
|
||||
eraId?: string;
|
||||
maxDevices?: number;
|
||||
deviceCount: number;
|
||||
|
||||
constructor() {
|
||||
this.joinedMembers = [];
|
||||
this.deviceCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
class Requests<T> {
|
||||
private _resolveById: Map<number, (response: T) => void> = new Map();
|
||||
private _nextId: number = 1;
|
||||
|
||||
add(): [number, Promise<T>] {
|
||||
const id = this._nextId++;
|
||||
const promise = new Promise<T>((resolve, _reject) => {
|
||||
this._resolveById.set(id, resolve);
|
||||
});
|
||||
return [id, promise];
|
||||
}
|
||||
|
||||
resolve(id: number, response: T): boolean {
|
||||
const resolve = this._resolveById.get(id);
|
||||
if (!resolve) {
|
||||
return false;
|
||||
}
|
||||
resolve(response);
|
||||
this._resolveById.delete(id);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export class RingRTCType {
|
||||
private readonly callManager: CallManager;
|
||||
private _call: Call | null;
|
||||
private _groupCallByClientId: Map<GroupCallClientId, GroupCall>;
|
||||
private _peekRequests: Requests<PeekInfo>;
|
||||
|
||||
// Set by UX
|
||||
handleOutgoingSignaling: ((remoteUserId: UserId, message: CallingMessage) => Promise<boolean>) | null = null;
|
||||
@ -29,6 +69,7 @@ export class RingRTCType {
|
||||
this.callManager = new Native.CallManager() as CallManager;
|
||||
this._call = null;
|
||||
this._groupCallByClientId = new Map();
|
||||
this._peekRequests = new Requests<PeekInfo>();
|
||||
this.pollEvery(50);
|
||||
}
|
||||
|
||||
@ -117,12 +158,7 @@ export class RingRTCType {
|
||||
}
|
||||
|
||||
private proceed(callId: CallId, settings: CallSettings): void {
|
||||
// tslint:disable no-floating-promises
|
||||
(async () => {
|
||||
// This is a silly way of causing a deadlock.
|
||||
// tslint:disable-next-line await-promise
|
||||
await 0;
|
||||
|
||||
silly_deadlock_protection(() => {
|
||||
this.callManager.proceed(
|
||||
callId,
|
||||
settings.iceServer.username || '',
|
||||
@ -130,7 +166,7 @@ export class RingRTCType {
|
||||
settings.iceServer.urls,
|
||||
settings.hideIp,
|
||||
);
|
||||
})();
|
||||
});
|
||||
}
|
||||
|
||||
// Called by Rust
|
||||
@ -327,11 +363,25 @@ export class RingRTCType {
|
||||
}
|
||||
|
||||
receivedHttpResponse(requestId: number, status: number, body: ArrayBuffer) : void {
|
||||
this.callManager.receivedHttpResponse(requestId, status, body);
|
||||
silly_deadlock_protection(() => {
|
||||
try {
|
||||
this.callManager.receivedHttpResponse(requestId, status, body);
|
||||
} catch {
|
||||
// We may not have an active connection any more.
|
||||
// In which case it doesn't matter
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
httpRequestFailed(requestId: number, debugInfo: string | undefined) {
|
||||
this.callManager.httpRequestFailed(requestId, debugInfo);
|
||||
httpRequestFailed(requestId: number, debugInfo: string | undefined) : void {
|
||||
silly_deadlock_protection(() => {
|
||||
try {
|
||||
this.callManager.httpRequestFailed(requestId, debugInfo);
|
||||
} catch {
|
||||
// We may not have an active connection any more.
|
||||
// In which case it doesn't matter
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Group Calls
|
||||
@ -339,22 +389,37 @@ export class RingRTCType {
|
||||
// Called by UX
|
||||
getGroupCall(
|
||||
groupId: ArrayBuffer,
|
||||
sfuUrl: string,
|
||||
observer: GroupCallObserver
|
||||
): GroupCall | undefined {
|
||||
const groupCall = new GroupCall(this.callManager, groupId, observer);
|
||||
const groupCall = new GroupCall(this.callManager, groupId, sfuUrl, observer);
|
||||
|
||||
this._groupCallByClientId.set(groupCall.clientId, groupCall);
|
||||
|
||||
return groupCall;
|
||||
}
|
||||
|
||||
// Called by UX
|
||||
// Returns a list of user IDs
|
||||
peekGroupCall(
|
||||
sfu_url: string,
|
||||
membership_proof: ArrayBuffer,
|
||||
group_members: Array<GroupMemberInfo>,
|
||||
|
||||
): Promise<PeekInfo> {
|
||||
let [requestId, promise] = this._peekRequests.add();
|
||||
// Response comes back via handlePeekResponse
|
||||
silly_deadlock_protection(() => {
|
||||
this.callManager.peekGroupCall(requestId, sfu_url, membership_proof, group_members);
|
||||
});
|
||||
return promise;
|
||||
}
|
||||
|
||||
// Called by Rust
|
||||
requestMembershipProof(
|
||||
clientId: GroupCallClientId
|
||||
): void {
|
||||
(async () => {
|
||||
await 0;
|
||||
|
||||
silly_deadlock_protection(() => {
|
||||
let groupCall = this._groupCallByClientId.get(clientId);
|
||||
if (!groupCall) {
|
||||
let error = new Error();
|
||||
@ -363,16 +428,14 @@ export class RingRTCType {
|
||||
}
|
||||
|
||||
groupCall.requestMembershipProof();
|
||||
})();
|
||||
});
|
||||
}
|
||||
|
||||
// Called by Rust
|
||||
requestGroupMembers(
|
||||
clientId: GroupCallClientId
|
||||
): void {
|
||||
(async () => {
|
||||
await 0;
|
||||
|
||||
silly_deadlock_protection(() => {
|
||||
let groupCall = this._groupCallByClientId.get(clientId);
|
||||
if (!groupCall) {
|
||||
let error = new Error();
|
||||
@ -381,7 +444,7 @@ export class RingRTCType {
|
||||
}
|
||||
|
||||
groupCall.requestGroupMembers();
|
||||
})();
|
||||
});
|
||||
}
|
||||
|
||||
// Called by Rust
|
||||
@ -389,9 +452,7 @@ export class RingRTCType {
|
||||
clientId: GroupCallClientId,
|
||||
connectionState: ConnectionState
|
||||
): void {
|
||||
(async () => {
|
||||
await 0;
|
||||
|
||||
silly_deadlock_protection(() => {
|
||||
let groupCall = this._groupCallByClientId.get(clientId);
|
||||
if (!groupCall) {
|
||||
let error = new Error();
|
||||
@ -400,7 +461,7 @@ export class RingRTCType {
|
||||
}
|
||||
|
||||
groupCall.handleConnectionStateChanged(connectionState);
|
||||
})();
|
||||
});
|
||||
}
|
||||
|
||||
// Called by Rust
|
||||
@ -408,9 +469,7 @@ export class RingRTCType {
|
||||
clientId: GroupCallClientId,
|
||||
joinState: JoinState
|
||||
): void {
|
||||
(async () => {
|
||||
await 0;
|
||||
|
||||
silly_deadlock_protection(() => {
|
||||
let groupCall = this._groupCallByClientId.get(clientId);
|
||||
if (!groupCall) {
|
||||
let error = new Error();
|
||||
@ -419,7 +478,7 @@ export class RingRTCType {
|
||||
}
|
||||
|
||||
groupCall.handleJoinStateChanged(joinState);
|
||||
})();
|
||||
});
|
||||
}
|
||||
|
||||
// Called by Rust
|
||||
@ -427,9 +486,7 @@ export class RingRTCType {
|
||||
clientId: GroupCallClientId,
|
||||
remoteDeviceStates: Array<RemoteDeviceState>
|
||||
): void {
|
||||
(async () => {
|
||||
await 0;
|
||||
|
||||
silly_deadlock_protection(() => {
|
||||
let groupCall = this._groupCallByClientId.get(clientId);
|
||||
if (!groupCall) {
|
||||
let error = new Error();
|
||||
@ -438,26 +495,36 @@ export class RingRTCType {
|
||||
}
|
||||
|
||||
groupCall.handleRemoteDevicesChanged(remoteDeviceStates);
|
||||
})();
|
||||
});
|
||||
}
|
||||
|
||||
// Called by Rust
|
||||
handleJoinedMembersChanged(
|
||||
handlePeekChanged(
|
||||
clientId: GroupCallClientId,
|
||||
members: Array<ArrayBuffer>
|
||||
info: PeekInfo,
|
||||
): void {
|
||||
(async () => {
|
||||
await 0;
|
||||
|
||||
silly_deadlock_protection(() => {
|
||||
let groupCall = this._groupCallByClientId.get(clientId);
|
||||
if (!groupCall) {
|
||||
let error = new Error();
|
||||
this.onLogMessage(CallLogLevel.Error, 'Service.ts', 0, 'handleJoinedMembersChanged(): GroupCall not found in map!');
|
||||
this.onLogMessage(CallLogLevel.Error, 'Service.ts', 0, 'handlePeekChanged(): GroupCall not found in map!');
|
||||
return;
|
||||
}
|
||||
|
||||
groupCall.handleJoinedMembersChanged(members);
|
||||
})();
|
||||
groupCall.handlePeekChanged(info);
|
||||
});
|
||||
}
|
||||
|
||||
// Called by Rust
|
||||
handlePeekResponse(
|
||||
request_id: number,
|
||||
info: PeekInfo,
|
||||
): void {
|
||||
silly_deadlock_protection(() => {
|
||||
if (!this._peekRequests.resolve(request_id, info)) {
|
||||
this.onLogMessage(CallLogLevel.Warn, 'Service.ts', 0, `Invalid request ID for handlePeekResponse: ${request_id}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Called by Rust
|
||||
@ -465,9 +532,7 @@ export class RingRTCType {
|
||||
clientId: GroupCallClientId,
|
||||
reason: GroupCallEndReason
|
||||
): void {
|
||||
(async () => {
|
||||
await 0;
|
||||
|
||||
silly_deadlock_protection(() => {
|
||||
let groupCall = this._groupCallByClientId.get(clientId);
|
||||
if (!groupCall) {
|
||||
let error = new Error();
|
||||
@ -478,7 +543,7 @@ export class RingRTCType {
|
||||
this._groupCallByClientId.delete(clientId);
|
||||
|
||||
groupCall.handleEnded(reason);
|
||||
})();
|
||||
});
|
||||
}
|
||||
|
||||
// Called by Rust
|
||||
@ -883,12 +948,9 @@ export class Call {
|
||||
this._videoRenderer.disable();
|
||||
}
|
||||
// This assumes we only have one active all.
|
||||
(async () => {
|
||||
// This is a silly way of causing a deadlock.
|
||||
// tslint:disable-next-line await-promise
|
||||
await 0;
|
||||
silly_deadlock_protection(() => {
|
||||
this._callManager.hangup();
|
||||
})();
|
||||
});
|
||||
}
|
||||
|
||||
get outgoingAudioEnabled(): boolean {
|
||||
@ -898,12 +960,9 @@ export class Call {
|
||||
set outgoingAudioEnabled(enabled: boolean) {
|
||||
this._outgoingAudioEnabled = enabled;
|
||||
// This assumes we only have one active all.
|
||||
(async () => {
|
||||
// This is a silly way of not causing a deadlock.
|
||||
// tslint:disable-next-line await-promise
|
||||
await 0;
|
||||
silly_deadlock_protection(() => {
|
||||
this._callManager.setOutgoingAudioEnabled(enabled);
|
||||
})();
|
||||
});
|
||||
}
|
||||
|
||||
get outgoingVideoEnabled(): boolean {
|
||||
@ -968,33 +1027,25 @@ export class Call {
|
||||
}
|
||||
|
||||
private setOutgoingVideoEnabled(enabled: boolean) {
|
||||
// tslint:disable no-floating-promises
|
||||
(async () => {
|
||||
// This is a silly way of causing a deadlock.
|
||||
// tslint:disable-next-line await-promise
|
||||
await 0;
|
||||
silly_deadlock_protection(() => {
|
||||
try {
|
||||
this._callManager.setOutgoingVideoEnabled(enabled);
|
||||
} catch {
|
||||
// We may not have an active connection any more.
|
||||
// In which case it doesn't matter
|
||||
}
|
||||
})();
|
||||
});
|
||||
}
|
||||
|
||||
setLowBandwidthMode(enabled: boolean) {
|
||||
// tslint:disable no-floating-promises
|
||||
(async () => {
|
||||
// This is a silly way of causing a deadlock.
|
||||
// tslint:disable-next-line await-promise
|
||||
await 0;
|
||||
silly_deadlock_protection(() => {
|
||||
try {
|
||||
this._callManager.setLowBandwidthMode(enabled);
|
||||
} catch {
|
||||
// We may not have an active connection any more.
|
||||
// In which case it doesn't matter
|
||||
}
|
||||
})();
|
||||
});
|
||||
}
|
||||
|
||||
private enableOrDisableRenderer(): void {
|
||||
@ -1073,6 +1124,7 @@ export enum HttpMethod {
|
||||
Get = 0,
|
||||
Put = 1,
|
||||
Post = 2,
|
||||
Delete = 3,
|
||||
}
|
||||
|
||||
// The local device state for a group call.
|
||||
@ -1095,6 +1147,7 @@ export class LocalDeviceState {
|
||||
export class RemoteDeviceState {
|
||||
demuxId: number; // UInt32
|
||||
userId: ArrayBuffer;
|
||||
mediaKeysReceived: boolean;
|
||||
|
||||
audioMuted: boolean | undefined;
|
||||
videoMuted: boolean | undefined;
|
||||
@ -1104,10 +1157,12 @@ export class RemoteDeviceState {
|
||||
|
||||
constructor(
|
||||
demuxId: number,
|
||||
userId: ArrayBuffer
|
||||
userId: ArrayBuffer,
|
||||
mediaKeysReceived: boolean
|
||||
) {
|
||||
this.demuxId = demuxId;
|
||||
this.userId = userId;
|
||||
this.mediaKeysReceived = mediaKeysReceived
|
||||
}
|
||||
}
|
||||
|
||||
@ -1127,7 +1182,7 @@ export class GroupMemberInfo {
|
||||
|
||||
// Used for the application to communicate the actual resolutions of
|
||||
// each device in a group call to RingRTC and the SFU.
|
||||
export class RenderedResolution {
|
||||
export class VideoRequest {
|
||||
demuxId: number; // UInt32
|
||||
width: number; // UInt16
|
||||
height: number; // UInt16
|
||||
@ -1151,7 +1206,7 @@ export interface GroupCallObserver {
|
||||
requestGroupMembers(groupCall: GroupCall): void;
|
||||
onLocalDeviceStateChanged(groupCall: GroupCall): void;
|
||||
onRemoteDeviceStatesChanged(groupCall: GroupCall): void;
|
||||
onJoinedMembersChanged(groupCall: GroupCall): void;
|
||||
onPeekChanged(groupCall: GroupCall): void;
|
||||
onEnded(groupCall: GroupCall, reason: GroupCallEndReason): void;
|
||||
}
|
||||
|
||||
@ -1167,12 +1222,13 @@ export class GroupCall {
|
||||
private _localDeviceState: LocalDeviceState;
|
||||
private _remoteDeviceStates: Array<RemoteDeviceState> | undefined;
|
||||
|
||||
private _joinedGroupMembers: Array<ArrayBuffer> | undefined; // uuid
|
||||
private _peekInfo: PeekInfo | undefined; // uuid
|
||||
|
||||
// Called by UI via RingRTC object
|
||||
constructor(
|
||||
callManager: CallManager,
|
||||
groupId: ArrayBuffer,
|
||||
sfuUrl: string,
|
||||
observer: GroupCallObserver
|
||||
) {
|
||||
this._callManager = callManager;
|
||||
@ -1180,7 +1236,7 @@ export class GroupCall {
|
||||
|
||||
this._localDeviceState = new LocalDeviceState();
|
||||
|
||||
this._clientId = this._callManager.createGroupCallClient(groupId);
|
||||
this._clientId = this._callManager.createGroupCallClient(groupId, sfuUrl);
|
||||
}
|
||||
|
||||
// Called by UI
|
||||
@ -1214,20 +1270,27 @@ export class GroupCall {
|
||||
}
|
||||
|
||||
// Called by UI
|
||||
getJoinedGroupMembers(): Array<ArrayBuffer> | undefined {
|
||||
return this._joinedGroupMembers;
|
||||
getPeekInfo(): PeekInfo | undefined {
|
||||
return this._peekInfo;
|
||||
}
|
||||
|
||||
// Called by UI
|
||||
setOutgoingAudioMuted(muted: boolean): void {
|
||||
this._localDeviceState.audioMuted = muted;
|
||||
this._callManager.setOutgoingAudioMuted(this._clientId, muted);
|
||||
this._observer.onLocalDeviceStateChanged(this);
|
||||
}
|
||||
|
||||
// Called by UI
|
||||
setOutgoingVideoMuted(muted: boolean): void {
|
||||
this._localDeviceState.videoMuted = muted;
|
||||
this._callManager.setOutgoingVideoMuted(this._clientId, muted);
|
||||
this._observer.onLocalDeviceStateChanged(this);
|
||||
}
|
||||
|
||||
// Called by UI
|
||||
resendMediaKeys(): void {
|
||||
this._callManager.resendMediaKeys(this._clientId);
|
||||
}
|
||||
|
||||
// Called by UI
|
||||
@ -1236,8 +1299,8 @@ export class GroupCall {
|
||||
}
|
||||
|
||||
// Called by UI
|
||||
setRenderedResolutions(resolutions: Array<RenderedResolution>): void {
|
||||
this._callManager.setRenderedResolutions(this._clientId, resolutions);
|
||||
requestVideo(resolutions: Array<VideoRequest>): void {
|
||||
this._callManager.requestVideo(this._clientId, resolutions);
|
||||
}
|
||||
|
||||
// Called by UI
|
||||
@ -1276,16 +1339,22 @@ export class GroupCall {
|
||||
|
||||
// Called by Rust via RingRTC object
|
||||
handleRemoteDevicesChanged(remoteDeviceStates: Array<RemoteDeviceState>): void {
|
||||
// We don't get aspect ratios from RingRTC, so make sure to copy them over.
|
||||
for (const noo of remoteDeviceStates) {
|
||||
const old = this._remoteDeviceStates?.find((old) => old.demuxId == noo.demuxId);
|
||||
noo.videoAspectRatio = old?.videoAspectRatio;
|
||||
}
|
||||
|
||||
this._remoteDeviceStates = remoteDeviceStates;
|
||||
|
||||
this._observer.onRemoteDeviceStatesChanged(this);
|
||||
}
|
||||
|
||||
// Called by Rust via RingRTC object
|
||||
handleJoinedMembersChanged(members: Array<ArrayBuffer>): void {
|
||||
this._joinedGroupMembers = members;
|
||||
handlePeekChanged(info: PeekInfo): void {
|
||||
this._peekInfo = info;
|
||||
|
||||
this._observer.onJoinedMembersChanged(this);
|
||||
this._observer.onPeekChanged(this);
|
||||
}
|
||||
|
||||
// Called by Rust via RingRTC object
|
||||
@ -1303,28 +1372,43 @@ export class GroupCall {
|
||||
|
||||
// With this, a GroupCall can provide a VideoFrameSource for each remote device.
|
||||
getVideoSource(remoteDemuxId: number): GroupCallVideoFrameSource {
|
||||
return new GroupCallVideoFrameSource(this._callManager, this._clientId, remoteDemuxId);
|
||||
return new GroupCallVideoFrameSource(this._callManager, this, remoteDemuxId);
|
||||
}
|
||||
|
||||
// Called by the GroupCallVideoFrameSource when it receives a video frame.
|
||||
setRemoteAspectRatio(remoteDemuxId: number, aspectRatio: number) {
|
||||
const remoteDevice = this._remoteDeviceStates?.find((device) => device.demuxId == remoteDemuxId);
|
||||
if (!!remoteDevice && remoteDevice.videoAspectRatio != aspectRatio) {
|
||||
remoteDevice.videoAspectRatio = aspectRatio;
|
||||
this._observer.onRemoteDeviceStatesChanged(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Implements VideoSource for use in CanvasVideoRenderer
|
||||
class GroupCallVideoFrameSource {
|
||||
private readonly _callManager: CallManager;
|
||||
private readonly _clientId: GroupCallClientId;
|
||||
private readonly _groupCall: GroupCall;
|
||||
private readonly _remoteDemuxId: number; // Uint32
|
||||
|
||||
constructor(
|
||||
callManager: CallManager,
|
||||
clientId: GroupCallClientId,
|
||||
groupCall: GroupCall,
|
||||
remoteDemuxId: number, // Uint32
|
||||
) {
|
||||
this._callManager = callManager;
|
||||
this._clientId = clientId;
|
||||
this._groupCall = groupCall;
|
||||
this._remoteDemuxId = remoteDemuxId;
|
||||
}
|
||||
|
||||
receiveVideoFrame(buffer: ArrayBuffer): [number, number] | undefined {
|
||||
return this._callManager.receiveGroupCallVideoFrame(this._clientId, this._remoteDemuxId, buffer);
|
||||
// This assumes we only have one active all.
|
||||
const frame = this._callManager.receiveGroupCallVideoFrame(this._groupCall.clientId, this._remoteDemuxId, buffer);
|
||||
if (!!frame) {
|
||||
const [ width, height ] = frame;
|
||||
this._groupCall.setRemoteAspectRatio(this._remoteDemuxId, width / height);
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1485,7 +1569,7 @@ export interface CallManager {
|
||||
|
||||
// Group Calls
|
||||
|
||||
createGroupCallClient(groupId: ArrayBuffer) : GroupCallClientId;
|
||||
createGroupCallClient(groupId: ArrayBuffer, sfuUrl: string) : GroupCallClientId;
|
||||
deleteGroupCallClient(clientId: GroupCallClientId): void;
|
||||
connect(clientId: GroupCallClientId): void;
|
||||
join(clientId: GroupCallClientId): void;
|
||||
@ -1493,12 +1577,15 @@ export interface CallManager {
|
||||
disconnect(clientId: GroupCallClientId): void;
|
||||
setOutgoingAudioMuted(clientId: GroupCallClientId, muted: boolean): void;
|
||||
setOutgoingVideoMuted(clientId: GroupCallClientId, muted: boolean): void;
|
||||
resendMediaKeys(clientId: GroupCallClientId): void;
|
||||
setBandwidthMode(clientId: GroupCallClientId, bandwidthMode: BandwidthMode): void;
|
||||
setRenderedResolutions(clientId: GroupCallClientId, resolutions: Array<RenderedResolution>): void;
|
||||
requestVideo(clientId: GroupCallClientId, resolutions: Array<VideoRequest>): void;
|
||||
setGroupMembers(clientId: GroupCallClientId, members: Array<GroupMemberInfo>): void;
|
||||
setMembershipProof(clientId: GroupCallClientId, proof: ArrayBuffer): void;
|
||||
// Same as receiveVideoFrame, but with a specific GroupCallClientId and remoteDemuxId.
|
||||
receiveGroupCallVideoFrame(clientId: GroupCallClientId, remoteDemuxId: number, buffer: ArrayBuffer): [number, number] | undefined;
|
||||
// Response comes back via handlePeekResponse
|
||||
peekGroupCall(requestId: number, sfu_url: string, membership_proof: ArrayBuffer, group_members: Array<GroupMemberInfo>): Promise<PeekInfo>;
|
||||
|
||||
getAudioInputs() : AudioDevice[];
|
||||
setAudioInput(index: number) : void;
|
||||
@ -1591,9 +1678,13 @@ export interface CallManagerCallbacks {
|
||||
clientId: GroupCallClientId,
|
||||
remoteDeviceStates: Array<RemoteDeviceState>
|
||||
): void;
|
||||
handleJoinedMembersChanged(
|
||||
handlePeekChanged(
|
||||
clientId: GroupCallClientId,
|
||||
members: Array<ArrayBuffer>
|
||||
info: PeekInfo
|
||||
): void;
|
||||
handlePeekResponse(
|
||||
request_id: number,
|
||||
info: PeekInfo
|
||||
): void;
|
||||
handleEnded(
|
||||
clientId: GroupCallClientId,
|
||||
@ -1644,3 +1735,14 @@ export enum CallLogLevel {
|
||||
Debug,
|
||||
Trace,
|
||||
}
|
||||
|
||||
function silly_deadlock_protection(f: () => void) {
|
||||
// tslint:disable no-floating-promises
|
||||
(async () => {
|
||||
// This is a silly way of preventing a deadlock.
|
||||
// tslint:disable-next-line await-promise
|
||||
await 0;
|
||||
|
||||
f();
|
||||
})();
|
||||
}
|
||||
|
||||
@ -303,8 +303,9 @@ export class CanvasVideoRenderer {
|
||||
if (!!this.source) {
|
||||
// If we're replacing an existing source, make sure we stop the
|
||||
// current rAF loop before starting another one.
|
||||
// And blanking the video is nice as well.
|
||||
this.disable();
|
||||
if (this.rafId) {
|
||||
window.cancelAnimationFrame(this.rafId);
|
||||
}
|
||||
}
|
||||
this.source = source;
|
||||
this.requestAnimationFrameCallback();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user