Skip to content

Commit 8e80d35

Browse files
committed
make loadSound public + play or seek after load
1 parent fc1fea6 commit 8e80d35

File tree

2 files changed

+79
-39
lines changed

2 files changed

+79
-39
lines changed

src/library/core.ts

Lines changed: 65 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { PlayerSound, ISound, ISoundAttributes, ISoundSource, typeSoundStates } from './sound';
1+
import { PlayerSound, ISound, ISoundAttributes, ISoundSource } from './sound';
22
import {
33
PlayerAudio,
44
IAudioOptions,
@@ -37,10 +37,6 @@ export interface ISoundsQueueOptions {
3737
whereInQueue?: typeWhereInQueue;
3838
}
3939

40-
interface IDecodeSoundOptions {
41-
sound: ISound;
42-
}
43-
4440
export interface IPlayOptions {
4541
whichSound?: number | string | undefined;
4642
playTimeOffset?: number;
@@ -288,21 +284,37 @@ export class PlayerCore {
288284

289285
if (currentSound !== null) {
290286

291-
let duration = currentSound.getDuration();
287+
currentSound.seekPercentage = Math.round(soundPositionInPercent);
288+
289+
const duration = currentSound.getDuration();
292290

293291
// if the duration did not get set manually or is not a number
294292
if (duration === null || isNaN(duration)) {
295293

296294
// the user can set the sound duration manually but if he didn't the sound
297295
// needs to get loaded first, to be able to know the duration it has
298-
await this._loadSound(currentSound);
296+
await this.loadSound(currentSound);
299297

300-
duration = currentSound.getDuration();
298+
} else {
299+
300+
this._setPosition(currentSound);
301301

302302
}
303303

304+
}
305+
306+
}
307+
308+
protected _setPosition(sound: ISound): void {
309+
310+
const currentSound = this._getSoundFromQueue({ whichSound: PlayerCore.CURRENT_SOUND });
311+
312+
if (currentSound !== null) {
313+
314+
const duration = currentSound.getDuration();
315+
304316
// calculate the position in seconds
305-
const soundPositionInSeconds = (duration / 100) * soundPositionInPercent;
317+
const soundPositionInSeconds = (duration / 100) * sound.seekPercentage;
306318

307319
this.setPositionInSeconds(soundPositionInSeconds);
308320

@@ -323,6 +335,10 @@ export class PlayerCore {
323335
soundPositionInSeconds = currentSound.duration - 0.1
324336
}
325337

338+
const previousState = currentSound.state;
339+
340+
currentSound.state = PlayerSound.SOUND_STATE_SEEKING;
341+
326342
if (currentSound.onSeeking !== null) {
327343

328344
const playTime = soundPositionInSeconds;
@@ -334,7 +350,7 @@ export class PlayerCore {
334350

335351
}
336352

337-
if (currentSound.state === PlayerSound.SOUND_STATE_PLAYING) {
353+
if (previousState === PlayerSound.SOUND_STATE_PLAYING) {
338354

339355
// already playing so just change the position
340356
currentSound.playTime = soundPositionInSeconds;
@@ -343,26 +359,25 @@ export class PlayerCore {
343359
// in ajax mode (when source is AudioBufferSourceNode) we
344360
// need to stop the song and start again at new position
345361
currentSound.elapsedPlayTime = soundPositionInSeconds;
346-
await this._stop(currentSound, PlayerSound.SOUND_STATE_SEEKING);
362+
await this._stop(currentSound);
347363
} else if (this._options.loadPlayerMode === PlayerCore.PLAYER_MODE_AUDIO) {
348364
// in audio (element) mode it is easier we can just change the position
349-
currentSound.state = PlayerSound.SOUND_STATE_SEEKING;
350365
await this._play(currentSound);
351366
}
352367

353368
} else {
354369

355-
// only set the sound position but don't play yet
370+
// setPositionInSeconds got called and sound is currently not playing
371+
// only set the sound position but don't play
356372
currentSound.playTime = soundPositionInSeconds;
357-
currentSound.state = PlayerSound.SOUND_STATE_SEEKING;
358373

359374
}
360375

361376
}
362377

363378
}
364379

365-
protected async _loadSound(sound: ISound): Promise<void> {
380+
public async loadSound(sound: ISound): Promise<ISound> {
366381

367382
switch (this._options.loadPlayerMode) {
368383
case PlayerCore.PLAYER_MODE_AUDIO:
@@ -374,8 +389,11 @@ export class PlayerCore {
374389
case PlayerCore.PLAYER_MODE_FETCH:
375390
// TODO: implement fetch (?)
376391
console.warn(PlayerCore.PLAYER_MODE_FETCH + ' is not implemented yet');
392+
break;
377393
}
378394

395+
return sound;
396+
379397
}
380398

381399
protected async _loadSoundUsingAudioElement(sound: ISound): Promise<void> {
@@ -428,8 +446,15 @@ export class PlayerCore {
428446
sound.duration = sound.audioElement.duration;
429447
}
430448

431-
await this._play(sound);
432-
449+
switch (sound.state) {
450+
case PlayerSound.SOUND_STATE_SEEKING:
451+
this._setPosition(sound)
452+
break;
453+
case PlayerSound.SOUND_STATE_PLAYING:
454+
this._play(sound);
455+
break;
456+
}
457+
433458
}
434459

435460
sound.audioElement.addEventListener('canplaythrough', canPlayThroughHandler);
@@ -470,7 +495,7 @@ export class PlayerCore {
470495

471496
// user provided array buffer
472497
if (sound.arrayBuffer !== null) {
473-
return await this._decodeSound({ sound });
498+
return await this._decodeSound(sound);
474499
}
475500

476501
// extract the url and codec from sources
@@ -487,7 +512,7 @@ export class PlayerCore {
487512
const arrayBuffer = await request.getArrayBuffer(sound);
488513
sound.arrayBuffer = arrayBuffer;
489514

490-
await this._decodeSound({ sound });
515+
await this._decodeSound(sound);
491516

492517
} else {
493518

@@ -497,7 +522,7 @@ export class PlayerCore {
497522

498523
}
499524

500-
protected async _decodeSound({ sound }: IDecodeSoundOptions): Promise<void> {
525+
protected async _decodeSound(sound: ISound): Promise<void> {
501526

502527
// make a copy of the array buffer first
503528
// because the decoding will detach the array buffer
@@ -517,7 +542,14 @@ export class PlayerCore {
517542
sound.audioBufferDate = new Date();
518543
sound.isReadyToPLay = true;
519544

520-
await this._play(sound);
545+
switch (sound.state) {
546+
case PlayerSound.SOUND_STATE_SEEKING:
547+
this._setPosition(sound)
548+
break;
549+
case PlayerSound.SOUND_STATE_PLAYING:
550+
this._play(sound);
551+
break;
552+
}
521553

522554
}
523555

@@ -561,7 +593,8 @@ export class PlayerCore {
561593
&& (currentSound.id !== sound.id)
562594
) {
563595
// stop the current sound
564-
await this._stop(currentSound, PlayerSound.SOUND_STATE_STOPPED);
596+
currentSound.state = PlayerSound.SOUND_STATE_STOPPED;
597+
await this._stop(currentSound);
565598
}
566599

567600
// if the user wants to play the sound from a certain position
@@ -581,7 +614,7 @@ export class PlayerCore {
581614

582615
if (!sound.isReadyToPLay) {
583616

584-
await this._loadSound(sound);
617+
await this.loadSound(sound);
585618

586619
} else {
587620

@@ -1082,7 +1115,9 @@ export class PlayerCore {
10821115
currentSound.onPaused(currentSound.playTime);
10831116
}
10841117

1085-
await this._stop(currentSound, PlayerSound.SOUND_STATE_PAUSED);
1118+
currentSound.state = PlayerSound.SOUND_STATE_PAUSED;
1119+
1120+
await this._stop(currentSound);
10861121

10871122
return currentSound;
10881123

@@ -1108,21 +1143,21 @@ export class PlayerCore {
11081143
currentSound.onStopped(currentSound.playTime);
11091144
}
11101145

1111-
await this._stop(currentSound, PlayerSound.SOUND_STATE_STOPPED);
1146+
currentSound.state = PlayerSound.SOUND_STATE_STOPPED;
1147+
1148+
await this._stop(currentSound);
11121149

11131150
return currentSound;
11141151

11151152
}
11161153

1117-
protected async _stop(sound: ISound, soundState: typeSoundStates): Promise<void> {
1154+
protected async _stop(sound: ISound): Promise<void> {
11181155

11191156
if (this._playingProgressRequestId !== null) {
11201157
cancelAnimationFrame(this._playingProgressRequestId);
11211158
this._playingProgressRequestId = null;
11221159
}
11231160

1124-
sound.state = soundState;
1125-
11261161
if (sound.sourceNode !== null) {
11271162

11281163
if (sound.sourceNode instanceof AudioBufferSourceNode) {
@@ -1140,8 +1175,8 @@ export class PlayerCore {
11401175

11411176
}
11421177

1143-
// if it is fully stopped, not just paused
1144-
if (soundState === PlayerSound.SOUND_STATE_STOPPED) {
1178+
// if it is fully stopped, not just paused (or seeking)
1179+
if (sound.state === PlayerSound.SOUND_STATE_STOPPED) {
11451180
// reset sound values
11461181
sound.isReadyToPLay = false;
11471182
sound.firstTimePlayed = true;

src/library/sound.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export interface ISoundAttributes {
4949
arrayBuffer?: ArrayBuffer;
5050
duration?: number;
5151

52-
// events
52+
// callbacks
5353
onLoading?: IOnProgress;
5454
onPlaying?: IOnProgress;
5555
onEnded?: IOnEnded;
@@ -61,6 +61,7 @@ export interface ISoundAttributes {
6161
}
6262

6363
export interface ISound extends ISoundAttributes, ISoundSource {
64+
// public properties
6465
sourceNode: AudioBufferSourceNode | MediaElementAudioSourceNode;
6566
gainNode: GainNode;
6667
isReadyToPLay: boolean;
@@ -71,13 +72,15 @@ export interface ISound extends ISoundAttributes, ISoundSource {
7172
playTimeOffset: number;
7273
startTime: number;
7374
playTime: number;
74-
elapsedPlayTime: number;
7575
playedTimePercentage: number;
7676
state: typeSoundStates;
7777
loadingProgress: number;
7878
firstTimePlayed: boolean;
7979
isConnectToPlayerGain: boolean;
8080
durationSetManually: boolean;
81+
elapsedPlayTime: number;
82+
seekPercentage: number;
83+
// methods
8184
getCurrentTime(): number;
8285
getDuration(): number;
8386
setDuration(duration: number): void;
@@ -93,7 +96,7 @@ export class PlayerSound implements ISound {
9396
static readonly SOUND_STATE_PLAYING = 'sound_state_playing';
9497
static readonly SOUND_STATE_SEEKING = 'sound_state_seeking';
9598

96-
// properties
99+
// public properties
97100
public source: (ISoundSource)[] | ISoundSource;
98101
public url: string = null;
99102
public codec: string = null;
@@ -110,11 +113,6 @@ export class PlayerSound implements ISound {
110113
public audioBufferDate: Date = null;
111114
public playTimeOffset = 0;
112115
public startTime = 0;
113-
// elapsedPlayTime is used to adjust the playtime
114-
// when playing audio buffers
115-
// on seek, pause or when there is a playTimeOffset
116-
// see getCurrentTime function
117-
public elapsedPlayTime = 0;
118116
public playTime = 0;
119117
public playedTimePercentage = 0;
120118
public state: typeSoundStates = SOUND_STATE_STOPPED;
@@ -123,7 +121,14 @@ export class PlayerSound implements ISound {
123121
public durationSetManually: boolean = false;
124122
public firstTimePlayed = true;
125123
public isConnectToPlayerGain = false;
126-
124+
// elapsedPlayTime is used to adjust the playtime
125+
// when playing audio buffers
126+
// on seek, pause or when there is a playTimeOffset
127+
// see getCurrentTime function
128+
public elapsedPlayTime = 0;
129+
// the percentage to seek to
130+
public seekPercentage = 0;
131+
127132
// callbacks
128133
public onLoading: IOnProgress;
129134
public onPlaying: IOnProgress;

0 commit comments

Comments
 (0)