@symbiote-native/audio 0.1.2 → 0.1.4
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 +96 -52
- package/build/angular/index.d.ts +8 -0
- package/build/angular/index.js +8 -3
- package/build/angular/inject-audio-player-status.d.ts +4 -0
- package/build/angular/inject-audio-player-status.js +4 -0
- package/build/angular/inject-audio-player.d.ts +4 -0
- package/build/angular/inject-audio-player.js +8 -0
- package/build/angular/inject-audio-playlist-status.d.ts +3 -0
- package/build/angular/inject-audio-playlist-status.js +4 -0
- package/build/angular/inject-audio-playlist.d.ts +5 -0
- package/build/angular/inject-audio-playlist.js +7 -0
- package/build/angular/inject-audio-recorder-state.d.ts +5 -0
- package/build/angular/inject-audio-recorder-state.js +10 -0
- package/build/angular/inject-audio-recorder.d.ts +5 -0
- package/build/angular/inject-audio-recorder.js +13 -0
- package/build/angular/inject-audio-sample-listener.d.ts +4 -0
- package/build/angular/inject-audio-sample-listener.js +7 -0
- package/build/angular/inject-audio-stream.d.ts +4 -0
- package/build/angular/inject-audio-stream.js +17 -0
- package/build/core/audio-module.js +1 -1
- package/build/core/audio-player-controller.d.ts +7 -0
- package/build/core/audio-player-controller.js +10 -0
- package/build/core/audio-player.js +16 -4
- package/build/core/audio-playlist-controller.d.ts +4 -0
- package/build/core/audio-playlist-controller.js +5 -0
- package/build/core/audio-recorder-controller.d.ts +4 -0
- package/build/core/audio-recorder-controller.js +5 -0
- package/build/core/audio-recorder-polling.d.ts +5 -0
- package/build/core/audio-recorder-polling.js +10 -0
- package/build/core/audio-recorder-state.d.ts +2 -0
- package/build/core/audio-recorder-state.js +18 -0
- package/build/core/audio-recorder-status.d.ts +8 -0
- package/build/core/audio-recorder-status.js +6 -0
- package/build/core/audio-recorder.d.ts +2 -0
- package/build/core/audio-recorder.js +4 -0
- package/build/core/audio-sample-listener.d.ts +11 -0
- package/build/core/audio-sample-listener.js +9 -0
- package/build/core/audio-stream-controller.d.ts +4 -0
- package/build/core/audio-stream-controller.js +5 -0
- package/build/core/audio-stream-hooks.d.ts +8 -0
- package/build/core/audio-stream-hooks.js +13 -0
- package/build/core/audio-stream-lifecycle.d.ts +3 -0
- package/build/core/audio-stream-lifecycle.js +9 -0
- package/build/core/audio-stream-subscription.d.ts +10 -0
- package/build/core/audio-stream-subscription.js +12 -0
- package/build/core/audio-stream.d.ts +9 -10
- package/build/core/audio-stream.js +1 -9
- package/build/core/index.d.ts +14 -2
- package/build/core/index.js +9 -1
- package/build/core/json-keyed-resource-controller.d.ts +1 -0
- package/build/core/json-keyed-resource-controller.js +1 -0
- package/build/core/resolve-source.d.ts +2 -7
- package/build/core/resolve-source.js +69 -15
- package/build/core/subscribe-single-event.d.ts +5 -0
- package/build/core/subscribe-single-event.js +8 -0
- package/build/core/types.d.ts +11 -5
- package/build/react/index.d.ts +9 -0
- package/build/react/index.js +9 -0
- package/build/react/use-audio-player-status.d.ts +4 -0
- package/build/react/use-audio-player-status.js +4 -0
- package/build/react/use-audio-player.d.ts +3 -0
- package/build/react/use-audio-player.js +7 -0
- package/build/react/use-audio-playlist-status.d.ts +3 -0
- package/build/react/use-audio-playlist-status.js +4 -0
- package/build/react/use-audio-playlist.d.ts +4 -0
- package/build/react/use-audio-playlist.js +7 -0
- package/build/react/use-audio-recorder-state.d.ts +4 -0
- package/build/react/use-audio-recorder-state.js +9 -0
- package/build/react/use-audio-recorder.d.ts +4 -0
- package/build/react/use-audio-recorder.js +11 -0
- package/build/react/use-audio-sample-listener.d.ts +4 -0
- package/build/react/use-audio-sample-listener.js +6 -0
- package/build/react/use-audio-stream.d.ts +3 -0
- package/build/react/use-audio-stream.js +14 -0
- package/build/solid/index.d.ts +9 -0
- package/build/solid/index.js +9 -0
- package/build/solid/use-audio-player-status.d.ts +4 -0
- package/build/solid/use-audio-player-status.js +4 -0
- package/build/solid/use-audio-player.d.ts +5 -0
- package/build/solid/use-audio-player.js +7 -0
- package/build/solid/use-audio-playlist-status.d.ts +3 -0
- package/build/solid/use-audio-playlist-status.js +4 -0
- package/build/solid/use-audio-playlist.d.ts +5 -0
- package/build/solid/use-audio-playlist.js +7 -0
- package/build/solid/use-audio-recorder-state.d.ts +5 -0
- package/build/solid/use-audio-recorder-state.js +9 -0
- package/build/solid/use-audio-recorder.d.ts +5 -0
- package/build/solid/use-audio-recorder.js +13 -0
- package/build/solid/use-audio-sample-listener.d.ts +4 -0
- package/build/solid/use-audio-sample-listener.js +8 -0
- package/build/solid/use-audio-stream.d.ts +4 -0
- package/build/solid/use-audio-stream.js +16 -0
- package/build/svelte/index.d.ts +9 -0
- package/build/svelte/index.js +9 -0
- package/build/svelte/use-audio-player-status.svelte.d.ts +6 -0
- package/build/svelte/use-audio-player-status.svelte.js +4 -0
- package/build/svelte/use-audio-player.svelte.d.ts +6 -0
- package/build/svelte/use-audio-player.svelte.js +8 -0
- package/build/svelte/use-audio-playlist-status.svelte.d.ts +5 -0
- package/build/svelte/use-audio-playlist-status.svelte.js +4 -0
- package/build/svelte/use-audio-playlist.svelte.d.ts +6 -0
- package/build/svelte/use-audio-playlist.svelte.js +8 -0
- package/build/svelte/use-audio-recorder-state.svelte.d.ts +7 -0
- package/build/svelte/use-audio-recorder-state.svelte.js +14 -0
- package/build/svelte/use-audio-recorder.svelte.d.ts +6 -0
- package/build/svelte/use-audio-recorder.svelte.js +11 -0
- package/build/svelte/use-audio-sample-listener.svelte.d.ts +4 -0
- package/build/svelte/use-audio-sample-listener.svelte.js +5 -0
- package/build/svelte/use-audio-stream.svelte.d.ts +4 -0
- package/build/svelte/use-audio-stream.svelte.js +29 -0
- package/build/vue/index.d.ts +9 -0
- package/build/vue/index.js +9 -0
- package/build/vue/use-audio-player-status.d.ts +4 -0
- package/build/vue/use-audio-player-status.js +4 -0
- package/build/vue/use-audio-player.d.ts +5 -0
- package/build/vue/use-audio-player.js +8 -0
- package/build/vue/use-audio-playlist-status.d.ts +3 -0
- package/build/vue/use-audio-playlist-status.js +4 -0
- package/build/vue/use-audio-playlist.d.ts +5 -0
- package/build/vue/use-audio-playlist.js +8 -0
- package/build/vue/use-audio-recorder-state.d.ts +5 -0
- package/build/vue/use-audio-recorder-state.js +12 -0
- package/build/vue/use-audio-recorder.d.ts +5 -0
- package/build/vue/use-audio-recorder.js +11 -0
- package/build/vue/use-audio-sample-listener.d.ts +4 -0
- package/build/vue/use-audio-sample-listener.js +11 -0
- package/build/vue/use-audio-stream.d.ts +4 -0
- package/build/vue/use-audio-stream.js +18 -0
- package/build-ngc/angular/index.d.ts +8 -0
- package/build-ngc/angular/index.js +8 -3
- package/build-ngc/angular/index.js.map +1 -1
- package/build-ngc/angular/inject-audio-player-status.d.ts +4 -0
- package/build-ngc/angular/inject-audio-player-status.js +5 -0
- package/build-ngc/angular/inject-audio-player-status.js.map +1 -0
- package/build-ngc/angular/inject-audio-player.d.ts +4 -0
- package/build-ngc/angular/inject-audio-player.js +9 -0
- package/build-ngc/angular/inject-audio-player.js.map +1 -0
- package/build-ngc/angular/inject-audio-playlist-status.d.ts +3 -0
- package/build-ngc/angular/inject-audio-playlist-status.js +5 -0
- package/build-ngc/angular/inject-audio-playlist-status.js.map +1 -0
- package/build-ngc/angular/inject-audio-playlist.d.ts +5 -0
- package/build-ngc/angular/inject-audio-playlist.js +8 -0
- package/build-ngc/angular/inject-audio-playlist.js.map +1 -0
- package/build-ngc/angular/inject-audio-recorder-state.d.ts +5 -0
- package/build-ngc/angular/inject-audio-recorder-state.js +12 -0
- package/build-ngc/angular/inject-audio-recorder-state.js.map +1 -0
- package/build-ngc/angular/inject-audio-recorder.d.ts +5 -0
- package/build-ngc/angular/inject-audio-recorder.js +14 -0
- package/build-ngc/angular/inject-audio-recorder.js.map +1 -0
- package/build-ngc/angular/inject-audio-sample-listener.d.ts +4 -0
- package/build-ngc/angular/inject-audio-sample-listener.js +8 -0
- package/build-ngc/angular/inject-audio-sample-listener.js.map +1 -0
- package/build-ngc/angular/inject-audio-stream.d.ts +4 -0
- package/build-ngc/angular/inject-audio-stream.js +18 -0
- package/build-ngc/angular/inject-audio-stream.js.map +1 -0
- package/build-ngc/core/audio-module.js +1 -1
- package/build-ngc/core/audio-module.js.map +1 -1
- package/build-ngc/core/audio-player-controller.d.ts +7 -0
- package/build-ngc/core/audio-player-controller.js +11 -0
- package/build-ngc/core/audio-player-controller.js.map +1 -0
- package/build-ngc/core/audio-player.js +16 -4
- package/build-ngc/core/audio-player.js.map +1 -1
- package/build-ngc/core/audio-playlist-controller.d.ts +4 -0
- package/build-ngc/core/audio-playlist-controller.js +6 -0
- package/build-ngc/core/audio-playlist-controller.js.map +1 -0
- package/build-ngc/core/audio-recorder-controller.d.ts +4 -0
- package/build-ngc/core/audio-recorder-controller.js +6 -0
- package/build-ngc/core/audio-recorder-controller.js.map +1 -0
- package/build-ngc/core/audio-recorder-polling.d.ts +5 -0
- package/build-ngc/core/audio-recorder-polling.js +11 -0
- package/build-ngc/core/audio-recorder-polling.js.map +1 -0
- package/build-ngc/core/audio-recorder-state.d.ts +2 -0
- package/build-ngc/core/audio-recorder-state.js +19 -0
- package/build-ngc/core/audio-recorder-state.js.map +1 -0
- package/build-ngc/core/audio-recorder-status.d.ts +8 -0
- package/build-ngc/core/audio-recorder-status.js +7 -0
- package/build-ngc/core/audio-recorder-status.js.map +1 -0
- package/build-ngc/core/audio-recorder.d.ts +2 -0
- package/build-ngc/core/audio-recorder.js +4 -0
- package/build-ngc/core/audio-recorder.js.map +1 -1
- package/build-ngc/core/audio-sample-listener.d.ts +11 -0
- package/build-ngc/core/audio-sample-listener.js +10 -0
- package/build-ngc/core/audio-sample-listener.js.map +1 -0
- package/build-ngc/core/audio-stream-controller.d.ts +4 -0
- package/build-ngc/core/audio-stream-controller.js +6 -0
- package/build-ngc/core/audio-stream-controller.js.map +1 -0
- package/build-ngc/core/audio-stream-hooks.d.ts +8 -0
- package/build-ngc/core/audio-stream-hooks.js +14 -0
- package/build-ngc/core/audio-stream-hooks.js.map +1 -0
- package/build-ngc/core/audio-stream-lifecycle.d.ts +3 -0
- package/build-ngc/core/audio-stream-lifecycle.js +10 -0
- package/build-ngc/core/audio-stream-lifecycle.js.map +1 -0
- package/build-ngc/core/audio-stream-subscription.d.ts +10 -0
- package/build-ngc/core/audio-stream-subscription.js +13 -0
- package/build-ngc/core/audio-stream-subscription.js.map +1 -0
- package/build-ngc/core/audio-stream.d.ts +9 -10
- package/build-ngc/core/audio-stream.js +1 -9
- package/build-ngc/core/audio-stream.js.map +1 -1
- package/build-ngc/core/index.d.ts +14 -2
- package/build-ngc/core/index.js +9 -1
- package/build-ngc/core/index.js.map +1 -1
- package/build-ngc/core/json-keyed-resource-controller.d.ts +1 -0
- package/build-ngc/core/json-keyed-resource-controller.js +2 -0
- package/build-ngc/core/json-keyed-resource-controller.js.map +1 -0
- package/build-ngc/core/resolve-source.d.ts +2 -7
- package/build-ngc/core/resolve-source.js +69 -15
- package/build-ngc/core/resolve-source.js.map +1 -1
- package/build-ngc/core/subscribe-single-event.d.ts +5 -0
- package/build-ngc/core/subscribe-single-event.js +9 -0
- package/build-ngc/core/subscribe-single-event.js.map +1 -0
- package/build-ngc/core/types.d.ts +11 -5
- package/build-ngc/core/types.js.map +1 -1
- package/package.json +24 -23
- package/src/angular/index.ts +8 -3
- package/src/angular/inject-audio-player-status.ts +11 -0
- package/src/angular/inject-audio-player.ts +17 -0
- package/src/angular/inject-audio-playlist-status.ts +11 -0
- package/src/angular/inject-audio-playlist.ts +16 -0
- package/src/angular/inject-audio-recorder-state.ts +21 -0
- package/src/angular/inject-audio-recorder.ts +24 -0
- package/src/angular/inject-audio-sample-listener.ts +13 -0
- package/src/angular/inject-audio-stream.ts +41 -0
- package/src/core/audio-module.ts +2 -1
- package/src/core/audio-player-controller.ts +25 -0
- package/src/core/audio-player.ts +17 -4
- package/src/core/audio-playlist-controller.ts +14 -0
- package/src/core/audio-recorder-controller.ts +14 -0
- package/src/core/audio-recorder-polling.ts +20 -0
- package/src/core/audio-recorder-state.ts +26 -0
- package/src/core/audio-recorder-status.ts +22 -0
- package/src/core/audio-recorder.ts +5 -0
- package/src/core/audio-sample-listener.ts +23 -0
- package/src/core/audio-stream-controller.ts +14 -0
- package/src/core/audio-stream-hooks.ts +31 -0
- package/src/core/audio-stream-lifecycle.ts +19 -0
- package/src/core/audio-stream-subscription.ts +28 -0
- package/src/core/audio-stream.ts +11 -10
- package/src/core/index.ts +20 -1
- package/src/core/json-keyed-resource-controller.ts +1 -0
- package/src/core/resolve-source.ts +80 -18
- package/src/core/subscribe-single-event.ts +17 -0
- package/src/core/types.ts +13 -14
- package/src/react/index.ts +9 -0
- package/src/react/use-audio-player-status.ts +11 -0
- package/src/react/use-audio-player.ts +14 -0
- package/src/react/use-audio-playlist-status.ts +11 -0
- package/src/react/use-audio-playlist.ts +13 -0
- package/src/react/use-audio-recorder-state.ts +23 -0
- package/src/react/use-audio-recorder.ts +23 -0
- package/src/react/use-audio-sample-listener.ts +15 -0
- package/src/react/use-audio-stream.ts +39 -0
- package/src/solid/index.ts +9 -0
- package/src/solid/use-audio-player-status.ts +11 -0
- package/src/solid/use-audio-player.ts +15 -0
- package/src/solid/use-audio-playlist-status.ts +11 -0
- package/src/solid/use-audio-playlist.ts +14 -0
- package/src/solid/use-audio-recorder-state.ts +18 -0
- package/src/solid/use-audio-recorder.ts +22 -0
- package/src/solid/use-audio-sample-listener.ts +14 -0
- package/src/solid/use-audio-stream.ts +34 -0
- package/src/svelte/index.ts +9 -0
- package/src/svelte/svelte-ambient.d.ts +3 -0
- package/src/svelte/svelte-compile.test-helper.ts +7 -0
- package/src/svelte/use-audio-player-status.svelte.ts +11 -0
- package/src/svelte/use-audio-player.svelte.ts +20 -0
- package/src/svelte/use-audio-playlist-status.svelte.ts +11 -0
- package/src/svelte/use-audio-playlist.svelte.ts +19 -0
- package/src/svelte/use-audio-recorder-state.svelte.ts +29 -0
- package/src/svelte/use-audio-recorder.svelte.ts +25 -0
- package/src/svelte/use-audio-sample-listener.svelte.ts +11 -0
- package/src/svelte/use-audio-stream.svelte.ts +44 -0
- package/src/vue/index.ts +9 -0
- package/src/vue/use-audio-player-status.ts +11 -0
- package/src/vue/use-audio-player.ts +19 -0
- package/src/vue/use-audio-playlist-status.ts +11 -0
- package/src/vue/use-audio-playlist.ts +15 -0
- package/src/vue/use-audio-recorder-state.ts +21 -0
- package/src/vue/use-audio-recorder.ts +30 -0
- package/src/vue/use-audio-sample-listener.ts +22 -0
- package/src/vue/use-audio-stream.ts +40 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Shared shape behind `subscribeRecordingStatus`/`subscribeAudioStreamBuffer`: one optional
|
|
2
|
+
// listener over one named event, unsubscribed via the returned cleanup
|
|
3
|
+
export function subscribeSingleEvent(source, event, listener) {
|
|
4
|
+
const subscription = source.addListener(event, payload => {
|
|
5
|
+
listener?.(payload);
|
|
6
|
+
});
|
|
7
|
+
return () => subscription.remove();
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=subscribe-single-event.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscribe-single-event.js","sourceRoot":"","sources":["../../src/core/subscribe-single-event.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,uEAAuE;AACvE,MAAM,UAAU,oBAAoB,CAClC,MAKC,EACD,KAAa,EACb,QAAmD;IAEnD,MAAM,YAAY,GAAG,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE;QACvD,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC;IACtB,CAAC,CAAC,CAAC;IACH,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;AACrC,CAAC"}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
+
import type { Asset } from '@symbiote-native/asset';
|
|
1
2
|
import type { AudioQuality, IOSOutputFormat } from './recording-presets';
|
|
2
3
|
/** Audio source information returned from native when reading sources from a queue. */
|
|
3
4
|
export type IAudioSourceInfo = {
|
|
4
5
|
uri?: string;
|
|
5
6
|
name?: string;
|
|
6
7
|
};
|
|
7
|
-
/**
|
|
8
|
-
|
|
9
|
-
* id `require('./song.mp3')` produces — resolved via `resolveSource`/`resolveSources`.
|
|
10
|
-
*/
|
|
11
|
-
export type IAudioSource = string | number | null | {
|
|
8
|
+
/** A URI, a `require()` module id, an `Asset`, or a source object — see resolve-source.ts. */
|
|
9
|
+
export type IAudioSource = string | number | Asset | null | {
|
|
12
10
|
uri?: string;
|
|
11
|
+
/** id of a local asset from `require()`; ignored if `uri` is set. */
|
|
12
|
+
assetId?: number;
|
|
13
13
|
headers?: Record<string, string>;
|
|
14
14
|
name?: string;
|
|
15
15
|
};
|
|
@@ -31,7 +31,11 @@ export type IAudioPlayerOptions = {
|
|
|
31
31
|
* @default 0
|
|
32
32
|
*/
|
|
33
33
|
preferredForwardBufferDuration?: number;
|
|
34
|
+
/** Downloads the source via `Asset` before the native player loads it. @default false */
|
|
35
|
+
downloadFirst?: boolean;
|
|
34
36
|
};
|
|
37
|
+
/** @deprecated Use `IAudioPlayerOptions` instead */
|
|
38
|
+
export type IAudioLoadOptions = IAudioPlayerOptions;
|
|
35
39
|
export type IPreloadOptions = {
|
|
36
40
|
/** @default 10 */
|
|
37
41
|
preferredForwardBufferDuration?: number;
|
|
@@ -136,6 +140,8 @@ export type IAudioMode = {
|
|
|
136
140
|
playsInSilentMode: boolean;
|
|
137
141
|
/** @default 'mixWithOthers' */
|
|
138
142
|
interruptionMode: IInterruptionMode;
|
|
143
|
+
/** @platform android @deprecated Use `interruptionMode`, which now works on both platforms */
|
|
144
|
+
interruptionModeAndroid?: IInterruptionMode;
|
|
139
145
|
/** @default false @platform ios */
|
|
140
146
|
allowsRecording: boolean;
|
|
141
147
|
/** @default false */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAiRA,8FAA8F;AAC9F,MAAM,CAAC,MAAM,sBAAsB,GAAG,sBAAsB,CAAC;AAC7D,MAAM,CAAC,MAAM,mBAAmB,GAAG,mBAAmB,CAAC;AACvD,MAAM,CAAC,MAAM,uBAAuB,GAAG,uBAAuB,CAAC;AAC/D,MAAM,CAAC,MAAM,sBAAsB,GAAG,sBAAsB,CAAC;AAC7D,MAAM,CAAC,MAAM,aAAa,GAAG,cAAc,CAAC;AAC5C,MAAM,CAAC,MAAM,mBAAmB,GAAG,mBAAmB,CAAC;AACvD,MAAM,CAAC,MAAM,mBAAmB,GAAG,mBAAmB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symbiote-native/audio",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "expo-audio wrapped for SymbioteNative — one framework-agnostic core, built once and reachable from the React, Vue, Svelte, Solid, and Angular adapters. AudioPlayer / AudioRecorder / AudioPlaylist / AudioStream shared-object classes, audio-session config, and recording permissions.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -35,20 +35,20 @@
|
|
|
35
35
|
"default": "./build/core/index.js"
|
|
36
36
|
},
|
|
37
37
|
"./vue": {
|
|
38
|
-
"types": "./build/
|
|
39
|
-
"default": "./build/
|
|
38
|
+
"types": "./build/vue/index.d.ts",
|
|
39
|
+
"default": "./build/vue/index.js"
|
|
40
40
|
},
|
|
41
41
|
"./react": {
|
|
42
|
-
"types": "./build/
|
|
43
|
-
"default": "./build/
|
|
42
|
+
"types": "./build/react/index.d.ts",
|
|
43
|
+
"default": "./build/react/index.js"
|
|
44
44
|
},
|
|
45
45
|
"./svelte": {
|
|
46
|
-
"types": "./build/
|
|
47
|
-
"default": "./build/
|
|
46
|
+
"types": "./build/svelte/index.d.ts",
|
|
47
|
+
"default": "./build/svelte/index.js"
|
|
48
48
|
},
|
|
49
49
|
"./solid": {
|
|
50
|
-
"types": "./build/
|
|
51
|
-
"default": "./build/
|
|
50
|
+
"types": "./build/solid/index.d.ts",
|
|
51
|
+
"default": "./build/solid/index.js"
|
|
52
52
|
},
|
|
53
53
|
"./angular": {
|
|
54
54
|
"types": "./build-ngc/angular/index.d.ts",
|
|
@@ -70,7 +70,8 @@
|
|
|
70
70
|
},
|
|
71
71
|
"dependencies": {
|
|
72
72
|
"expo-audio": "57.0.4",
|
|
73
|
-
"expo-modules-core": "57.0.
|
|
73
|
+
"expo-modules-core": "57.0.20",
|
|
74
|
+
"@symbiote-native/asset": "0.1.2"
|
|
74
75
|
},
|
|
75
76
|
"peerDependencies": {
|
|
76
77
|
"@angular/core": ">=20",
|
|
@@ -80,12 +81,12 @@
|
|
|
80
81
|
"solid-js": ">=1.9.0",
|
|
81
82
|
"svelte": ">=5.56.0",
|
|
82
83
|
"vue": ">=3.5.0",
|
|
83
|
-
"@symbiote-native/angular": "^3.
|
|
84
|
-
"@symbiote-native/engine": "^1.
|
|
85
|
-
"@symbiote-native/react": "^3.0
|
|
86
|
-
"@symbiote-native/solid": "^3.0
|
|
87
|
-
"@symbiote-native/svelte": "^3.0
|
|
88
|
-
"@symbiote-native/vue": "^3.0
|
|
84
|
+
"@symbiote-native/angular": "^3.3.0",
|
|
85
|
+
"@symbiote-native/engine": "^1.6.0",
|
|
86
|
+
"@symbiote-native/react": "^3.3.0",
|
|
87
|
+
"@symbiote-native/solid": "^3.2.0",
|
|
88
|
+
"@symbiote-native/svelte": "^3.2.0",
|
|
89
|
+
"@symbiote-native/vue": "^3.3.0"
|
|
89
90
|
},
|
|
90
91
|
"peerDependenciesMeta": {
|
|
91
92
|
"@symbiote-native/angular": {
|
|
@@ -133,13 +134,13 @@
|
|
|
133
134
|
"solid-js": "^1.9.14",
|
|
134
135
|
"svelte": "^5.56.0",
|
|
135
136
|
"typescript": "~6.0.0",
|
|
136
|
-
"@symbiote-native/angular": "3.
|
|
137
|
-
"@symbiote-native/engine": "1.
|
|
138
|
-
"@symbiote-native/react": "3.0
|
|
139
|
-
"@symbiote-native/solid": "3.0
|
|
140
|
-
"@symbiote-native/svelte": "3.0
|
|
141
|
-
"@symbiote-native/test-utils": "0.4.
|
|
142
|
-
"@symbiote-native/vue": "3.0
|
|
137
|
+
"@symbiote-native/angular": "3.3.0",
|
|
138
|
+
"@symbiote-native/engine": "1.6.0",
|
|
139
|
+
"@symbiote-native/react": "3.3.0",
|
|
140
|
+
"@symbiote-native/solid": "3.2.0",
|
|
141
|
+
"@symbiote-native/svelte": "3.2.0",
|
|
142
|
+
"@symbiote-native/test-utils": "0.4.7",
|
|
143
|
+
"@symbiote-native/vue": "3.3.0"
|
|
143
144
|
},
|
|
144
145
|
"scripts": {
|
|
145
146
|
"typecheck": "tsc --build",
|
package/src/angular/index.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
// @symbiote-native/audio/angular: the Angular entry over the framework-agnostic core. Same
|
|
2
|
-
// reasoning as the React/Vue entries — every export here is a plain class/function with no
|
|
3
|
-
// framework-specific lifecycle to wrap, so this is a plain re-export.
|
|
4
1
|
export * from '../core';
|
|
2
|
+
export { injectAudioPlayer } from './inject-audio-player';
|
|
3
|
+
export { injectAudioPlayerStatus } from './inject-audio-player-status';
|
|
4
|
+
export { injectAudioSampleListener } from './inject-audio-sample-listener';
|
|
5
|
+
export { injectAudioPlaylist } from './inject-audio-playlist';
|
|
6
|
+
export { injectAudioPlaylistStatus } from './inject-audio-playlist-status';
|
|
7
|
+
export { injectAudioRecorder } from './inject-audio-recorder';
|
|
8
|
+
export { injectAudioRecorderState } from './inject-audio-recorder-state';
|
|
9
|
+
export { injectAudioStream } from './inject-audio-stream';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createEventValueHook } from '@symbiote-native/angular';
|
|
2
|
+
import { PLAYBACK_STATUS_UPDATE } from '../core/types';
|
|
3
|
+
import type { AudioPlayer } from '../core';
|
|
4
|
+
import type { IAudioStatus } from '../core';
|
|
5
|
+
|
|
6
|
+
/** Angular twin of `expo-audio`'s `useAudioPlayerStatus` */
|
|
7
|
+
export const injectAudioPlayerStatus = createEventValueHook<
|
|
8
|
+
AudioPlayer,
|
|
9
|
+
IAudioStatus,
|
|
10
|
+
typeof PLAYBACK_STATUS_UPDATE
|
|
11
|
+
>(PLAYBACK_STATUS_UPDATE, player => player.currentStatus);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Angular twin of `useAudioPlayer`, `injectX` shape matching
|
|
2
|
+
// `@symbiote-native/navigation`'s `injectLinkingIntegration`
|
|
3
|
+
|
|
4
|
+
import type { Signal } from '@angular/core';
|
|
5
|
+
import { createResourceHook } from '@symbiote-native/angular';
|
|
6
|
+
import { createAudioPlayerController } from '../core/audio-player-controller';
|
|
7
|
+
import type { AudioPlayer } from '../core';
|
|
8
|
+
import type { IAudioPlayerOptions, IAudioSource } from '../core';
|
|
9
|
+
|
|
10
|
+
const injectPlayerResource = createResourceHook(createAudioPlayerController);
|
|
11
|
+
|
|
12
|
+
export function injectAudioPlayer(
|
|
13
|
+
source: () => IAudioSource,
|
|
14
|
+
options: () => IAudioPlayerOptions = () => ({}),
|
|
15
|
+
): Signal<AudioPlayer> {
|
|
16
|
+
return injectPlayerResource(() => [source(), options()]);
|
|
17
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createEventValueHook } from '@symbiote-native/angular';
|
|
2
|
+
import { PLAYLIST_STATUS_UPDATE } from '../core/types';
|
|
3
|
+
import type { AudioPlaylist } from '../core';
|
|
4
|
+
import type { IAudioPlaylistStatus } from '../core';
|
|
5
|
+
|
|
6
|
+
/** Angular twin of `expo-audio`'s `useAudioPlaylistStatus` */
|
|
7
|
+
export const injectAudioPlaylistStatus = createEventValueHook<
|
|
8
|
+
AudioPlaylist,
|
|
9
|
+
IAudioPlaylistStatus,
|
|
10
|
+
typeof PLAYLIST_STATUS_UPDATE
|
|
11
|
+
>(PLAYLIST_STATUS_UPDATE, playlist => playlist.currentStatus);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Signal } from '@angular/core';
|
|
2
|
+
import { createResourceHook } from '@symbiote-native/angular';
|
|
3
|
+
import { createAudioPlaylistController } from '../core/audio-playlist-controller';
|
|
4
|
+
import type { AudioPlaylist } from '../core';
|
|
5
|
+
import type { IAudioPlaylistOptions } from '../core';
|
|
6
|
+
|
|
7
|
+
const injectPlaylistResource = createResourceHook(
|
|
8
|
+
createAudioPlaylistController,
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
/** Angular twin of `expo-audio`'s `useAudioPlaylist` */
|
|
12
|
+
export function injectAudioPlaylist(
|
|
13
|
+
getOptions: () => IAudioPlaylistOptions,
|
|
14
|
+
): Signal<AudioPlaylist> {
|
|
15
|
+
return injectPlaylistResource(() => [getOptions()]);
|
|
16
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { DestroyRef, inject, signal, type Signal } from '@angular/core';
|
|
2
|
+
import { pollRecorderState } from '../core/audio-recorder-polling';
|
|
3
|
+
import type { AudioRecorder } from '../core';
|
|
4
|
+
import type { IRecorderState } from '../core';
|
|
5
|
+
|
|
6
|
+
const DEFAULT_POLL_INTERVAL_MS = 500;
|
|
7
|
+
|
|
8
|
+
/** Angular twin of `expo-audio`'s `useAudioRecorderState` */
|
|
9
|
+
export function injectAudioRecorderState(
|
|
10
|
+
recorder: AudioRecorder,
|
|
11
|
+
interval: number = DEFAULT_POLL_INTERVAL_MS,
|
|
12
|
+
): Signal<IRecorderState> {
|
|
13
|
+
const state = signal(recorder.getStatus());
|
|
14
|
+
|
|
15
|
+
const stop = pollRecorderState(recorder, interval, updater =>
|
|
16
|
+
state.set(updater(state())),
|
|
17
|
+
);
|
|
18
|
+
inject(DestroyRef).onDestroy(stop);
|
|
19
|
+
|
|
20
|
+
return state.asReadonly();
|
|
21
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { effect, type Signal } from '@angular/core';
|
|
2
|
+
import { createResourceHook } from '@symbiote-native/angular';
|
|
3
|
+
import { createAudioRecorderController } from '../core/audio-recorder-controller';
|
|
4
|
+
import { subscribeRecordingStatus } from '../core/audio-recorder-status';
|
|
5
|
+
import type { AudioRecorder } from '../core';
|
|
6
|
+
import type { IRecordingOptions, IRecordingStatus } from '../core';
|
|
7
|
+
|
|
8
|
+
const injectRecorderResource = createResourceHook(
|
|
9
|
+
createAudioRecorderController,
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
/** Angular twin of `expo-audio`'s `useAudioRecorder` */
|
|
13
|
+
export function injectAudioRecorder(
|
|
14
|
+
getOptions: () => IRecordingOptions,
|
|
15
|
+
statusListener?: (status: IRecordingStatus) => void,
|
|
16
|
+
): Signal<AudioRecorder> {
|
|
17
|
+
const recorder = injectRecorderResource(() => [getOptions()]);
|
|
18
|
+
|
|
19
|
+
effect(onCleanup => {
|
|
20
|
+
onCleanup(subscribeRecordingStatus(recorder(), statusListener));
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
return recorder;
|
|
24
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { DestroyRef, inject } from '@angular/core';
|
|
2
|
+
import { subscribeAudioSampleListener } from '../core/audio-sample-listener';
|
|
3
|
+
import type { IAudioSamplePlayer } from '../core/audio-sample-listener';
|
|
4
|
+
import type { IAudioSample } from '../core/types';
|
|
5
|
+
|
|
6
|
+
/** Angular twin of `expo-audio`'s `useAudioSampleListener` */
|
|
7
|
+
export function injectAudioSampleListener(
|
|
8
|
+
player: IAudioSamplePlayer,
|
|
9
|
+
listener: (data: IAudioSample) => void,
|
|
10
|
+
): void {
|
|
11
|
+
const unsubscribe = subscribeAudioSampleListener(player, listener);
|
|
12
|
+
inject(DestroyRef).onDestroy(unsubscribe);
|
|
13
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import {
|
|
2
|
+
computed,
|
|
3
|
+
DestroyRef,
|
|
4
|
+
effect,
|
|
5
|
+
inject,
|
|
6
|
+
type Signal,
|
|
7
|
+
} from '@angular/core';
|
|
8
|
+
import {
|
|
9
|
+
createResourceHook,
|
|
10
|
+
createEventValueHook,
|
|
11
|
+
} from '@symbiote-native/angular';
|
|
12
|
+
import { createAudioStreamHooks } from '../core/audio-stream-hooks';
|
|
13
|
+
import { toAudioStreamKey } from '../core/audio-stream-subscription';
|
|
14
|
+
import { runAudioStreamBufferEffect } from '../core/audio-stream-lifecycle';
|
|
15
|
+
import type { IAudioStreamResult, IUseAudioStreamOptions } from '../core';
|
|
16
|
+
|
|
17
|
+
const { useStreamResource, useStreamStatus } = createAudioStreamHooks(
|
|
18
|
+
createResourceHook,
|
|
19
|
+
createEventValueHook,
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
/** Angular twin of `expo-audio`'s `useAudioStream` */
|
|
23
|
+
export function injectAudioStream(
|
|
24
|
+
getOptions: () => IUseAudioStreamOptions,
|
|
25
|
+
): Signal<IAudioStreamResult> {
|
|
26
|
+
const destroyRef = inject(DestroyRef);
|
|
27
|
+
const stream = useStreamResource(() => [toAudioStreamKey(getOptions())]);
|
|
28
|
+
const status = useStreamStatus(stream);
|
|
29
|
+
|
|
30
|
+
runAudioStreamBufferEffect(
|
|
31
|
+
stream,
|
|
32
|
+
() => getOptions().onBuffer,
|
|
33
|
+
effect,
|
|
34
|
+
cleanup => destroyRef.onDestroy(cleanup),
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
return computed(() => ({
|
|
38
|
+
stream: stream(),
|
|
39
|
+
isStreaming: status().isStreaming,
|
|
40
|
+
}));
|
|
41
|
+
}
|
package/src/core/audio-module.ts
CHANGED
|
@@ -18,7 +18,8 @@ export async function setAudioModeAsync(
|
|
|
18
18
|
: {
|
|
19
19
|
shouldPlayInBackground: mode.shouldPlayInBackground,
|
|
20
20
|
shouldRouteThroughEarpiece: mode.shouldRouteThroughEarpiece,
|
|
21
|
-
interruptionMode:
|
|
21
|
+
interruptionMode:
|
|
22
|
+
mode.interruptionMode ?? mode.interruptionModeAndroid,
|
|
22
23
|
allowsBackgroundRecording: mode.allowsBackgroundRecording,
|
|
23
24
|
playsInSilentMode: mode.playsInSilentMode,
|
|
24
25
|
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { createJsonKeyedResourceController } from './json-keyed-resource-controller';
|
|
2
|
+
import { createAudioPlayer, type AudioPlayer } from './audio-player';
|
|
3
|
+
import type { IAudioPlayerOptions, IAudioSource } from './types';
|
|
4
|
+
|
|
5
|
+
type IAudioPlayerKey = { source: IAudioSource; options: IAudioPlayerOptions };
|
|
6
|
+
|
|
7
|
+
export function createAudioPlayerController(): {
|
|
8
|
+
resolve: (source: IAudioSource, options: IAudioPlayerOptions) => AudioPlayer;
|
|
9
|
+
flushDispose: () => void;
|
|
10
|
+
dispose: () => void;
|
|
11
|
+
} {
|
|
12
|
+
const controller = createJsonKeyedResourceController<
|
|
13
|
+
IAudioPlayerKey,
|
|
14
|
+
AudioPlayer
|
|
15
|
+
>(
|
|
16
|
+
key => createAudioPlayer(key.source, key.options),
|
|
17
|
+
player => player.remove(),
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
resolve: (source, options) => controller.resolve({ source, options }),
|
|
22
|
+
flushDispose: controller.flushDispose,
|
|
23
|
+
dispose: controller.dispose,
|
|
24
|
+
};
|
|
25
|
+
}
|
package/src/core/audio-player.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Platform } from 'expo-modules-core';
|
|
2
2
|
import { expoAudio } from './native-module';
|
|
3
|
-
import { resolveSource } from './resolve-source';
|
|
3
|
+
import { resolveSource, resolveSourceWithDownload } from './resolve-source';
|
|
4
4
|
import type {
|
|
5
5
|
IAudioPlayerOptions,
|
|
6
6
|
IAudioSource,
|
|
@@ -40,14 +40,27 @@ export function createAudioPlayer(
|
|
|
40
40
|
): AudioPlayer {
|
|
41
41
|
const {
|
|
42
42
|
updateInterval = 500,
|
|
43
|
+
downloadFirst = false,
|
|
43
44
|
keepAudioSessionActive = false,
|
|
44
45
|
preferredForwardBufferDuration = 0,
|
|
45
46
|
} = options;
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
resolvedSource,
|
|
47
|
+
const player = new AudioPlayer(
|
|
48
|
+
downloadFirst ? null : resolveSource(source),
|
|
49
49
|
updateInterval,
|
|
50
50
|
keepAudioSessionActive,
|
|
51
51
|
preferredForwardBufferDuration,
|
|
52
52
|
);
|
|
53
|
+
|
|
54
|
+
if (downloadFirst && source) {
|
|
55
|
+
resolveSourceWithDownload(source)
|
|
56
|
+
.then(resolved => {
|
|
57
|
+
if (resolved) player.replace(resolved);
|
|
58
|
+
})
|
|
59
|
+
.catch(() => {
|
|
60
|
+
const fallback = resolveSource(source);
|
|
61
|
+
if (fallback) player.replace(fallback);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return player;
|
|
53
66
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { IResourceController } from '@symbiote-native/engine';
|
|
2
|
+
import { createJsonKeyedResourceController } from './json-keyed-resource-controller';
|
|
3
|
+
import { createAudioPlaylist, type AudioPlaylist } from './audio-playlist';
|
|
4
|
+
import type { IAudioPlaylistOptions } from './types';
|
|
5
|
+
|
|
6
|
+
export function createAudioPlaylistController(): IResourceController<
|
|
7
|
+
IAudioPlaylistOptions,
|
|
8
|
+
AudioPlaylist
|
|
9
|
+
> {
|
|
10
|
+
return createJsonKeyedResourceController<
|
|
11
|
+
IAudioPlaylistOptions,
|
|
12
|
+
AudioPlaylist
|
|
13
|
+
>(createAudioPlaylist, playlist => playlist.destroy());
|
|
14
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { IResourceController } from '@symbiote-native/engine';
|
|
2
|
+
import { createJsonKeyedResourceController } from './json-keyed-resource-controller';
|
|
3
|
+
import { createAudioRecorder, type AudioRecorder } from './audio-recorder';
|
|
4
|
+
import type { IRecordingOptions } from './types';
|
|
5
|
+
|
|
6
|
+
export function createAudioRecorderController(): IResourceController<
|
|
7
|
+
IRecordingOptions,
|
|
8
|
+
AudioRecorder
|
|
9
|
+
> {
|
|
10
|
+
return createJsonKeyedResourceController<IRecordingOptions, AudioRecorder>(
|
|
11
|
+
createAudioRecorder,
|
|
12
|
+
recorder => recorder.release(),
|
|
13
|
+
);
|
|
14
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { shouldUpdateRecorderState } from './audio-recorder-state';
|
|
2
|
+
import type { IRecorderState } from './types';
|
|
3
|
+
|
|
4
|
+
export type IPollableRecorder = {
|
|
5
|
+
getStatus: () => IRecorderState;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
// Ported from `useAudioRecorderState`'s `setInterval` body; `update` matches every adapter's
|
|
9
|
+
// own state setter (`useState`, Solid's `createSignal`, a plain `(prev) => next` writer, ...)
|
|
10
|
+
export function pollRecorderState(
|
|
11
|
+
recorder: IPollableRecorder,
|
|
12
|
+
interval: number,
|
|
13
|
+
update: (updater: (prev: IRecorderState) => IRecorderState) => void,
|
|
14
|
+
): () => void {
|
|
15
|
+
const id = setInterval(() => {
|
|
16
|
+
const next = recorder.getStatus();
|
|
17
|
+
update(prev => (shouldUpdateRecorderState(prev, next) ? next : prev));
|
|
18
|
+
}, interval);
|
|
19
|
+
return () => clearInterval(id);
|
|
20
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { IRecorderState } from './types';
|
|
2
|
+
|
|
3
|
+
const METERING_EPSILON = 0.1;
|
|
4
|
+
const DURATION_EPSILON_MS = 50;
|
|
5
|
+
|
|
6
|
+
function meteringChanged(prev: IRecorderState, next: IRecorderState): boolean {
|
|
7
|
+
if ((prev.metering === undefined) !== (next.metering === undefined))
|
|
8
|
+
return true;
|
|
9
|
+
if (prev.metering === undefined || next.metering === undefined) return false;
|
|
10
|
+
return Math.abs(prev.metering - next.metering) > METERING_EPSILON;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Ported from `useAudioRecorderState`'s poll-diff `setState` body
|
|
14
|
+
export function shouldUpdateRecorderState(
|
|
15
|
+
prev: IRecorderState,
|
|
16
|
+
next: IRecorderState,
|
|
17
|
+
): boolean {
|
|
18
|
+
return (
|
|
19
|
+
prev.canRecord !== next.canRecord ||
|
|
20
|
+
prev.isRecording !== next.isRecording ||
|
|
21
|
+
prev.mediaServicesDidReset !== next.mediaServicesDidReset ||
|
|
22
|
+
prev.url !== next.url ||
|
|
23
|
+
Math.abs(prev.durationMillis - next.durationMillis) > DURATION_EPSILON_MS ||
|
|
24
|
+
meteringChanged(prev, next)
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { RECORDING_STATUS_UPDATE } from './types';
|
|
2
|
+
import { subscribeSingleEvent } from './subscribe-single-event';
|
|
3
|
+
import type { IRecordingStatus } from './types';
|
|
4
|
+
|
|
5
|
+
export type IStatusRecorder = {
|
|
6
|
+
addListener: (
|
|
7
|
+
event: typeof RECORDING_STATUS_UPDATE,
|
|
8
|
+
listener: (status: IRecordingStatus) => void,
|
|
9
|
+
) => { remove: () => void };
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// Ported from `useAudioRecorder`'s status-listener `useEffect` body
|
|
13
|
+
export function subscribeRecordingStatus(
|
|
14
|
+
recorder: IStatusRecorder,
|
|
15
|
+
statusListener: ((status: IRecordingStatus) => void) | undefined,
|
|
16
|
+
): () => void {
|
|
17
|
+
return subscribeSingleEvent(
|
|
18
|
+
recorder,
|
|
19
|
+
RECORDING_STATUS_UPDATE,
|
|
20
|
+
statusListener,
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -44,3 +44,8 @@ export class AudioRecorder extends expoAudio.AudioRecorder {
|
|
|
44
44
|
return super.prepareToRecordAsync(processedOptions);
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
|
+
|
|
48
|
+
/** Does not release automatically, same lifecycle note as `createAudioPlayer` */
|
|
49
|
+
export function createAudioRecorder(options: IRecordingOptions): AudioRecorder {
|
|
50
|
+
return new AudioRecorder(createRecordingOptions(options));
|
|
51
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { AUDIO_SAMPLE_UPDATE } from './types';
|
|
2
|
+
import type { IAudioSample } from './types';
|
|
3
|
+
|
|
4
|
+
export type IAudioSamplePlayer = {
|
|
5
|
+
isAudioSamplingSupported: boolean;
|
|
6
|
+
setAudioSamplingEnabled: (enabled: boolean) => void;
|
|
7
|
+
addListener: (
|
|
8
|
+
event: typeof AUDIO_SAMPLE_UPDATE,
|
|
9
|
+
listener: (data: IAudioSample) => void,
|
|
10
|
+
) => { remove: () => void };
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/** Ported from `expo-audio`'s `useAudioSampleListener` (its `useEffect` body factored out) */
|
|
14
|
+
export function subscribeAudioSampleListener(
|
|
15
|
+
player: IAudioSamplePlayer,
|
|
16
|
+
listener: (data: IAudioSample) => void,
|
|
17
|
+
): () => void {
|
|
18
|
+
if (!player.isAudioSamplingSupported) return () => {};
|
|
19
|
+
|
|
20
|
+
player.setAudioSamplingEnabled(true);
|
|
21
|
+
const subscription = player.addListener(AUDIO_SAMPLE_UPDATE, listener);
|
|
22
|
+
return () => subscription.remove();
|
|
23
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { IResourceController } from '@symbiote-native/engine';
|
|
2
|
+
import { createJsonKeyedResourceController } from './json-keyed-resource-controller';
|
|
3
|
+
import { createAudioStream, type AudioStream } from './audio-stream';
|
|
4
|
+
import type { IAudioStreamOptions } from './types';
|
|
5
|
+
|
|
6
|
+
export function createAudioStreamController(): IResourceController<
|
|
7
|
+
IAudioStreamOptions,
|
|
8
|
+
AudioStream
|
|
9
|
+
> {
|
|
10
|
+
return createJsonKeyedResourceController<IAudioStreamOptions, AudioStream>(
|
|
11
|
+
createAudioStream,
|
|
12
|
+
stream => stream.release(),
|
|
13
|
+
);
|
|
14
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { IResourceController } from '@symbiote-native/engine';
|
|
2
|
+
import { createAudioStreamController } from './audio-stream-controller';
|
|
3
|
+
import { AUDIO_STREAM_STATUS } from './types';
|
|
4
|
+
import type { AudioStream } from './audio-stream';
|
|
5
|
+
import type { IAudioStreamOptions, IAudioStreamStatus } from './types';
|
|
6
|
+
|
|
7
|
+
// Binds `createAudioStreamController`/`AUDIO_STREAM_STATUS` behind the getter-based
|
|
8
|
+
// `createResourceHook`/`createEventValueHook` shape Vue/Solid/Angular share (React keeps its own
|
|
9
|
+
// ref-based wiring, same split as `runAudioStreamBufferEffect`)
|
|
10
|
+
export function createAudioStreamHooks<TResourceBox, TStatusBox>(
|
|
11
|
+
createResourceHook: (
|
|
12
|
+
createController: () => IResourceController<
|
|
13
|
+
IAudioStreamOptions,
|
|
14
|
+
AudioStream
|
|
15
|
+
>,
|
|
16
|
+
) => (getArgs: () => [IAudioStreamOptions]) => TResourceBox,
|
|
17
|
+
createEventValueHook: (
|
|
18
|
+
event: typeof AUDIO_STREAM_STATUS,
|
|
19
|
+
getValue: (source: AudioStream) => IAudioStreamStatus,
|
|
20
|
+
) => (getSource: () => AudioStream) => TStatusBox,
|
|
21
|
+
): {
|
|
22
|
+
useStreamResource: (getArgs: () => [IAudioStreamOptions]) => TResourceBox;
|
|
23
|
+
useStreamStatus: (getSource: () => AudioStream) => TStatusBox;
|
|
24
|
+
} {
|
|
25
|
+
return {
|
|
26
|
+
useStreamResource: createResourceHook(createAudioStreamController),
|
|
27
|
+
useStreamStatus: createEventValueHook(AUDIO_STREAM_STATUS, stream => ({
|
|
28
|
+
isStreaming: stream.isStreaming,
|
|
29
|
+
})),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { subscribeAudioStreamBuffer } from './audio-stream-subscription';
|
|
2
|
+
import type { IAudioStreamBufferSource } from './audio-stream-subscription';
|
|
3
|
+
import type { IAudioStreamBuffer } from './types';
|
|
4
|
+
|
|
5
|
+
// Shared by adapters whose reactivity auto-tracks reads inside a plain effect (Vue's
|
|
6
|
+
// `watchEffect`, Solid's `createEffect`, Angular's `effect`); React's render model doesn't, so
|
|
7
|
+
// it keeps its own ref-based wiring - same split as `createNetworkRequestObserverLifecycle`
|
|
8
|
+
export function runAudioStreamBufferEffect<
|
|
9
|
+
TStream extends IAudioStreamBufferSource,
|
|
10
|
+
>(
|
|
11
|
+
getStream: () => TStream,
|
|
12
|
+
getOnBuffer: () => ((buffer: IAudioStreamBuffer) => void) | undefined,
|
|
13
|
+
runEffect: (effect: () => void) => void,
|
|
14
|
+
registerCleanup: (cleanup: () => void) => void,
|
|
15
|
+
): void {
|
|
16
|
+
runEffect(() => {
|
|
17
|
+
registerCleanup(subscribeAudioStreamBuffer(getStream(), getOnBuffer()));
|
|
18
|
+
});
|
|
19
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { AUDIO_STREAM_BUFFER } from './types';
|
|
2
|
+
import { subscribeSingleEvent } from './subscribe-single-event';
|
|
3
|
+
import type { IAudioStreamBuffer, IAudioStreamOptions } from './types';
|
|
4
|
+
import type { IUseAudioStreamOptions } from './audio-stream';
|
|
5
|
+
|
|
6
|
+
export type IAudioStreamBufferSource = {
|
|
7
|
+
addListener: (
|
|
8
|
+
event: typeof AUDIO_STREAM_BUFFER,
|
|
9
|
+
listener: (buffer: IAudioStreamBuffer) => void,
|
|
10
|
+
) => { remove: () => void };
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// Ported from `useAudioStream`'s buffer-listener `useEffect` body
|
|
14
|
+
export function subscribeAudioStreamBuffer(
|
|
15
|
+
stream: IAudioStreamBufferSource,
|
|
16
|
+
onBuffer: ((buffer: IAudioStreamBuffer) => void) | undefined,
|
|
17
|
+
): () => void {
|
|
18
|
+
return subscribeSingleEvent(stream, AUDIO_STREAM_BUFFER, onBuffer);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Drops `onBuffer` so a callback identity change doesn't recreate the native stream - matches
|
|
22
|
+
// upstream's own `[sampleRate, channels, encoding]` dependency array
|
|
23
|
+
export function toAudioStreamKey(
|
|
24
|
+
options: IUseAudioStreamOptions,
|
|
25
|
+
): IAudioStreamOptions {
|
|
26
|
+
const { sampleRate, channels, encoding } = options;
|
|
27
|
+
return { sampleRate, channels, encoding };
|
|
28
|
+
}
|