@symbiote-native/audio 0.1.2 → 0.1.3

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.
Files changed (280) hide show
  1. package/README.md +96 -52
  2. package/build/angular/index.d.ts +8 -0
  3. package/build/angular/index.js +8 -3
  4. package/build/angular/inject-audio-player-status.d.ts +4 -0
  5. package/build/angular/inject-audio-player-status.js +4 -0
  6. package/build/angular/inject-audio-player.d.ts +4 -0
  7. package/build/angular/inject-audio-player.js +8 -0
  8. package/build/angular/inject-audio-playlist-status.d.ts +3 -0
  9. package/build/angular/inject-audio-playlist-status.js +4 -0
  10. package/build/angular/inject-audio-playlist.d.ts +5 -0
  11. package/build/angular/inject-audio-playlist.js +7 -0
  12. package/build/angular/inject-audio-recorder-state.d.ts +5 -0
  13. package/build/angular/inject-audio-recorder-state.js +10 -0
  14. package/build/angular/inject-audio-recorder.d.ts +5 -0
  15. package/build/angular/inject-audio-recorder.js +13 -0
  16. package/build/angular/inject-audio-sample-listener.d.ts +4 -0
  17. package/build/angular/inject-audio-sample-listener.js +7 -0
  18. package/build/angular/inject-audio-stream.d.ts +4 -0
  19. package/build/angular/inject-audio-stream.js +17 -0
  20. package/build/core/audio-module.js +1 -1
  21. package/build/core/audio-player-controller.d.ts +7 -0
  22. package/build/core/audio-player-controller.js +10 -0
  23. package/build/core/audio-player.js +16 -4
  24. package/build/core/audio-playlist-controller.d.ts +4 -0
  25. package/build/core/audio-playlist-controller.js +5 -0
  26. package/build/core/audio-recorder-controller.d.ts +4 -0
  27. package/build/core/audio-recorder-controller.js +5 -0
  28. package/build/core/audio-recorder-polling.d.ts +5 -0
  29. package/build/core/audio-recorder-polling.js +10 -0
  30. package/build/core/audio-recorder-state.d.ts +2 -0
  31. package/build/core/audio-recorder-state.js +18 -0
  32. package/build/core/audio-recorder-status.d.ts +8 -0
  33. package/build/core/audio-recorder-status.js +6 -0
  34. package/build/core/audio-recorder.d.ts +2 -0
  35. package/build/core/audio-recorder.js +4 -0
  36. package/build/core/audio-sample-listener.d.ts +11 -0
  37. package/build/core/audio-sample-listener.js +9 -0
  38. package/build/core/audio-stream-controller.d.ts +4 -0
  39. package/build/core/audio-stream-controller.js +5 -0
  40. package/build/core/audio-stream-hooks.d.ts +8 -0
  41. package/build/core/audio-stream-hooks.js +13 -0
  42. package/build/core/audio-stream-lifecycle.d.ts +3 -0
  43. package/build/core/audio-stream-lifecycle.js +9 -0
  44. package/build/core/audio-stream-subscription.d.ts +10 -0
  45. package/build/core/audio-stream-subscription.js +12 -0
  46. package/build/core/audio-stream.d.ts +9 -10
  47. package/build/core/audio-stream.js +1 -9
  48. package/build/core/index.d.ts +14 -2
  49. package/build/core/index.js +9 -1
  50. package/build/core/json-keyed-resource-controller.d.ts +2 -0
  51. package/build/core/json-keyed-resource-controller.js +5 -0
  52. package/build/core/resolve-source.d.ts +2 -7
  53. package/build/core/resolve-source.js +69 -15
  54. package/build/core/subscribe-single-event.d.ts +5 -0
  55. package/build/core/subscribe-single-event.js +8 -0
  56. package/build/core/types.d.ts +11 -5
  57. package/build/react/index.d.ts +9 -0
  58. package/build/react/index.js +9 -0
  59. package/build/react/use-audio-player-status.d.ts +4 -0
  60. package/build/react/use-audio-player-status.js +4 -0
  61. package/build/react/use-audio-player.d.ts +3 -0
  62. package/build/react/use-audio-player.js +7 -0
  63. package/build/react/use-audio-playlist-status.d.ts +3 -0
  64. package/build/react/use-audio-playlist-status.js +4 -0
  65. package/build/react/use-audio-playlist.d.ts +4 -0
  66. package/build/react/use-audio-playlist.js +7 -0
  67. package/build/react/use-audio-recorder-state.d.ts +4 -0
  68. package/build/react/use-audio-recorder-state.js +9 -0
  69. package/build/react/use-audio-recorder.d.ts +4 -0
  70. package/build/react/use-audio-recorder.js +11 -0
  71. package/build/react/use-audio-sample-listener.d.ts +4 -0
  72. package/build/react/use-audio-sample-listener.js +6 -0
  73. package/build/react/use-audio-stream.d.ts +3 -0
  74. package/build/react/use-audio-stream.js +14 -0
  75. package/build/solid/index.d.ts +9 -0
  76. package/build/solid/index.js +9 -0
  77. package/build/solid/use-audio-player-status.d.ts +4 -0
  78. package/build/solid/use-audio-player-status.js +4 -0
  79. package/build/solid/use-audio-player.d.ts +5 -0
  80. package/build/solid/use-audio-player.js +7 -0
  81. package/build/solid/use-audio-playlist-status.d.ts +3 -0
  82. package/build/solid/use-audio-playlist-status.js +4 -0
  83. package/build/solid/use-audio-playlist.d.ts +5 -0
  84. package/build/solid/use-audio-playlist.js +7 -0
  85. package/build/solid/use-audio-recorder-state.d.ts +5 -0
  86. package/build/solid/use-audio-recorder-state.js +9 -0
  87. package/build/solid/use-audio-recorder.d.ts +5 -0
  88. package/build/solid/use-audio-recorder.js +13 -0
  89. package/build/solid/use-audio-sample-listener.d.ts +4 -0
  90. package/build/solid/use-audio-sample-listener.js +8 -0
  91. package/build/solid/use-audio-stream.d.ts +4 -0
  92. package/build/solid/use-audio-stream.js +16 -0
  93. package/build/svelte/index.d.ts +9 -0
  94. package/build/svelte/index.js +9 -0
  95. package/build/svelte/use-audio-player-status.svelte.d.ts +6 -0
  96. package/build/svelte/use-audio-player-status.svelte.js +4 -0
  97. package/build/svelte/use-audio-player.svelte.d.ts +6 -0
  98. package/build/svelte/use-audio-player.svelte.js +8 -0
  99. package/build/svelte/use-audio-playlist-status.svelte.d.ts +5 -0
  100. package/build/svelte/use-audio-playlist-status.svelte.js +4 -0
  101. package/build/svelte/use-audio-playlist.svelte.d.ts +6 -0
  102. package/build/svelte/use-audio-playlist.svelte.js +8 -0
  103. package/build/svelte/use-audio-recorder-state.svelte.d.ts +7 -0
  104. package/build/svelte/use-audio-recorder-state.svelte.js +14 -0
  105. package/build/svelte/use-audio-recorder.svelte.d.ts +6 -0
  106. package/build/svelte/use-audio-recorder.svelte.js +11 -0
  107. package/build/svelte/use-audio-sample-listener.svelte.d.ts +4 -0
  108. package/build/svelte/use-audio-sample-listener.svelte.js +5 -0
  109. package/build/svelte/use-audio-stream.svelte.d.ts +4 -0
  110. package/build/svelte/use-audio-stream.svelte.js +29 -0
  111. package/build/vue/index.d.ts +9 -0
  112. package/build/vue/index.js +9 -0
  113. package/build/vue/use-audio-player-status.d.ts +4 -0
  114. package/build/vue/use-audio-player-status.js +4 -0
  115. package/build/vue/use-audio-player.d.ts +5 -0
  116. package/build/vue/use-audio-player.js +8 -0
  117. package/build/vue/use-audio-playlist-status.d.ts +3 -0
  118. package/build/vue/use-audio-playlist-status.js +4 -0
  119. package/build/vue/use-audio-playlist.d.ts +5 -0
  120. package/build/vue/use-audio-playlist.js +8 -0
  121. package/build/vue/use-audio-recorder-state.d.ts +5 -0
  122. package/build/vue/use-audio-recorder-state.js +12 -0
  123. package/build/vue/use-audio-recorder.d.ts +5 -0
  124. package/build/vue/use-audio-recorder.js +11 -0
  125. package/build/vue/use-audio-sample-listener.d.ts +4 -0
  126. package/build/vue/use-audio-sample-listener.js +11 -0
  127. package/build/vue/use-audio-stream.d.ts +4 -0
  128. package/build/vue/use-audio-stream.js +18 -0
  129. package/build-ngc/angular/index.d.ts +8 -0
  130. package/build-ngc/angular/index.js +8 -3
  131. package/build-ngc/angular/index.js.map +1 -1
  132. package/build-ngc/angular/inject-audio-player-status.d.ts +4 -0
  133. package/build-ngc/angular/inject-audio-player-status.js +5 -0
  134. package/build-ngc/angular/inject-audio-player-status.js.map +1 -0
  135. package/build-ngc/angular/inject-audio-player.d.ts +4 -0
  136. package/build-ngc/angular/inject-audio-player.js +9 -0
  137. package/build-ngc/angular/inject-audio-player.js.map +1 -0
  138. package/build-ngc/angular/inject-audio-playlist-status.d.ts +3 -0
  139. package/build-ngc/angular/inject-audio-playlist-status.js +5 -0
  140. package/build-ngc/angular/inject-audio-playlist-status.js.map +1 -0
  141. package/build-ngc/angular/inject-audio-playlist.d.ts +5 -0
  142. package/build-ngc/angular/inject-audio-playlist.js +8 -0
  143. package/build-ngc/angular/inject-audio-playlist.js.map +1 -0
  144. package/build-ngc/angular/inject-audio-recorder-state.d.ts +5 -0
  145. package/build-ngc/angular/inject-audio-recorder-state.js +12 -0
  146. package/build-ngc/angular/inject-audio-recorder-state.js.map +1 -0
  147. package/build-ngc/angular/inject-audio-recorder.d.ts +5 -0
  148. package/build-ngc/angular/inject-audio-recorder.js +14 -0
  149. package/build-ngc/angular/inject-audio-recorder.js.map +1 -0
  150. package/build-ngc/angular/inject-audio-sample-listener.d.ts +4 -0
  151. package/build-ngc/angular/inject-audio-sample-listener.js +8 -0
  152. package/build-ngc/angular/inject-audio-sample-listener.js.map +1 -0
  153. package/build-ngc/angular/inject-audio-stream.d.ts +4 -0
  154. package/build-ngc/angular/inject-audio-stream.js +18 -0
  155. package/build-ngc/angular/inject-audio-stream.js.map +1 -0
  156. package/build-ngc/core/audio-module.js +1 -1
  157. package/build-ngc/core/audio-module.js.map +1 -1
  158. package/build-ngc/core/audio-player-controller.d.ts +7 -0
  159. package/build-ngc/core/audio-player-controller.js +11 -0
  160. package/build-ngc/core/audio-player-controller.js.map +1 -0
  161. package/build-ngc/core/audio-player.js +16 -4
  162. package/build-ngc/core/audio-player.js.map +1 -1
  163. package/build-ngc/core/audio-playlist-controller.d.ts +4 -0
  164. package/build-ngc/core/audio-playlist-controller.js +6 -0
  165. package/build-ngc/core/audio-playlist-controller.js.map +1 -0
  166. package/build-ngc/core/audio-recorder-controller.d.ts +4 -0
  167. package/build-ngc/core/audio-recorder-controller.js +6 -0
  168. package/build-ngc/core/audio-recorder-controller.js.map +1 -0
  169. package/build-ngc/core/audio-recorder-polling.d.ts +5 -0
  170. package/build-ngc/core/audio-recorder-polling.js +11 -0
  171. package/build-ngc/core/audio-recorder-polling.js.map +1 -0
  172. package/build-ngc/core/audio-recorder-state.d.ts +2 -0
  173. package/build-ngc/core/audio-recorder-state.js +19 -0
  174. package/build-ngc/core/audio-recorder-state.js.map +1 -0
  175. package/build-ngc/core/audio-recorder-status.d.ts +8 -0
  176. package/build-ngc/core/audio-recorder-status.js +7 -0
  177. package/build-ngc/core/audio-recorder-status.js.map +1 -0
  178. package/build-ngc/core/audio-recorder.d.ts +2 -0
  179. package/build-ngc/core/audio-recorder.js +4 -0
  180. package/build-ngc/core/audio-recorder.js.map +1 -1
  181. package/build-ngc/core/audio-sample-listener.d.ts +11 -0
  182. package/build-ngc/core/audio-sample-listener.js +10 -0
  183. package/build-ngc/core/audio-sample-listener.js.map +1 -0
  184. package/build-ngc/core/audio-stream-controller.d.ts +4 -0
  185. package/build-ngc/core/audio-stream-controller.js +6 -0
  186. package/build-ngc/core/audio-stream-controller.js.map +1 -0
  187. package/build-ngc/core/audio-stream-hooks.d.ts +8 -0
  188. package/build-ngc/core/audio-stream-hooks.js +14 -0
  189. package/build-ngc/core/audio-stream-hooks.js.map +1 -0
  190. package/build-ngc/core/audio-stream-lifecycle.d.ts +3 -0
  191. package/build-ngc/core/audio-stream-lifecycle.js +10 -0
  192. package/build-ngc/core/audio-stream-lifecycle.js.map +1 -0
  193. package/build-ngc/core/audio-stream-subscription.d.ts +10 -0
  194. package/build-ngc/core/audio-stream-subscription.js +13 -0
  195. package/build-ngc/core/audio-stream-subscription.js.map +1 -0
  196. package/build-ngc/core/audio-stream.d.ts +9 -10
  197. package/build-ngc/core/audio-stream.js +1 -9
  198. package/build-ngc/core/audio-stream.js.map +1 -1
  199. package/build-ngc/core/index.d.ts +14 -2
  200. package/build-ngc/core/index.js +9 -1
  201. package/build-ngc/core/index.js.map +1 -1
  202. package/build-ngc/core/json-keyed-resource-controller.d.ts +2 -0
  203. package/build-ngc/core/json-keyed-resource-controller.js +6 -0
  204. package/build-ngc/core/json-keyed-resource-controller.js.map +1 -0
  205. package/build-ngc/core/resolve-source.d.ts +2 -7
  206. package/build-ngc/core/resolve-source.js +69 -15
  207. package/build-ngc/core/resolve-source.js.map +1 -1
  208. package/build-ngc/core/subscribe-single-event.d.ts +5 -0
  209. package/build-ngc/core/subscribe-single-event.js +9 -0
  210. package/build-ngc/core/subscribe-single-event.js.map +1 -0
  211. package/build-ngc/core/types.d.ts +11 -5
  212. package/build-ngc/core/types.js.map +1 -1
  213. package/package.json +24 -23
  214. package/src/angular/index.ts +8 -3
  215. package/src/angular/inject-audio-player-status.ts +11 -0
  216. package/src/angular/inject-audio-player.ts +17 -0
  217. package/src/angular/inject-audio-playlist-status.ts +11 -0
  218. package/src/angular/inject-audio-playlist.ts +16 -0
  219. package/src/angular/inject-audio-recorder-state.ts +21 -0
  220. package/src/angular/inject-audio-recorder.ts +24 -0
  221. package/src/angular/inject-audio-sample-listener.ts +13 -0
  222. package/src/angular/inject-audio-stream.ts +41 -0
  223. package/src/core/audio-module.ts +2 -1
  224. package/src/core/audio-player-controller.ts +25 -0
  225. package/src/core/audio-player.ts +17 -4
  226. package/src/core/audio-playlist-controller.ts +14 -0
  227. package/src/core/audio-recorder-controller.ts +14 -0
  228. package/src/core/audio-recorder-polling.ts +20 -0
  229. package/src/core/audio-recorder-state.ts +26 -0
  230. package/src/core/audio-recorder-status.ts +22 -0
  231. package/src/core/audio-recorder.ts +5 -0
  232. package/src/core/audio-sample-listener.ts +23 -0
  233. package/src/core/audio-stream-controller.ts +14 -0
  234. package/src/core/audio-stream-hooks.ts +31 -0
  235. package/src/core/audio-stream-lifecycle.ts +19 -0
  236. package/src/core/audio-stream-subscription.ts +28 -0
  237. package/src/core/audio-stream.ts +11 -10
  238. package/src/core/index.ts +20 -1
  239. package/src/core/json-keyed-resource-controller.ts +16 -0
  240. package/src/core/resolve-source.ts +80 -18
  241. package/src/core/subscribe-single-event.ts +17 -0
  242. package/src/core/types.ts +13 -14
  243. package/src/react/index.ts +9 -0
  244. package/src/react/use-audio-player-status.ts +11 -0
  245. package/src/react/use-audio-player.ts +14 -0
  246. package/src/react/use-audio-playlist-status.ts +11 -0
  247. package/src/react/use-audio-playlist.ts +13 -0
  248. package/src/react/use-audio-recorder-state.ts +23 -0
  249. package/src/react/use-audio-recorder.ts +23 -0
  250. package/src/react/use-audio-sample-listener.ts +15 -0
  251. package/src/react/use-audio-stream.ts +39 -0
  252. package/src/solid/index.ts +9 -0
  253. package/src/solid/use-audio-player-status.ts +11 -0
  254. package/src/solid/use-audio-player.ts +15 -0
  255. package/src/solid/use-audio-playlist-status.ts +11 -0
  256. package/src/solid/use-audio-playlist.ts +14 -0
  257. package/src/solid/use-audio-recorder-state.ts +18 -0
  258. package/src/solid/use-audio-recorder.ts +22 -0
  259. package/src/solid/use-audio-sample-listener.ts +14 -0
  260. package/src/solid/use-audio-stream.ts +34 -0
  261. package/src/svelte/index.ts +9 -0
  262. package/src/svelte/svelte-ambient.d.ts +3 -0
  263. package/src/svelte/svelte-compile.test-helper.ts +7 -0
  264. package/src/svelte/use-audio-player-status.svelte.ts +11 -0
  265. package/src/svelte/use-audio-player.svelte.ts +20 -0
  266. package/src/svelte/use-audio-playlist-status.svelte.ts +11 -0
  267. package/src/svelte/use-audio-playlist.svelte.ts +19 -0
  268. package/src/svelte/use-audio-recorder-state.svelte.ts +29 -0
  269. package/src/svelte/use-audio-recorder.svelte.ts +25 -0
  270. package/src/svelte/use-audio-sample-listener.svelte.ts +11 -0
  271. package/src/svelte/use-audio-stream.svelte.ts +44 -0
  272. package/src/vue/index.ts +9 -0
  273. package/src/vue/use-audio-player-status.ts +11 -0
  274. package/src/vue/use-audio-player.ts +19 -0
  275. package/src/vue/use-audio-playlist-status.ts +11 -0
  276. package/src/vue/use-audio-playlist.ts +15 -0
  277. package/src/vue/use-audio-recorder-state.ts +21 -0
  278. package/src/vue/use-audio-recorder.ts +30 -0
  279. package/src/vue/use-audio-sample-listener.ts +22 -0
  280. package/src/vue/use-audio-stream.ts +40 -0
@@ -0,0 +1,5 @@
1
+ export declare function subscribeSingleEvent<TEvent extends string, TPayload>(source: {
2
+ addListener: (event: TEvent, listener: (payload: TPayload) => void) => {
3
+ remove: () => void;
4
+ };
5
+ }, event: TEvent, listener: ((payload: TPayload) => void) | undefined): () => void;
@@ -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
- * A URI string, an object describing a remote/local (by URI) audio source, or the numeric asset
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":"AAkRA,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"}
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.2",
3
+ "version": "0.1.3",
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/core/index.d.ts",
39
- "default": "./build/core/index.js"
38
+ "types": "./build/vue/index.d.ts",
39
+ "default": "./build/vue/index.js"
40
40
  },
41
41
  "./react": {
42
- "types": "./build/core/index.d.ts",
43
- "default": "./build/core/index.js"
42
+ "types": "./build/react/index.d.ts",
43
+ "default": "./build/react/index.js"
44
44
  },
45
45
  "./svelte": {
46
- "types": "./build/core/index.d.ts",
47
- "default": "./build/core/index.js"
46
+ "types": "./build/svelte/index.d.ts",
47
+ "default": "./build/svelte/index.js"
48
48
  },
49
49
  "./solid": {
50
- "types": "./build/core/index.d.ts",
51
- "default": "./build/core/index.js"
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.5"
73
+ "expo-modules-core": "57.0.20",
74
+ "@symbiote-native/asset": "0.1.1"
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.1.2",
84
- "@symbiote-native/engine": "^1.3.1",
85
- "@symbiote-native/react": "^3.0.4",
86
- "@symbiote-native/solid": "^3.0.4",
87
- "@symbiote-native/svelte": "^3.0.4",
88
- "@symbiote-native/vue": "^3.0.4"
84
+ "@symbiote-native/angular": "^3.2.0",
85
+ "@symbiote-native/engine": "^1.5.0",
86
+ "@symbiote-native/react": "^3.2.0",
87
+ "@symbiote-native/solid": "^3.1.0",
88
+ "@symbiote-native/svelte": "^3.1.0",
89
+ "@symbiote-native/vue": "^3.2.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.1.2",
137
- "@symbiote-native/engine": "1.3.1",
138
- "@symbiote-native/react": "3.0.4",
139
- "@symbiote-native/solid": "3.0.4",
140
- "@symbiote-native/svelte": "3.0.4",
141
- "@symbiote-native/test-utils": "0.4.4",
142
- "@symbiote-native/vue": "3.0.4"
137
+ "@symbiote-native/angular": "3.2.0",
138
+ "@symbiote-native/engine": "1.5.0",
139
+ "@symbiote-native/react": "3.2.0",
140
+ "@symbiote-native/solid": "3.1.0",
141
+ "@symbiote-native/svelte": "3.1.0",
142
+ "@symbiote-native/test-utils": "0.4.6",
143
+ "@symbiote-native/vue": "3.2.0"
143
144
  },
144
145
  "scripts": {
145
146
  "typecheck": "tsc --build",
@@ -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
+ }
@@ -18,7 +18,8 @@ export async function setAudioModeAsync(
18
18
  : {
19
19
  shouldPlayInBackground: mode.shouldPlayInBackground,
20
20
  shouldRouteThroughEarpiece: mode.shouldRouteThroughEarpiece,
21
- interruptionMode: mode.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
+ }
@@ -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 resolvedSource = resolveSource(source);
47
- return new AudioPlayer(
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
+ }