nosnia-audio-recorder 0.1.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +66 -3
- package/android/src/main/java/com/nosniaaudiorecorder/NosniaAudioPlayerModule.kt +238 -0
- package/android/src/main/java/com/nosniaaudiorecorder/NosniaAudioRecorderModule.kt +59 -1
- package/android/src/main/java/com/nosniaaudiorecorder/NosniaAudioRecorderPackage.kt +12 -4
- package/ios/NosniaAudioPlayer.h +7 -0
- package/ios/NosniaAudioPlayer.mm +263 -0
- package/ios/NosniaAudioRecorder.h +2 -1
- package/ios/NosniaAudioRecorder.mm +51 -0
- package/lib/module/AudioPlayer.js +176 -0
- package/lib/module/AudioPlayer.js.map +1 -0
- package/lib/module/NativeNosniaAudioPlayer.js +5 -0
- package/lib/module/NativeNosniaAudioPlayer.js.map +1 -0
- package/lib/module/index.js +37 -1
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/AudioPlayer.d.ts +76 -0
- package/lib/typescript/src/AudioPlayer.d.ts.map +1 -0
- package/lib/typescript/src/NativeNosniaAudioPlayer.d.ts +24 -0
- package/lib/typescript/src/NativeNosniaAudioPlayer.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +17 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +19 -7
- package/src/AudioPlayer.tsx +201 -0
- package/src/NativeNosniaAudioPlayer.ts +26 -0
- package/src/index.tsx +58 -1
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { type PlayOptions, type PlayerStatus } from './NativeNosniaAudioPlayer';
|
|
2
|
+
export type { PlayOptions, PlayerStatus };
|
|
3
|
+
export type PlaybackProgressCallback = (data: {
|
|
4
|
+
currentTime: number;
|
|
5
|
+
duration: number;
|
|
6
|
+
isPlaying: boolean;
|
|
7
|
+
}) => void;
|
|
8
|
+
export type PlaybackCompleteCallback = () => void;
|
|
9
|
+
declare class AudioPlayer {
|
|
10
|
+
private static instance;
|
|
11
|
+
private eventEmitter;
|
|
12
|
+
private progressListener;
|
|
13
|
+
private completeListener;
|
|
14
|
+
private constructor();
|
|
15
|
+
static getInstance(): AudioPlayer;
|
|
16
|
+
/**
|
|
17
|
+
* Add a listener for playback progress updates
|
|
18
|
+
* @param callback Function called with playback progress (every 100ms during playback)
|
|
19
|
+
* @returns Function to remove the listener
|
|
20
|
+
*/
|
|
21
|
+
addPlaybackProgressListener(callback: PlaybackProgressCallback): () => void;
|
|
22
|
+
/**
|
|
23
|
+
* Remove the playback progress listener
|
|
24
|
+
*/
|
|
25
|
+
removePlaybackProgressListener(): void;
|
|
26
|
+
/**
|
|
27
|
+
* Add a listener for playback completion
|
|
28
|
+
* @param callback Function called when playback completes
|
|
29
|
+
* @returns Function to remove the listener
|
|
30
|
+
*/
|
|
31
|
+
addPlaybackCompleteListener(callback: PlaybackCompleteCallback): () => void;
|
|
32
|
+
/**
|
|
33
|
+
* Remove the playback complete listener
|
|
34
|
+
*/
|
|
35
|
+
removePlaybackCompleteListener(): void;
|
|
36
|
+
/**
|
|
37
|
+
* Start playing audio from a file path
|
|
38
|
+
* @param options Configuration options (filePath, volume, loop)
|
|
39
|
+
* @returns Promise that resolves when playback starts
|
|
40
|
+
*/
|
|
41
|
+
startPlaying(options: PlayOptions): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Stop playing and reset player
|
|
44
|
+
* @returns Promise that resolves when playback stops
|
|
45
|
+
*/
|
|
46
|
+
stopPlaying(): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Pause the current playback
|
|
49
|
+
* @returns Promise that resolves when playback is paused
|
|
50
|
+
*/
|
|
51
|
+
pausePlaying(): Promise<void>;
|
|
52
|
+
/**
|
|
53
|
+
* Resume a paused playback
|
|
54
|
+
* @returns Promise that resolves when playback resumes
|
|
55
|
+
*/
|
|
56
|
+
resumePlaying(): Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Seek to a specific time in the audio
|
|
59
|
+
* @param time Time in seconds
|
|
60
|
+
* @returns Promise that resolves when seek completes
|
|
61
|
+
*/
|
|
62
|
+
seekToTime(time: number): Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* Set the playback volume
|
|
65
|
+
* @param volume Volume level (0.0 to 1.0)
|
|
66
|
+
* @returns Promise that resolves when volume is set
|
|
67
|
+
*/
|
|
68
|
+
setVolume(volume: number): Promise<void>;
|
|
69
|
+
/**
|
|
70
|
+
* Get the current status of the player
|
|
71
|
+
* @returns Promise that resolves to the current player status
|
|
72
|
+
*/
|
|
73
|
+
getStatus(): Promise<PlayerStatus>;
|
|
74
|
+
}
|
|
75
|
+
export declare const NosniaAudioPlayer: AudioPlayer;
|
|
76
|
+
//# sourceMappingURL=AudioPlayer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AudioPlayer.d.ts","sourceRoot":"","sources":["../../../src/AudioPlayer.tsx"],"names":[],"mappings":"AACA,OAAqB,EACnB,KAAK,WAAW,EAChB,KAAK,YAAY,EAClB,MAAM,2BAA2B,CAAC;AAEnC,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,CAAC;AAE1C,MAAM,MAAM,wBAAwB,GAAG,CAAC,IAAI,EAAE;IAC5C,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;CACpB,KAAK,IAAI,CAAC;AAEX,MAAM,MAAM,wBAAwB,GAAG,MAAM,IAAI,CAAC;AAElD,cAAM,WAAW;IACf,OAAO,CAAC,MAAM,CAAC,QAAQ,CAA4B;IACnD,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,gBAAgB,CAAa;IACrC,OAAO,CAAC,gBAAgB,CAAa;IAErC,OAAO;IAIP,MAAM,CAAC,WAAW,IAAI,WAAW;IAOjC;;;;OAIG;IACH,2BAA2B,CAAC,QAAQ,EAAE,wBAAwB,GAAG,MAAM,IAAI;IAkB3E;;OAEG;IACH,8BAA8B,IAAI,IAAI;IAOtC;;;;OAIG;IACH,2BAA2B,CAAC,QAAQ,EAAE,wBAAwB,GAAG,MAAM,IAAI;IAkB3E;;OAEG;IACH,8BAA8B,IAAI,IAAI;IAOtC;;;;OAIG;IACG,YAAY,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAcvD;;;OAGG;IACG,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IASlC;;;OAGG;IACG,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IASnC;;;OAGG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IASpC;;;;OAIG;IACG,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS7C;;;;OAIG;IACG,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAU9C;;;OAGG;IACG,SAAS,IAAI,OAAO,CAAC,YAAY,CAAC;CAQzC;AAED,eAAO,MAAM,iBAAiB,aAA4B,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type TurboModule } from 'react-native';
|
|
2
|
+
export interface PlayerStatus {
|
|
3
|
+
isPlaying: boolean;
|
|
4
|
+
duration: number;
|
|
5
|
+
currentTime: number;
|
|
6
|
+
currentFilePath?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface PlayOptions {
|
|
9
|
+
filePath: string;
|
|
10
|
+
volume?: number;
|
|
11
|
+
loop?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface Spec extends TurboModule {
|
|
14
|
+
startPlaying(options: PlayOptions): Promise<void>;
|
|
15
|
+
stopPlaying(): Promise<void>;
|
|
16
|
+
pausePlaying(): Promise<void>;
|
|
17
|
+
resumePlaying(): Promise<void>;
|
|
18
|
+
seekToTime(time: number): Promise<void>;
|
|
19
|
+
setVolume(volume: number): Promise<void>;
|
|
20
|
+
getPlayerStatus(): Promise<PlayerStatus>;
|
|
21
|
+
}
|
|
22
|
+
declare const _default: Spec;
|
|
23
|
+
export default _default;
|
|
24
|
+
//# sourceMappingURL=NativeNosniaAudioPlayer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NativeNosniaAudioPlayer.d.ts","sourceRoot":"","sources":["../../../src/NativeNosniaAudioPlayer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAErE,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,YAAY,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,eAAe,IAAI,OAAO,CAAC,YAAY,CAAC,CAAC;CAC1C;;AAED,wBAA2E"}
|
|
@@ -1,9 +1,25 @@
|
|
|
1
1
|
import { type RecorderOptions, type RecorderStatus } from './NativeNosniaAudioRecorder';
|
|
2
2
|
export type { RecorderOptions, RecorderStatus };
|
|
3
|
+
export type RecordingProgressCallback = (data: {
|
|
4
|
+
duration: number;
|
|
5
|
+
isRecording: boolean;
|
|
6
|
+
}) => void;
|
|
3
7
|
declare class AudioRecorder {
|
|
4
8
|
private static instance;
|
|
9
|
+
private eventEmitter;
|
|
10
|
+
private progressListener;
|
|
5
11
|
private constructor();
|
|
6
12
|
static getInstance(): AudioRecorder;
|
|
13
|
+
/**
|
|
14
|
+
* Add a listener for recording progress updates
|
|
15
|
+
* @param callback Function called with duration updates (every 100ms during recording)
|
|
16
|
+
* @returns Function to remove the listener
|
|
17
|
+
*/
|
|
18
|
+
addRecordingProgressListener(callback: RecordingProgressCallback): () => void;
|
|
19
|
+
/**
|
|
20
|
+
* Remove the recording progress listener
|
|
21
|
+
*/
|
|
22
|
+
removeRecordingProgressListener(): void;
|
|
7
23
|
/**
|
|
8
24
|
* Request audio recording permission from the user
|
|
9
25
|
* @returns Promise that resolves to true if permission is granted
|
|
@@ -47,4 +63,5 @@ declare class AudioRecorder {
|
|
|
47
63
|
getStatus(): Promise<RecorderStatus>;
|
|
48
64
|
}
|
|
49
65
|
export declare const NosniaAudioRecorder: AudioRecorder;
|
|
66
|
+
export { NosniaAudioPlayer, type PlayOptions, type PlayerStatus, type PlaybackProgressCallback, type PlaybackCompleteCallback, } from './AudioPlayer';
|
|
50
67
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AACA,OAAqB,EACnB,KAAK,eAAe,EACpB,KAAK,cAAc,EACpB,MAAM,6BAA6B,CAAC;AAErC,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,CAAC;AAEhD,MAAM,MAAM,yBAAyB,GAAG,CAAC,IAAI,EAAE;IAC7C,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;CACtB,KAAK,IAAI,CAAC;AAEX,cAAM,aAAa;IACjB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAA8B;IACrD,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,gBAAgB,CAAa;IAErC,OAAO;IAMP,MAAM,CAAC,WAAW,IAAI,aAAa;IAOnC;;;;OAIG;IACH,4BAA4B,CAC1B,QAAQ,EAAE,yBAAyB,GAClC,MAAM,IAAI;IAmBb;;OAEG;IACH,+BAA+B,IAAI,IAAI;IAOvC;;;OAGG;IACG,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC;IAS3C;;;OAGG;IACG,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;IASzC;;;;OAIG;IACG,cAAc,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAuB9D;;;OAGG;IACG,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC;IAStC;;;OAGG;IACG,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IASrC;;;OAGG;IACG,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAStC;;;OAGG;IACG,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAStC;;;OAGG;IACG,SAAS,IAAI,OAAO,CAAC,cAAc,CAAC;CAQ3C;AAED,eAAO,MAAM,mBAAmB,eAA8B,CAAC;AAG/D,OAAO,EACL,iBAAiB,EACjB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,wBAAwB,EAC7B,KAAK,wBAAwB,GAC9B,MAAM,eAAe,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nosnia-audio-recorder",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "This is a modern audio recorder which actually works cross platform",
|
|
5
5
|
"main": "./lib/module/index.js",
|
|
6
6
|
"types": "./lib/typescript/src/index.d.ts",
|
|
@@ -111,12 +111,24 @@
|
|
|
111
111
|
]
|
|
112
112
|
},
|
|
113
113
|
"codegenConfig": {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
114
|
+
"libraries": [
|
|
115
|
+
{
|
|
116
|
+
"name": "NosniaAudioRecorderSpec",
|
|
117
|
+
"type": "modules",
|
|
118
|
+
"jsSrcsDir": "src",
|
|
119
|
+
"android": {
|
|
120
|
+
"javaPackageName": "com.nosniaaudiorecorder"
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"name": "NosniaAudioPlayerSpec",
|
|
125
|
+
"type": "modules",
|
|
126
|
+
"jsSrcsDir": "src",
|
|
127
|
+
"android": {
|
|
128
|
+
"javaPackageName": "com.nosniaaudiorecorder"
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
]
|
|
120
132
|
},
|
|
121
133
|
"prettier": {
|
|
122
134
|
"quoteProps": "consistent",
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { NativeEventEmitter, NativeModules } from 'react-native';
|
|
2
|
+
import NativeModule, {
|
|
3
|
+
type PlayOptions,
|
|
4
|
+
type PlayerStatus,
|
|
5
|
+
} from './NativeNosniaAudioPlayer';
|
|
6
|
+
|
|
7
|
+
export type { PlayOptions, PlayerStatus };
|
|
8
|
+
|
|
9
|
+
export type PlaybackProgressCallback = (data: {
|
|
10
|
+
currentTime: number;
|
|
11
|
+
duration: number;
|
|
12
|
+
isPlaying: boolean;
|
|
13
|
+
}) => void;
|
|
14
|
+
|
|
15
|
+
export type PlaybackCompleteCallback = () => void;
|
|
16
|
+
|
|
17
|
+
class AudioPlayer {
|
|
18
|
+
private static instance: AudioPlayer | null = null;
|
|
19
|
+
private eventEmitter: NativeEventEmitter;
|
|
20
|
+
private progressListener: any = null;
|
|
21
|
+
private completeListener: any = null;
|
|
22
|
+
|
|
23
|
+
private constructor() {
|
|
24
|
+
this.eventEmitter = new NativeEventEmitter(NativeModules.NosniaAudioPlayer);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
static getInstance(): AudioPlayer {
|
|
28
|
+
if (!AudioPlayer.instance) {
|
|
29
|
+
AudioPlayer.instance = new AudioPlayer();
|
|
30
|
+
}
|
|
31
|
+
return AudioPlayer.instance;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Add a listener for playback progress updates
|
|
36
|
+
* @param callback Function called with playback progress (every 100ms during playback)
|
|
37
|
+
* @returns Function to remove the listener
|
|
38
|
+
*/
|
|
39
|
+
addPlaybackProgressListener(callback: PlaybackProgressCallback): () => void {
|
|
40
|
+
if (this.progressListener) {
|
|
41
|
+
this.progressListener.remove();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
this.progressListener = this.eventEmitter.addListener(
|
|
45
|
+
'onPlaybackProgress',
|
|
46
|
+
(data: any) => callback(data)
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
return () => {
|
|
50
|
+
if (this.progressListener) {
|
|
51
|
+
this.progressListener.remove();
|
|
52
|
+
this.progressListener = null;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Remove the playback progress listener
|
|
59
|
+
*/
|
|
60
|
+
removePlaybackProgressListener(): void {
|
|
61
|
+
if (this.progressListener) {
|
|
62
|
+
this.progressListener.remove();
|
|
63
|
+
this.progressListener = null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Add a listener for playback completion
|
|
69
|
+
* @param callback Function called when playback completes
|
|
70
|
+
* @returns Function to remove the listener
|
|
71
|
+
*/
|
|
72
|
+
addPlaybackCompleteListener(callback: PlaybackCompleteCallback): () => void {
|
|
73
|
+
if (this.completeListener) {
|
|
74
|
+
this.completeListener.remove();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
this.completeListener = this.eventEmitter.addListener(
|
|
78
|
+
'onPlaybackComplete',
|
|
79
|
+
callback
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
return () => {
|
|
83
|
+
if (this.completeListener) {
|
|
84
|
+
this.completeListener.remove();
|
|
85
|
+
this.completeListener = null;
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Remove the playback complete listener
|
|
92
|
+
*/
|
|
93
|
+
removePlaybackCompleteListener(): void {
|
|
94
|
+
if (this.completeListener) {
|
|
95
|
+
this.completeListener.remove();
|
|
96
|
+
this.completeListener = null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Start playing audio from a file path
|
|
102
|
+
* @param options Configuration options (filePath, volume, loop)
|
|
103
|
+
* @returns Promise that resolves when playback starts
|
|
104
|
+
*/
|
|
105
|
+
async startPlaying(options: PlayOptions): Promise<void> {
|
|
106
|
+
try {
|
|
107
|
+
const config: PlayOptions = {
|
|
108
|
+
volume: 1.0,
|
|
109
|
+
loop: false,
|
|
110
|
+
...options,
|
|
111
|
+
};
|
|
112
|
+
return await NativeModule.startPlaying(config);
|
|
113
|
+
} catch (error) {
|
|
114
|
+
console.error('Error starting playback:', error);
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Stop playing and reset player
|
|
121
|
+
* @returns Promise that resolves when playback stops
|
|
122
|
+
*/
|
|
123
|
+
async stopPlaying(): Promise<void> {
|
|
124
|
+
try {
|
|
125
|
+
return await NativeModule.stopPlaying();
|
|
126
|
+
} catch (error) {
|
|
127
|
+
console.error('Error stopping playback:', error);
|
|
128
|
+
throw error;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Pause the current playback
|
|
134
|
+
* @returns Promise that resolves when playback is paused
|
|
135
|
+
*/
|
|
136
|
+
async pausePlaying(): Promise<void> {
|
|
137
|
+
try {
|
|
138
|
+
return await NativeModule.pausePlaying();
|
|
139
|
+
} catch (error) {
|
|
140
|
+
console.error('Error pausing playback:', error);
|
|
141
|
+
throw error;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Resume a paused playback
|
|
147
|
+
* @returns Promise that resolves when playback resumes
|
|
148
|
+
*/
|
|
149
|
+
async resumePlaying(): Promise<void> {
|
|
150
|
+
try {
|
|
151
|
+
return await NativeModule.resumePlaying();
|
|
152
|
+
} catch (error) {
|
|
153
|
+
console.error('Error resuming playback:', error);
|
|
154
|
+
throw error;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Seek to a specific time in the audio
|
|
160
|
+
* @param time Time in seconds
|
|
161
|
+
* @returns Promise that resolves when seek completes
|
|
162
|
+
*/
|
|
163
|
+
async seekToTime(time: number): Promise<void> {
|
|
164
|
+
try {
|
|
165
|
+
return await NativeModule.seekToTime(time);
|
|
166
|
+
} catch (error) {
|
|
167
|
+
console.error('Error seeking:', error);
|
|
168
|
+
throw error;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Set the playback volume
|
|
174
|
+
* @param volume Volume level (0.0 to 1.0)
|
|
175
|
+
* @returns Promise that resolves when volume is set
|
|
176
|
+
*/
|
|
177
|
+
async setVolume(volume: number): Promise<void> {
|
|
178
|
+
try {
|
|
179
|
+
const clampedVolume = Math.max(0, Math.min(1, volume));
|
|
180
|
+
return await NativeModule.setVolume(clampedVolume);
|
|
181
|
+
} catch (error) {
|
|
182
|
+
console.error('Error setting volume:', error);
|
|
183
|
+
throw error;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Get the current status of the player
|
|
189
|
+
* @returns Promise that resolves to the current player status
|
|
190
|
+
*/
|
|
191
|
+
async getStatus(): Promise<PlayerStatus> {
|
|
192
|
+
try {
|
|
193
|
+
return await NativeModule.getPlayerStatus();
|
|
194
|
+
} catch (error) {
|
|
195
|
+
console.error('Error getting player status:', error);
|
|
196
|
+
throw error;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export const NosniaAudioPlayer = AudioPlayer.getInstance();
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { TurboModuleRegistry, type TurboModule } from 'react-native';
|
|
2
|
+
|
|
3
|
+
export interface PlayerStatus {
|
|
4
|
+
isPlaying: boolean;
|
|
5
|
+
duration: number;
|
|
6
|
+
currentTime: number;
|
|
7
|
+
currentFilePath?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface PlayOptions {
|
|
11
|
+
filePath: string;
|
|
12
|
+
volume?: number; // 0.0 to 1.0
|
|
13
|
+
loop?: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface Spec extends TurboModule {
|
|
17
|
+
startPlaying(options: PlayOptions): Promise<void>;
|
|
18
|
+
stopPlaying(): Promise<void>;
|
|
19
|
+
pausePlaying(): Promise<void>;
|
|
20
|
+
resumePlaying(): Promise<void>;
|
|
21
|
+
seekToTime(time: number): Promise<void>;
|
|
22
|
+
setVolume(volume: number): Promise<void>;
|
|
23
|
+
getPlayerStatus(): Promise<PlayerStatus>;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default TurboModuleRegistry.getEnforcing<Spec>('NosniaAudioPlayer');
|
package/src/index.tsx
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { NativeEventEmitter, NativeModules } from 'react-native';
|
|
1
2
|
import NativeModule, {
|
|
2
3
|
type RecorderOptions,
|
|
3
4
|
type RecorderStatus,
|
|
@@ -5,10 +6,21 @@ import NativeModule, {
|
|
|
5
6
|
|
|
6
7
|
export type { RecorderOptions, RecorderStatus };
|
|
7
8
|
|
|
9
|
+
export type RecordingProgressCallback = (data: {
|
|
10
|
+
duration: number;
|
|
11
|
+
isRecording: boolean;
|
|
12
|
+
}) => void;
|
|
13
|
+
|
|
8
14
|
class AudioRecorder {
|
|
9
15
|
private static instance: AudioRecorder | null = null;
|
|
16
|
+
private eventEmitter: NativeEventEmitter;
|
|
17
|
+
private progressListener: any = null;
|
|
10
18
|
|
|
11
|
-
private constructor() {
|
|
19
|
+
private constructor() {
|
|
20
|
+
this.eventEmitter = new NativeEventEmitter(
|
|
21
|
+
NativeModules.NosniaAudioRecorder
|
|
22
|
+
);
|
|
23
|
+
}
|
|
12
24
|
|
|
13
25
|
static getInstance(): AudioRecorder {
|
|
14
26
|
if (!AudioRecorder.instance) {
|
|
@@ -17,6 +29,42 @@ class AudioRecorder {
|
|
|
17
29
|
return AudioRecorder.instance;
|
|
18
30
|
}
|
|
19
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Add a listener for recording progress updates
|
|
34
|
+
* @param callback Function called with duration updates (every 100ms during recording)
|
|
35
|
+
* @returns Function to remove the listener
|
|
36
|
+
*/
|
|
37
|
+
addRecordingProgressListener(
|
|
38
|
+
callback: RecordingProgressCallback
|
|
39
|
+
): () => void {
|
|
40
|
+
// Remove existing listener if any
|
|
41
|
+
if (this.progressListener) {
|
|
42
|
+
this.progressListener.remove();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
this.progressListener = this.eventEmitter.addListener(
|
|
46
|
+
'onRecordingProgress',
|
|
47
|
+
(data: any) => callback(data)
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
return () => {
|
|
51
|
+
if (this.progressListener) {
|
|
52
|
+
this.progressListener.remove();
|
|
53
|
+
this.progressListener = null;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Remove the recording progress listener
|
|
60
|
+
*/
|
|
61
|
+
removeRecordingProgressListener(): void {
|
|
62
|
+
if (this.progressListener) {
|
|
63
|
+
this.progressListener.remove();
|
|
64
|
+
this.progressListener = null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
20
68
|
/**
|
|
21
69
|
* Request audio recording permission from the user
|
|
22
70
|
* @returns Promise that resolves to true if permission is granted
|
|
@@ -138,3 +186,12 @@ class AudioRecorder {
|
|
|
138
186
|
}
|
|
139
187
|
|
|
140
188
|
export const NosniaAudioRecorder = AudioRecorder.getInstance();
|
|
189
|
+
|
|
190
|
+
// Export AudioPlayer
|
|
191
|
+
export {
|
|
192
|
+
NosniaAudioPlayer,
|
|
193
|
+
type PlayOptions,
|
|
194
|
+
type PlayerStatus,
|
|
195
|
+
type PlaybackProgressCallback,
|
|
196
|
+
type PlaybackCompleteCallback,
|
|
197
|
+
} from './AudioPlayer';
|