Skip to content

Commit

Permalink
chore: apply review, add resume to player
Browse files Browse the repository at this point in the history
  • Loading branch information
bang9 committed Nov 3, 2023
1 parent c6b8329 commit 8b5c33a
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ const createNativePlayerService = ({ audioRecorderModule, permissionModule }: Mo
const module = new audioRecorderModule.default();

class Player implements PlayerServiceInterface {
uri?: string;
state: PlayerServiceInterface['state'] = 'idle';
private readonly subscribers = new Set<(currentTime: number, duration: number) => void>();

constructor() {
this.state = 'idle';

module.setSubscriptionDuration(1);
module.setSubscriptionDuration(0.1);
module.addPlayBackListener((data) => {
this.subscribers.forEach((callback) => {
callback(data.currentPosition, data.duration);
Expand All @@ -44,49 +45,55 @@ const createNativePlayerService = ({ audioRecorderModule, permissionModule }: Mo
}
}

async play(uri: string, headers?: Record<string, string>): Promise<void> {
if (this.state === 'playing') return;
addListener(callback: (currentTime: number, duration: number) => void): Unsubscribe {
this.subscribers.add(callback);
return () => {
this.subscribers.delete(callback);
};
}

try {
this.state = 'preparing';
await module.startPlayer(uri, headers);
async play(uri: string): Promise<void> {
if (this.state === 'idle' || this.state === 'stopped') {
try {
this.state = 'preparing';
this.uri = uri;
await module.startPlayer(uri);
this.state = 'playing';
} catch {
this.state = 'idle';
this.uri = undefined;
}
} else if (this.state === 'paused' && this.uri === uri) {
await module.resumePlayer();
this.state = 'playing';
} catch {
this.state = 'idle';
}
}

async seek(time: number): Promise<void> {
if (this.state !== 'playing') return;

await module.seekToPlayer(time);
}

async pause(): Promise<void> {
if (this.state === 'paused' || this.state === 'stopped') return;

await module.pausePlayer();
this.state = 'paused';
if (this.state === 'playing') {
await module.pausePlayer();
this.state = 'paused';
}
}

async stop(): Promise<void> {
if (this.state === 'stopped') return;

await module.stopPlayer();
this.state = 'stopped';
if (this.state === 'preparing' || this.state === 'playing' || this.state === 'paused') {
await module.stopPlayer();
this.state = 'stopped';
}
}

async reset(): Promise<void> {
await this.stop();
this.state = 'idle';
this.uri = undefined;
this.subscribers.clear();
}

addListener(callback: (currentTime: number, duration: number) => void): Unsubscribe {
this.subscribers.add(callback);
return () => {
this.subscribers.delete(callback);
};
async seek(time: number): Promise<void> {
if (this.state !== 'playing' && this.state !== 'paused') return;

await module.seekToPlayer(time);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const createNativeRecorderService = ({ audioRecorderModule, permissionModule }:
constructor() {
this.state = 'idle';

module.setSubscriptionDuration(0.5);
module.setSubscriptionDuration(0.1);
module.addRecordBackListener((data) => {
if (this.state === 'recording') {
this.subscribers.forEach((callback) => {
Expand Down Expand Up @@ -88,39 +88,39 @@ const createNativeRecorderService = ({ audioRecorderModule, permissionModule }:
}
}

addListener(callback: (currentTime: number) => void): Unsubscribe {
this.subscribers.add(callback);
return () => {
this.subscribers.delete(callback);
};
}

async record(uri?: string): Promise<void> {
if (this.state === 'recording') return;

try {
this.state = 'preparing';
await module.startRecorder(uri, {
...this.audioOptions,
});
this.state = 'recording';
} catch {
this.state = 'idle';
if (this.state === 'idle' || this.state === 'completed') {
try {
this.state = 'preparing';
await module.startRecorder(uri, {
...this.audioOptions,
});
this.state = 'recording';
} catch {
this.state = 'idle';
}
}
}

async stop(): Promise<void> {
if (this.state === 'completed') return;

await module.stopRecorder();
this.state = 'completed';
if (this.state === 'recording') {
await module.stopRecorder();
this.state = 'completed';
}
}

async reset(): Promise<void> {
await this.stop();
this.state = 'idle';
this.subscribers.clear();
}

addListener(callback: (currentTime: number) => void): Unsubscribe {
this.subscribers.add(callback);
return () => {
this.subscribers.delete(callback);
};
}
}

return new Recorder();
Expand Down
71 changes: 65 additions & 6 deletions packages/uikit-react-native/src/platform/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,31 +109,90 @@ export interface MediaServiceInterface {
// ---------- PlayerService ---------- //
export interface PlayerServiceInterface {
state: 'idle' | 'preparing' | 'playing' | 'paused' | 'stopped';

/**
* Check and request permission for the player.
* */
requestPermission(): Promise<boolean>;
play(uri: string, headers?: Record<string, string>): Promise<void>;
seek(time: number): Promise<void>;

/**
* Add a playback listener.
* */
addListener(callback: (currentTime: number, duration: number) => void): Unsubscribe;

/**
* State transition:
* [idle, stopped] to [playing] - start from the beginning
* [paused] to [playing] - resume
* */
play(uri: string): Promise<void>;

/**
* State transition:
* [playing] to [paused]
* */
pause(): Promise<void>;

/**
* State transition:
* [preparing, playing, paused] to [stop]
* */
stop(): Promise<void>;

/**
* State transition:
* [*] to [idle]
* */
reset(): Promise<void>;
addListener(callback: (currentTime: number, duration: number) => void): Unsubscribe;

/**
* Seek time, only available when the state is [playing, paused].
* */
seek(time: number): Promise<void>;
}

// ---------- RecorderService ---------- //
export interface RecorderOptions {
/**
* Minimum recording duration (seconds)
* Minimum recording duration (seconds).
* */
minDuration: number;

/**
* Maximum recording duration (seconds)
* Maximum recording duration (seconds).
* */
maxDuration: number;
}

export interface RecorderServiceInterface {
options: RecorderOptions;
state: 'idle' | 'preparing' | 'recording' | 'completed';

/**
* Check and request permission for the recorder.
* */
requestPermission(): Promise<boolean>;

/**
* Add recording listener.
* */
addListener(callback: (duration: number) => void): Unsubscribe;

/**
* State transition:
* [idle, completed] to [recording]
* */
record(uri?: string): Promise<void>;

/**
* State transition:
* [recording] to [completed]
* */
stop(): Promise<void>;
addListener(callback: (duration: number) => void): Unsubscribe;

/**
* State transition:
* [*] to [idle]
* */
reset(): Promise<void>;
}

0 comments on commit 8b5c33a

Please sign in to comment.