source: main/trunk/model-interfaces-dev/atea/korero-maori-asr/src/js/AudioPlaybackModule.js@ 35631

Last change on this file since 35631 was 35631, checked in by cstephen, 3 years ago

Improve audio loading flow.
Load audio on word editor click.

File size: 4.7 KB
Line 
1/**
2 * @file Provides an interface for playing transcription audio.
3 * @author Carl Stephens
4 * @module
5 */
6
7class LoadedAudio {
8 /**
9 * Initialises a new instance of the {@link LoadedAudio} class.
10 * @param {String | null} id The ID of the transcription for which this audio belongs to.
11 * @param {String | null} url The audio object URL.
12 */
13 constructor(id, url) {
14 /** @type {String | null} The ID of the transcription for which this audio belongs to. */
15 this.id = id;
16
17 /** @type {String | null} The audio object URL. */
18 this.url = url;
19 }
20}
21
22/**
23 * Polls an audio element's current time and updates the vuex store accordingly.
24 * @param {Audio} audioElement The audio element.
25 * @param {*} store The vuex store to update.
26 */
27function pollAudioTime(audioElement, store) {
28 var lastTime = 0;
29
30 (function poll() {
31 if (audioElement.currentTime !== lastTime) {
32 lastTime = audioElement.currentTime;
33 store.commit("playbackStateSetTime", { id: store.state.playbackState.id, time: lastTime });
34 }
35
36 requestAnimationFrame(poll);
37 })();
38}
39
40/**
41 * Loads an audio file.
42 * @param {HTMLAudioElement} player The audio player.
43 * @param {TranscriptionViewModel} transcription The name of the requested audio file.
44 * @param {LoadedAudio} current The currently loaded audio.
45 * @returns {LoadedAudio} If a new audio file was loaded, a new audio tracking object, else the current one.
46 */
47function loadAudio(player, transcription, current) {
48 // TODO: Need to profile on some larger tracks; this may not be worth it? Better to cache a URL object instead?
49 if (current.url !== null) {
50 URL.revokeObjectURL(current.url);
51 }
52
53 const urlObject = URL.createObjectURL(transcription.file);
54 player.src = urlObject;
55 player.load();
56
57 return new LoadedAudio(transcription.id, urlObject);
58}
59
60export default class AudioPlayback {
61 /**
62 * Initialises the {@link AudioPlayback} class.
63 * @param {*} store The vuex store to update.
64 */
65 static initialise(store) {
66 /** @type The vuex store. */
67 this.store = store;
68
69 this.player = new Audio();
70 this.loadedAudio = new LoadedAudio(null, null);
71 this.requestedPlaybackTime = 0;
72
73 pollAudioTime(this.player, store);
74
75 this.player.addEventListener("ended", function() {
76 store.commit("playbackStateSetIsPlaying", false);
77 });
78 }
79
80 static onCanPlayThrough() {
81 AudioPlayback.player.removeEventListener("canplaythrough", AudioPlayback.onCanPlayThrough);
82
83 AudioPlayback.player.currentTime = AudioPlayback.requestedPlaybackTime;
84 AudioPlayback.store.commit("playbackStateSetLength", { id: AudioPlayback.loadedAudio.id, time: AudioPlayback.player.duration });
85 }
86
87 /**
88 * Loads a transcription's audio file.
89 * @param {String} id The ID of the transcription to load the audio of.
90 * @param {Number} startTime The time into the audio to set the current playback time to. Leave negative to select the last value, or zero.
91 */
92 static async load(id, startTime = -1) {
93 this.player.addEventListener("canplaythrough", this.onCanPlayThrough);
94
95 const playbackTimes = this.store.state.playbackState.playbackTimes;
96
97 this.requestedPlaybackTime = startTime;
98 if (playbackTimes.has(id) && startTime < 0) {
99 this.requestedPlaybackTime = playbackTimes.get(id);
100 }
101
102 if (this.loadedAudio.id !== id) {
103 this.loadedAudio = loadAudio(this.player, this.store.state.rawTranscriptions.get(id), this.loadedAudio);
104
105 this.store.commit("playbackStateSetID", id);
106 }
107
108 this.player.currentTime = AudioPlayback.requestedPlaybackTime;
109 this.store.commit("playbackStateSetLength", { id: id, time: this.player.duration });
110 }
111
112 /**
113 * Plays a transcription's audio file.
114 * @param {String} id The ID of the transcription to play audio for.
115 * @param {Number} startTime The time into the audio at which to start playing. Leave negative to resume playback if paused.
116 */
117 static async play(id, startTime = -1) {
118 await this.load(id, startTime);
119 await this.player.play();
120 this.store.commit("playbackStateSetIsPlaying", true);
121 }
122
123 /**
124 * Sets the current time of the audio player.
125 * @param {Number} time The time to scrub to.
126 * @param {Boolean} fromCurrent Indicates if the time is an offset.
127 */
128 static scrub(time, fromCurrent) {
129 const newTime = fromCurrent ? this.player.currentTime + time : time;
130 this.player.currentTime = newTime;
131 }
132
133 /**
134 * Pauses playback.
135 */
136 static pause() {
137 this.player.pause();
138 this.store.commit("playbackStateSetIsPlaying", false);
139 }
140}
Note: See TracBrowser for help on using the repository browser.