Implement voice broadcast playback buffering (#9435)

Co-authored-by: Kerry <kerrya@element.io>
This commit is contained in:
Michael Weimann 2022-10-17 17:35:13 +02:00 committed by GitHub
parent 877c95df8f
commit 788dd904b7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 201 additions and 22 deletions

View file

@ -36,6 +36,7 @@ export enum VoiceBroadcastPlaybackState {
Paused,
Playing,
Stopped,
Buffering,
}
export enum VoiceBroadcastPlaybackEvent {
@ -91,7 +92,7 @@ export class VoiceBroadcastPlayback
this.chunkRelationHelper.emitCurrent();
}
private addChunkEvent(event: MatrixEvent): boolean {
private addChunkEvent = async (event: MatrixEvent): Promise<boolean> => {
const eventId = event.getId();
if (!eventId
@ -102,8 +103,17 @@ export class VoiceBroadcastPlayback
}
this.chunkEvents.set(eventId, event);
if (this.getState() !== VoiceBroadcastPlaybackState.Stopped) {
await this.enqueueChunk(event);
}
if (this.getState() === VoiceBroadcastPlaybackState.Buffering) {
await this.start();
}
return true;
}
};
private addInfoEvent = (event: MatrixEvent): void => {
if (this.lastInfoEvent && this.lastInfoEvent.getTs() >= event.getTs()) {
@ -149,20 +159,30 @@ export class VoiceBroadcastPlayback
playback.on(UPDATE_EVENT, (state) => this.onPlaybackStateChange(playback, state));
}
private onPlaybackStateChange(playback: Playback, newState: PlaybackState) {
private async onPlaybackStateChange(playback: Playback, newState: PlaybackState) {
if (newState !== PlaybackState.Stopped) {
return;
}
const next = this.queue[this.queue.indexOf(playback) + 1];
await this.playNext(playback);
}
private async playNext(current: Playback): Promise<void> {
const next = this.queue[this.queue.indexOf(current) + 1];
if (next) {
this.setState(VoiceBroadcastPlaybackState.Playing);
this.currentlyPlaying = next;
next.play();
await next.play();
return;
}
this.setState(VoiceBroadcastPlaybackState.Stopped);
if (this.getInfoState() === VoiceBroadcastInfoState.Stopped) {
this.setState(VoiceBroadcastPlaybackState.Stopped);
} else {
// No more chunks available, although the broadcast is not finished → enter buffering state.
this.setState(VoiceBroadcastPlaybackState.Buffering);
}
}
public async start(): Promise<void> {
@ -174,14 +194,14 @@ export class VoiceBroadcastPlayback
? 0 // start at the beginning for an ended voice broadcast
: this.queue.length - 1; // start at the current chunk for an ongoing voice broadcast
if (this.queue.length === 0 || !this.queue[toPlayIndex]) {
this.setState(VoiceBroadcastPlaybackState.Stopped);
if (this.queue[toPlayIndex]) {
this.setState(VoiceBroadcastPlaybackState.Playing);
this.currentlyPlaying = this.queue[toPlayIndex];
await this.currentlyPlaying.play();
return;
}
this.setState(VoiceBroadcastPlaybackState.Playing);
this.currentlyPlaying = this.queue[toPlayIndex];
await this.currentlyPlaying.play();
this.setState(VoiceBroadcastPlaybackState.Buffering);
}
public get length(): number {