Implement voice broadcast playback buffering (#9435)
Co-authored-by: Kerry <kerrya@element.io>
This commit is contained in:
parent
877c95df8f
commit
788dd904b7
5 changed files with 201 additions and 22 deletions
|
@ -20,7 +20,9 @@ import {
|
|||
PlaybackControlButton,
|
||||
VoiceBroadcastHeader,
|
||||
VoiceBroadcastPlayback,
|
||||
VoiceBroadcastPlaybackState,
|
||||
} from "../..";
|
||||
import Spinner from "../../../components/views/elements/Spinner";
|
||||
import { useVoiceBroadcastPlayback } from "../../hooks/useVoiceBroadcastPlayback";
|
||||
|
||||
interface VoiceBroadcastPlaybackBodyProps {
|
||||
|
@ -38,6 +40,10 @@ export const VoiceBroadcastPlaybackBody: React.FC<VoiceBroadcastPlaybackBodyProp
|
|||
playbackState,
|
||||
} = useVoiceBroadcastPlayback(playback);
|
||||
|
||||
const control = playbackState === VoiceBroadcastPlaybackState.Buffering
|
||||
? <Spinner />
|
||||
: <PlaybackControlButton onClick={toggle} state={playbackState} />;
|
||||
|
||||
return (
|
||||
<div className="mx_VoiceBroadcastPlaybackBody">
|
||||
<VoiceBroadcastHeader
|
||||
|
@ -47,10 +53,7 @@ export const VoiceBroadcastPlaybackBody: React.FC<VoiceBroadcastPlaybackBodyProp
|
|||
showBroadcast={true}
|
||||
/>
|
||||
<div className="mx_VoiceBroadcastPlaybackBody_controls">
|
||||
<PlaybackControlButton
|
||||
onClick={toggle}
|
||||
state={playbackState}
|
||||
/>
|
||||
{ control }
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue