Introduce basic audio playback control
This commit is contained in:
parent
470778cbb8
commit
dda60949c3
6 changed files with 203 additions and 20 deletions
|
@ -58,6 +58,7 @@ export class Playback extends EventEmitter implements IDestroyable {
|
|||
private resampledWaveform: number[];
|
||||
private waveformObservable = new SimpleObservable<number[]>();
|
||||
private readonly clock: PlaybackClock;
|
||||
private readonly fileSize: number;
|
||||
|
||||
/**
|
||||
* Creates a new playback instance from a buffer.
|
||||
|
@ -67,12 +68,22 @@ export class Playback extends EventEmitter implements IDestroyable {
|
|||
*/
|
||||
constructor(private buf: ArrayBuffer, seedWaveform = DEFAULT_WAVEFORM) {
|
||||
super();
|
||||
// Capture the file size early as reading the buffer will result in a 0-length buffer left behind
|
||||
this.fileSize = this.buf.byteLength;
|
||||
this.context = createAudioContext();
|
||||
this.resampledWaveform = arrayFastResample(seedWaveform ?? DEFAULT_WAVEFORM, PLAYBACK_WAVEFORM_SAMPLES);
|
||||
this.waveformObservable.update(this.resampledWaveform);
|
||||
this.clock = new PlaybackClock(this.context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Size of the audio clip in bytes. May be zero if unknown. This is updated
|
||||
* when the playback goes through phase changes.
|
||||
*/
|
||||
public get sizeBytes(): number {
|
||||
return this.fileSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stable waveform for the playback. Values are guaranteed to be between
|
||||
* zero and one, inclusive.
|
||||
|
|
|
@ -14,8 +14,9 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {SimpleObservable} from "matrix-widget-api";
|
||||
import {IDestroyable} from "../utils/IDestroyable";
|
||||
import { SimpleObservable } from "matrix-widget-api";
|
||||
import { IDestroyable } from "../utils/IDestroyable";
|
||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||
|
||||
// Because keeping track of time is sufficiently complicated...
|
||||
export class PlaybackClock implements IDestroyable {
|
||||
|
@ -25,12 +26,13 @@ export class PlaybackClock implements IDestroyable {
|
|||
private observable = new SimpleObservable<number[]>();
|
||||
private timerId: number;
|
||||
private clipDuration = 0;
|
||||
private placeholderDuration = 0;
|
||||
|
||||
public constructor(private context: AudioContext) {
|
||||
}
|
||||
|
||||
public get durationSeconds(): number {
|
||||
return this.clipDuration;
|
||||
return this.clipDuration || this.placeholderDuration;
|
||||
}
|
||||
|
||||
public set durationSeconds(val: number) {
|
||||
|
@ -54,6 +56,16 @@ export class PlaybackClock implements IDestroyable {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Populates default information about the audio clip from the event body.
|
||||
* The placeholders will be overridden once known.
|
||||
* @param {MatrixEvent} event The event to use for placeholders.
|
||||
*/
|
||||
public populatePlaceholdersFrom(event: MatrixEvent) {
|
||||
const durationSeconds = Number(event.getContent()['info']?.['duration']);
|
||||
if (Number.isFinite(durationSeconds)) this.placeholderDuration = durationSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark the time in the audio context where the clip starts/has been loaded.
|
||||
* This is to ensure the clock isn't skewed into thinking it is ~0.5s into
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue