Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 34b8870

Browse files
authored
Merge pull request #6417 from matrix-org/travis/voice-messages/play-1
Play only one audio file at a time
2 parents cdac3f9 + 45f9f3e commit 34b8870

File tree

5 files changed

+98
-2
lines changed

5 files changed

+98
-2
lines changed

src/components/views/messages/MAudioBody.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import AudioPlayer from "../audio_messages/AudioPlayer";
2323
import { IMediaEventContent } from "../../../customisations/models/IMediaEventContent";
2424
import MFileBody from "./MFileBody";
2525
import { IBodyProps } from "./IBodyProps";
26+
import { PlaybackManager } from "../../../voice/PlaybackManager";
2627

2728
interface IState {
2829
error?: Error;
@@ -62,7 +63,7 @@ export default class MAudioBody extends React.PureComponent<IBodyProps, IState>
6263
const waveform = content?.["org.matrix.msc1767.audio"]?.waveform?.map(p => p / 1024);
6364

6465
// We should have a buffer to work with now: let's set it up
65-
const playback = new Playback(buffer, waveform);
66+
const playback = PlaybackManager.instance.createPlaybackInstance(buffer, waveform);
6667
playback.clockInfo.populatePlaceholdersFrom(this.props.mxEvent);
6768
this.setState({ playback });
6869

src/voice/ManagedPlayback.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
Copyright 2021 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
import { DEFAULT_WAVEFORM, Playback } from "./Playback";
18+
import { PlaybackManager } from "./PlaybackManager";
19+
20+
/**
21+
* A managed playback is a Playback instance that is guided by a PlaybackManager.
22+
*/
23+
export class ManagedPlayback extends Playback {
24+
public constructor(private manager: PlaybackManager, buf: ArrayBuffer, seedWaveform = DEFAULT_WAVEFORM) {
25+
super(buf, seedWaveform);
26+
}
27+
28+
public async play(): Promise<void> {
29+
this.manager.playOnly(this);
30+
return super.play();
31+
}
32+
33+
public destroy() {
34+
this.manager.destroyPlaybackInstance(this);
35+
super.destroy();
36+
}
37+
}

src/voice/Playback.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export enum PlaybackState {
3232

3333
export const PLAYBACK_WAVEFORM_SAMPLES = 39;
3434
const THUMBNAIL_WAVEFORM_SAMPLES = 100; // arbitrary: [30,120]
35-
const DEFAULT_WAVEFORM = arraySeed(0, PLAYBACK_WAVEFORM_SAMPLES);
35+
export const DEFAULT_WAVEFORM = arraySeed(0, PLAYBACK_WAVEFORM_SAMPLES);
3636

3737
function makePlaybackWaveform(input: number[]): number[] {
3838
// First, convert negative amplitudes to positive so we don't detect zero as "noisy".

src/voice/PlaybackClock.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ export class PlaybackClock implements IDestroyable {
132132

133133
public flagStop() {
134134
this.stopped = true;
135+
136+
// Reset the clock time now so that the update going out will trigger components
137+
// to check their seek/position information (alongside the clock).
138+
this.clipStart = this.context.currentTime;
135139
}
136140

137141
public syncTo(contextTime: number, clipTime: number) {

src/voice/PlaybackManager.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
Copyright 2021 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
import { DEFAULT_WAVEFORM, Playback } from "./Playback";
18+
import { ManagedPlayback } from "./ManagedPlayback";
19+
20+
/**
21+
* Handles management of playback instances to ensure certain functionality, like
22+
* one playback operating at any one time.
23+
*/
24+
export class PlaybackManager {
25+
private static internalInstance: PlaybackManager;
26+
27+
private instances: ManagedPlayback[] = [];
28+
29+
public static get instance(): PlaybackManager {
30+
if (!PlaybackManager.internalInstance) {
31+
PlaybackManager.internalInstance = new PlaybackManager();
32+
}
33+
return PlaybackManager.internalInstance;
34+
}
35+
36+
/**
37+
* Stops all other playback instances. If no playback is provided, all instances
38+
* are stopped.
39+
* @param playback Optional. The playback to leave untouched.
40+
*/
41+
public playOnly(playback?: Playback) {
42+
this.instances.filter(p => p !== playback).forEach(p => p.stop());
43+
}
44+
45+
public destroyPlaybackInstance(playback: ManagedPlayback) {
46+
this.instances = this.instances.filter(p => p !== playback);
47+
}
48+
49+
public createPlaybackInstance(buf: ArrayBuffer, waveform = DEFAULT_WAVEFORM): Playback {
50+
const instance = new ManagedPlayback(this, buf, waveform);
51+
this.instances.push(instance);
52+
return instance;
53+
}
54+
}

0 commit comments

Comments
 (0)