This commit is contained in:
Bruno Windels 2022-03-10 17:39:29 +01:00
parent 6da4a4209c
commit b2ac4bc291
3 changed files with 55 additions and 8 deletions

View file

@ -96,12 +96,15 @@ party identification
## TODO ## TODO
Build basic version of PeerCall Build basic version of PeerCall
- add candidates code
Build basic version of GroupCall Build basic version of GroupCall
Make it possible to olm encrypt the messages - add state, block invalid actions
DONE: Make it possible to olm encrypt the messages
Do work needed for state events Do work needed for state events
- receiving (almost done?) - receiving (almost done?)
- sending - sending
Expose call objects Expose call objects
expose volume events from audiotrack to group call
Write view model Write view model
write view write view

View file

@ -27,17 +27,31 @@ import type {StateEvent} from "../../storage/types";
import type {Platform} from "../../../platform/web/Platform"; import type {Platform} from "../../../platform/web/Platform";
import type {EncryptedMessage} from "../../e2ee/olm/Encryption"; import type {EncryptedMessage} from "../../e2ee/olm/Encryption";
import type {ILogItem} from "../../../logging/types"; import type {ILogItem} from "../../../logging/types";
import type {Storage} from "../../storage/idb/Storage";
export enum GroupCallState {
LocalCallFeedUninitialized = "local_call_feed_uninitialized",
InitializingLocalCallFeed = "initializing_local_call_feed",
LocalCallFeedInitialized = "local_call_feed_initialized",
Joining = "entering",
Joined = "entered",
Ended = "ended",
}
export type Options = Omit<MemberOptions, "emitUpdate" | "confId" | "encryptDeviceMessage"> & { export type Options = Omit<MemberOptions, "emitUpdate" | "confId" | "encryptDeviceMessage"> & {
emitUpdate: (call: GroupCall, params?: any) => void; emitUpdate: (call: GroupCall, params?: any) => void;
encryptDeviceMessage: (roomId: string, message: SignallingMessage<MGroupCallBase>, log: ILogItem) => Promise<EncryptedMessage>, encryptDeviceMessage: (roomId: string, message: SignallingMessage<MGroupCallBase>, log: ILogItem) => Promise<EncryptedMessage>,
storage: Storage,
ownDeviceId: string
}; };
export class GroupCall { export class GroupCall {
private readonly _members: ObservableMap<string, Member> = new ObservableMap(); private readonly _members: ObservableMap<string, Member> = new ObservableMap();
private localMedia?: Promise<LocalMedia>; private localMedia?: Promise<LocalMedia>;
private _memberOptions: MemberOptions; private _memberOptions: MemberOptions;
private _state: GroupCallState = GroupCallState.LocalCallFeedInitialized;
// TODO: keep connected state and deal
constructor( constructor(
private callEvent: StateEvent, private callEvent: StateEvent,
private readonly room: Room, private readonly room: Room,
@ -52,6 +66,10 @@ export class GroupCall {
}, options); }, options);
} }
static async create(roomId: string, options: Options): Promise<GroupCall> {
}
get members(): BaseObservableMap<string, Member> { return this._members; } get members(): BaseObservableMap<string, Member> { return this._members; }
get id(): string { return this.callEvent.state_key; } get id(): string { return this.callEvent.state_key; }
@ -60,12 +78,11 @@ export class GroupCall {
return this.callEvent.content["m.terminated"] === true; return this.callEvent.content["m.terminated"] === true;
} }
async join(tracks: Promise<Track[]>) { async join(localMedia: Promise<LocalMedia>) {
this.localMedia = tracks.then(tracks => LocalMedia.fromTracks(tracks)); this.localMedia = localMedia;
const memberContent = await this._createOrUpdateOwnMemberStateContent();
// send m.call.member state event // send m.call.member state event
const request = this.options.hsApi.sendState(this.room.id, "m.call.member", this.options.ownUserId, { const request = this.options.hsApi.sendState(this.room.id, "m.call.member", this.options.ownUserId, memberContent);
});
await request.response(); await request.response();
// send invite to all members that are < my userId // send invite to all members that are < my userId
for (const [,member] of this._members) { for (const [,member] of this._members) {
@ -106,4 +123,31 @@ export class GroupCall {
// we haven't received the m.call.member yet for this caller. buffer the device messages or create the member/call anyway? // we haven't received the m.call.member yet for this caller. buffer the device messages or create the member/call anyway?
} }
} }
private async _createOrUpdateOwnMemberStateContent() {
const {storage} = this.options;
const txn = await storage.readTxn([storage.storeNames.roomState]);
const stateEvent = await txn.roomState.get(this.room.id, "m.call.member", this.options.ownUserId);
const stateContent = stateEvent?.event?.content ?? {
["m.calls"]: []
};
const callsInfo = stateContent["m.calls"];
let callInfo = callsInfo.find(c => c["m.call_id"] === this.id);
if (!callInfo) {
callInfo = {
["m.call_id"]: this.id,
["m.devices"]: []
};
callsInfo.push(callInfo);
}
const devicesInfo = callInfo["m.devices"];
let deviceInfo = devicesInfo.find(d => d["device_id"] === this.options.ownDeviceId);
if (!deviceInfo) {
deviceInfo = {
["device_id"]: this.options.ownDeviceId
};
devicesInfo.push(deviceInfo);
}
return stateContent;
}
} }

View file

@ -65,7 +65,7 @@ export class Member {
/** @internal */ /** @internal */
updateCallInfo(memberCallInfo) { updateCallInfo(memberCallInfo) {
// m.calls object from the m.call.member event
} }
/** @internal */ /** @internal */