forked from mystiq/hydrogen-web
WIP13
This commit is contained in:
parent
6da4a4209c
commit
b2ac4bc291
3 changed files with 55 additions and 8 deletions
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,7 @@ export class Member {
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
updateCallInfo(memberCallInfo) {
|
updateCallInfo(memberCallInfo) {
|
||||||
|
// m.calls object from the m.call.member event
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
|
|
Loading…
Reference in a new issue