react-native-audio-api 0.6.0-rc.1 → 0.6.0-rc.2

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 (90) hide show
  1. package/README.md +35 -22
  2. package/android/src/main/cpp/audioapi/android/core/AndroidAudioRecorder.cpp +73 -0
  3. package/android/src/main/cpp/audioapi/android/core/AndroidAudioRecorder.h +37 -0
  4. package/android/src/main/cpp/audioapi/android/core/AudioPlayer.cpp +6 -10
  5. package/android/src/main/cpp/audioapi/android/core/AudioPlayer.h +2 -3
  6. package/android/src/main/java/com/swmansion/audioapi/AudioManagerModule.kt +10 -8
  7. package/android/src/main/java/com/swmansion/audioapi/system/MediaNotificationManager.kt +7 -7
  8. package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionEventEmitter.kt +4 -0
  9. package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionManager.kt +31 -13
  10. package/android/src/main/java/com/swmansion/audioapi/system/VolumeChangeListener.kt +27 -0
  11. package/common/cpp/audioapi/AudioAPIModuleInstaller.h +29 -5
  12. package/common/cpp/audioapi/HostObjects/AnalyserNodeHostObject.h +1 -0
  13. package/common/cpp/audioapi/HostObjects/AudioRecorderHostObject.h +149 -0
  14. package/common/cpp/audioapi/core/AudioContext.cpp +4 -3
  15. package/common/cpp/audioapi/core/BaseAudioContext.cpp +6 -6
  16. package/common/cpp/audioapi/core/inputs/AudioRecorder.h +38 -0
  17. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +5 -0
  18. package/common/cpp/audioapi/core/sources/OscillatorNode.cpp +1 -1
  19. package/common/cpp/audioapi/core/utils/AudioNodeManager.cpp +45 -11
  20. package/common/cpp/audioapi/core/utils/AudioNodeManager.h +6 -2
  21. package/ios/audioapi/ios/AudioManagerModule.mm +9 -10
  22. package/ios/audioapi/ios/core/IOSAudioPlayer.h +11 -12
  23. package/ios/audioapi/ios/core/IOSAudioPlayer.mm +22 -16
  24. package/ios/audioapi/ios/core/IOSAudioRecorder.h +36 -0
  25. package/ios/audioapi/ios/core/IOSAudioRecorder.mm +62 -0
  26. package/ios/audioapi/ios/core/{AudioPlayer.h → NativeAudioPlayer.h} +1 -8
  27. package/ios/audioapi/ios/core/{AudioPlayer.m → NativeAudioPlayer.m} +4 -33
  28. package/ios/audioapi/ios/core/NativeAudioRecorder.h +25 -0
  29. package/ios/audioapi/ios/core/NativeAudioRecorder.m +47 -0
  30. package/ios/audioapi/ios/system/AudioEngine.h +7 -1
  31. package/ios/audioapi/ios/system/AudioEngine.mm +64 -20
  32. package/ios/audioapi/ios/system/AudioSessionManager.h +3 -1
  33. package/ios/audioapi/ios/system/AudioSessionManager.mm +37 -25
  34. package/ios/audioapi/ios/system/NotificationManager.h +7 -1
  35. package/ios/audioapi/ios/system/NotificationManager.mm +30 -0
  36. package/lib/commonjs/api.js +15 -1
  37. package/lib/commonjs/api.js.map +1 -1
  38. package/lib/commonjs/core/AudioRecorder.js +51 -0
  39. package/lib/commonjs/core/AudioRecorder.js.map +1 -0
  40. package/lib/commonjs/errors/NotSupportedError.js.map +1 -1
  41. package/lib/commonjs/hooks/useSytemVolume.js +24 -0
  42. package/lib/commonjs/hooks/useSytemVolume.js.map +1 -0
  43. package/lib/commonjs/plugin/withAudioAPI.js +1 -1
  44. package/lib/commonjs/plugin/withAudioAPI.js.map +1 -1
  45. package/lib/commonjs/specs/NativeAudioManagerModule.js +5 -2
  46. package/lib/commonjs/specs/NativeAudioManagerModule.js.map +1 -1
  47. package/lib/commonjs/system/AudioManager.js +23 -50
  48. package/lib/commonjs/system/AudioManager.js.map +1 -1
  49. package/lib/module/api.js +3 -1
  50. package/lib/module/api.js.map +1 -1
  51. package/lib/module/core/AudioRecorder.js +45 -0
  52. package/lib/module/core/AudioRecorder.js.map +1 -0
  53. package/lib/module/errors/NotSupportedError.js.map +1 -1
  54. package/lib/module/hooks/useSytemVolume.js +19 -0
  55. package/lib/module/hooks/useSytemVolume.js.map +1 -0
  56. package/lib/module/plugin/withAudioAPI.js +1 -1
  57. package/lib/module/plugin/withAudioAPI.js.map +1 -1
  58. package/lib/module/specs/NativeAudioManagerModule.js +5 -2
  59. package/lib/module/specs/NativeAudioManagerModule.js.map +1 -1
  60. package/lib/module/system/AudioManager.js +23 -50
  61. package/lib/module/system/AudioManager.js.map +1 -1
  62. package/lib/typescript/api.d.ts +5 -1
  63. package/lib/typescript/api.d.ts.map +1 -1
  64. package/lib/typescript/core/AudioRecorder.d.ts +22 -0
  65. package/lib/typescript/core/AudioRecorder.d.ts.map +1 -0
  66. package/lib/typescript/errors/NotSupportedError.d.ts.map +1 -1
  67. package/lib/typescript/hooks/useSytemVolume.d.ts +2 -0
  68. package/lib/typescript/hooks/useSytemVolume.d.ts.map +1 -0
  69. package/lib/typescript/interfaces.d.ts +11 -5
  70. package/lib/typescript/interfaces.d.ts.map +1 -1
  71. package/lib/typescript/plugin/withAudioAPI.d.ts.map +1 -1
  72. package/lib/typescript/specs/NativeAudioManagerModule.d.ts +2 -1
  73. package/lib/typescript/specs/NativeAudioManagerModule.d.ts.map +1 -1
  74. package/lib/typescript/system/AudioManager.d.ts +4 -3
  75. package/lib/typescript/system/AudioManager.d.ts.map +1 -1
  76. package/lib/typescript/system/types.d.ts +26 -7
  77. package/lib/typescript/system/types.d.ts.map +1 -1
  78. package/lib/typescript/types.d.ts +5 -0
  79. package/lib/typescript/types.d.ts.map +1 -1
  80. package/package.json +2 -1
  81. package/src/api.ts +13 -2
  82. package/src/core/AudioRecorder.ts +81 -0
  83. package/src/hooks/useSytemVolume.ts +19 -0
  84. package/src/interfaces.ts +25 -11
  85. package/src/plugin/withAudioAPI.ts +2 -1
  86. package/src/specs/NativeAudioManagerModule.ts +5 -8
  87. package/src/system/AudioManager.ts +30 -107
  88. package/src/system/types.ts +31 -21
  89. package/src/types.ts +13 -0
  90. /package/src/errors/{NotSupportedError.tsx → NotSupportedError.ts} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/system/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GACnB,QAAQ,GACR,SAAS,GACT,UAAU,GACV,YAAY,GACZ,aAAa,GACb,eAAe,CAAC;AAEpB,MAAM,MAAM,OAAO,GACf,SAAS,GACT,UAAU,GACV,WAAW,GACX,WAAW,GACX,aAAa,GACb,aAAa,GACb,aAAa,GACb,eAAe,GACf,gBAAgB,CAAC;AAErB,MAAM,MAAM,SAAS,GACjB,YAAY,GACZ,cAAc,GACd,eAAe,GACf,gBAAgB,GAChB,kBAAkB,GAClB,oBAAoB,GACpB,qCAAqC,GACrC,sCAAsC,CAAC;AAE3C,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,SAAS,EAAE,CAAC;IACzB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,MAAM,UAAU,GAAG,eAAe,GAAG,cAAc,CAAC;AAE1D,UAAU,kBAAkB;IAC1B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;CACtD;AAED,MAAM,WAAW,cAAe,SAAQ,kBAAkB;IACxD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,sBAAsB,GAC9B,MAAM,GACN,OAAO,GACP,MAAM,GACN,iBAAiB,GACjB,oBAAoB,GACpB,WAAW,GACX,eAAe,GACf,aAAa,GACb,cAAc,GACd,aAAa,GACb,cAAc,GACd,wBAAwB,CAAC;AAE7B,MAAM,MAAM,qBAAqB,GAAG,cAAc,GAAG,aAAa,CAAC;AAEnE,MAAM,WAAW,2BAA2B;CAAG;AAE/C,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;IACxB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;CAChB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/system/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GACnB,QAAQ,GACR,SAAS,GACT,UAAU,GACV,YAAY,GACZ,aAAa,GACb,eAAe,CAAC;AAEpB,MAAM,MAAM,OAAO,GACf,SAAS,GACT,UAAU,GACV,WAAW,GACX,WAAW,GACX,aAAa,GACb,aAAa,GACb,aAAa,GACb,eAAe,GACf,gBAAgB,CAAC;AAErB,MAAM,MAAM,SAAS,GACjB,YAAY,GACZ,cAAc,GACd,eAAe,GACf,gBAAgB,GAChB,kBAAkB,GAClB,oBAAoB,GACpB,qCAAqC,GACrC,sCAAsC,CAAC;AAE3C,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,SAAS,EAAE,CAAC;IACzB,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED,MAAM,MAAM,UAAU,GAAG,eAAe,GAAG,cAAc,CAAC;AAE1D,UAAU,kBAAkB;IAC1B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;CACtD;AAED,MAAM,WAAW,cAAe,SAAQ,kBAAkB;IACxD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,UAAU,eAAe;CAAG;AAE5B,UAAU,sBAAsB;IAC9B,KAAK,EAAE,MAAM,CAAC;CACf;AAED,UAAU,uBAAuB;IAC/B,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;IACxB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED,UAAU,sBAAsB;IAC9B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,cAAc;IACtB,IAAI,EAAE,eAAe,CAAC;IACtB,KAAK,EAAE,eAAe,CAAC;IACvB,IAAI,EAAE,eAAe,CAAC;IACtB,eAAe,EAAE,eAAe,CAAC;IACjC,kBAAkB,EAAE,eAAe,CAAC;IACpC,SAAS,EAAE,eAAe,CAAC;IAC3B,aAAa,EAAE,eAAe,CAAC;IAC/B,WAAW,EAAE,eAAe,CAAC;IAC7B,YAAY,EAAE,eAAe,CAAC;IAC9B,WAAW,EAAE,eAAe,CAAC;IAC7B,YAAY,EAAE,eAAe,CAAC;IAC9B,sBAAsB,EAAE,eAAe,CAAC;CACzC;AAED,UAAU,YAAY;IACpB,YAAY,EAAE,sBAAsB,CAAC;IACrC,YAAY,EAAE,uBAAuB,CAAC;IACtC,WAAW,EAAE,sBAAsB,CAAC;CACrC;AAED,MAAM,MAAM,iBAAiB,GAAG,MAAM,cAAc,CAAC;AACrD,MAAM,MAAM,eAAe,GAAG,MAAM,YAAY,CAAC;AACjD,MAAM,MAAM,mBAAmB,CAAC,IAAI,SAAS,eAAe,IAAI,CAC9D,KAAK,EAAE,YAAY,CAAC,IAAI,CAAC,KACtB,IAAI,CAAC"}
@@ -14,8 +14,13 @@ export interface OfflineAudioContextOptions {
14
14
  length: number;
15
15
  sampleRate: number;
16
16
  }
17
+ export interface AudioRecorderOptions {
18
+ sampleRate: number;
19
+ bufferLengthInSamples: number;
20
+ }
17
21
  export type WindowType = 'blackman' | 'hann';
18
22
  export interface AudioBufferSourceNodeOptions {
19
23
  pitchCorrection: boolean;
20
24
  }
25
+ export type AudioRecorderStatus = 'idle' | 'initializing' | 'ready' | 'running' | 'stopping' | 'error';
21
26
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,aAAa,GAAG,UAAU,CAAC;AAElE,MAAM,MAAM,qBAAqB,GAAG,UAAU,GAAG,UAAU,CAAC;AAE5D,MAAM,MAAM,gBAAgB,GACxB,SAAS,GACT,UAAU,GACV,UAAU,GACV,UAAU,GACV,WAAW,GACX,SAAS,GACT,OAAO,GACP,SAAS,CAAC;AAEd,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,QAAQ,GAAG,WAAW,CAAC;AAE9D,MAAM,MAAM,cAAc,GACtB,MAAM,GACN,QAAQ,GACR,UAAU,GACV,UAAU,GACV,QAAQ,CAAC;AAEb,MAAM,WAAW,uBAAuB;IACtC,oBAAoB,EAAE,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,0BAA0B;IACzC,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,MAAM,CAAC;AAE7C,MAAM,WAAW,4BAA4B;IAC3C,eAAe,EAAE,OAAO,CAAC;CAC1B"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,aAAa,GAAG,UAAU,CAAC;AAElE,MAAM,MAAM,qBAAqB,GAAG,UAAU,GAAG,UAAU,CAAC;AAE5D,MAAM,MAAM,gBAAgB,GACxB,SAAS,GACT,UAAU,GACV,UAAU,GACV,UAAU,GACV,WAAW,GACX,SAAS,GACT,OAAO,GACP,SAAS,CAAC;AAEd,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,QAAQ,GAAG,WAAW,CAAC;AAE9D,MAAM,MAAM,cAAc,GACtB,MAAM,GACN,QAAQ,GACR,UAAU,GACV,UAAU,GACV,QAAQ,CAAC;AAEb,MAAM,WAAW,uBAAuB;IACtC,oBAAoB,EAAE,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,0BAA0B;IACzC,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,qBAAqB,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,MAAM,CAAC;AAE7C,MAAM,WAAW,4BAA4B;IAC3C,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,MAAM,mBAAmB,GAC3B,MAAM,GACN,cAAc,GACd,OAAO,GACP,SAAS,GACT,UAAU,GACV,OAAO,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-audio-api",
3
- "version": "0.6.0-rc.1",
3
+ "version": "0.6.0-rc.2",
4
4
  "description": "react-native-audio-api provides system for controlling audio in React Native environment compatible with Web Audio API specification",
5
5
  "bin": {
6
6
  "setup-rn-audio-api-web": "./scripts/setup-rn-audio-api-web.js"
@@ -52,6 +52,7 @@
52
52
  "format:ios": "find ios/ \\( -iname \"*.h\" -o -iname \"*.m\" -o -iname \"*.mm\" -o -iname \"*.cpp\" \\) -not -path \"ios/audioapi/ios/*\" | xargs clang-format -i",
53
53
  "format:common": "find common/cpp/ -path 'common/cpp/audioapi/libs' -prune -iname \"*.h\" -o -iname \"*.cpp\" | xargs clang-format -i",
54
54
  "build": "bob build",
55
+ "create:package": "./scripts/create-package.sh",
55
56
  "prepack": "cp ../../README.md ./README.md",
56
57
  "postpack": "rm ./README.md"
57
58
  },
package/src/api.ts CHANGED
@@ -1,5 +1,10 @@
1
1
  import NativeAudioAPIModule from './specs/NativeAudioAPIModule';
2
- import type { IAudioContext, IOfflineAudioContext } from './interfaces';
2
+ import { AudioRecorderOptions } from './types';
3
+ import type {
4
+ IAudioContext,
5
+ IAudioRecorder,
6
+ IOfflineAudioContext,
7
+ } from './interfaces';
3
8
 
4
9
  /* eslint-disable no-var */
5
10
  declare global {
@@ -9,12 +14,16 @@ declare global {
9
14
  length: number,
10
15
  sampleRate: number
11
16
  ) => IOfflineAudioContext;
17
+
18
+ var createAudioRecorder: (options: AudioRecorderOptions) => IAudioRecorder;
12
19
  }
20
+
13
21
  /* eslint-disable no-var */
14
22
 
15
23
  if (
16
24
  global.createAudioContext == null ||
17
- global.createOfflineAudioContext == null
25
+ global.createOfflineAudioContext == null ||
26
+ global.createAudioRecorder == null
18
27
  ) {
19
28
  if (!NativeAudioAPIModule) {
20
29
  throw new Error(
@@ -39,7 +48,9 @@ export { default as BiquadFilterNode } from './core/BiquadFilterNode';
39
48
  export { default as GainNode } from './core/GainNode';
40
49
  export { default as OscillatorNode } from './core/OscillatorNode';
41
50
  export { default as StereoPannerNode } from './core/StereoPannerNode';
51
+ export { default as AudioRecorder } from './core/AudioRecorder';
42
52
  export { default as AudioManager } from './system';
53
+ export { default as useSystemVolume } from './hooks/useSytemVolume';
43
54
 
44
55
  export {
45
56
  OscillatorType,
@@ -0,0 +1,81 @@
1
+ import {
2
+ IAudioRecorder,
3
+ IErrorCallback,
4
+ IAudioReadyCallback,
5
+ IStatusChangeCallback,
6
+ IAudioBuffer,
7
+ } from '../interfaces';
8
+ import { AudioRecorderStatus, AudioRecorderOptions } from '../types';
9
+ import AudioBuffer from './AudioBuffer';
10
+
11
+ export type AudioReadyCallback = (
12
+ buffer: AudioBuffer,
13
+ numFrames: number,
14
+ when: number
15
+ ) => void;
16
+
17
+ export type ErrorCallback = (error: Error) => void;
18
+
19
+ export type StatusChangeCallback = (
20
+ status: AudioRecorderStatus,
21
+ previousStatus: AudioRecorderStatus
22
+ ) => void;
23
+
24
+ export default class AudioRecorder {
25
+ protected readonly recorder: IAudioRecorder;
26
+ private onAudioReadyCallback: AudioReadyCallback | null = null;
27
+ private onErrorCallback: ErrorCallback | null = null;
28
+ private onStatusChangeCallback: StatusChangeCallback | null = null;
29
+
30
+ private onAudioReadyInternal: IAudioReadyCallback = (
31
+ buffer: IAudioBuffer,
32
+ numFrames: number,
33
+ when: number
34
+ ) => {
35
+ if (this.onAudioReadyCallback) {
36
+ this.onAudioReadyCallback(new AudioBuffer(buffer), numFrames, when);
37
+ }
38
+ };
39
+
40
+ private onErrorInternal: IErrorCallback = (error: Error) => {
41
+ if (this.onErrorCallback) {
42
+ this.onErrorCallback(error);
43
+ }
44
+ };
45
+
46
+ private onStatusChangeInternal: IStatusChangeCallback = (
47
+ status: AudioRecorderStatus,
48
+ previousStatus: AudioRecorderStatus
49
+ ) => {
50
+ if (this.onStatusChangeCallback) {
51
+ this.onStatusChangeCallback(status, previousStatus);
52
+ }
53
+ };
54
+
55
+ constructor(options: AudioRecorderOptions) {
56
+ this.recorder = global.createAudioRecorder(options);
57
+ }
58
+
59
+ public start(): void {
60
+ this.recorder.start();
61
+ }
62
+
63
+ public stop(): void {
64
+ this.recorder.stop();
65
+ }
66
+
67
+ public onAudioReady(callback: AudioReadyCallback): void {
68
+ this.onAudioReadyCallback = callback;
69
+ this.recorder.onAudioReady(this.onAudioReadyInternal);
70
+ }
71
+
72
+ public onError(callback: ErrorCallback): void {
73
+ this.onErrorCallback = callback;
74
+ this.recorder.onError(this.onErrorInternal);
75
+ }
76
+
77
+ public onStatusChange(callback: StatusChangeCallback): void {
78
+ this.onStatusChangeCallback = callback;
79
+ this.recorder.onStatusChange(this.onStatusChangeInternal);
80
+ }
81
+ }
@@ -0,0 +1,19 @@
1
+ import { useEffect, useState } from 'react';
2
+ import AudioManager from '../system/AudioManager';
3
+
4
+ export default function useSystemVolume() {
5
+ const [volume, setVolume] = useState(0);
6
+
7
+ useEffect(() => {
8
+ AudioManager.observeVolumeChanges(true);
9
+ const listener = AudioManager.enableRemoteEvent('volumeChange', (e) => {
10
+ setVolume(parseFloat(e.value.toFixed(2)));
11
+ });
12
+ return () => {
13
+ listener?.remove();
14
+ AudioManager.observeVolumeChanges(false);
15
+ };
16
+ }, []);
17
+
18
+ return volume;
19
+ }
package/src/interfaces.ts CHANGED
@@ -1,21 +1,13 @@
1
1
  import {
2
+ WindowType,
2
3
  ContextState,
3
- BiquadFilterType,
4
4
  OscillatorType,
5
+ BiquadFilterType,
5
6
  ChannelCountMode,
7
+ AudioRecorderStatus,
6
8
  ChannelInterpretation,
7
- WindowType,
8
9
  } from './types';
9
10
 
10
- export interface AudioAPIInstaller {
11
- createAudioContext: (sampleRate?: number) => IAudioContext;
12
- createOfflineAudioContext: (
13
- numberOfChannels: number,
14
- length: number,
15
- sampleRate: number
16
- ) => IAudioContext;
17
- }
18
-
19
11
  export interface IBaseAudioContext {
20
12
  readonly destination: IAudioDestinationNode;
21
13
  readonly state: ContextState;
@@ -172,3 +164,25 @@ export interface IAnalyserNode extends IAudioNode {
172
164
  getFloatTimeDomainData: (array: Float32Array) => void;
173
165
  getByteTimeDomainData: (array: Uint8Array) => void;
174
166
  }
167
+
168
+ export type IAudioReadyCallback = (
169
+ buffer: IAudioBuffer,
170
+ numFrames: number,
171
+ when: number
172
+ ) => void;
173
+
174
+ export type IErrorCallback = (error: Error) => void;
175
+
176
+ export type IStatusChangeCallback = (
177
+ status: AudioRecorderStatus,
178
+ previousStatus: AudioRecorderStatus
179
+ ) => void;
180
+
181
+ export interface IAudioRecorder {
182
+ start: () => void;
183
+ stop: () => void;
184
+
185
+ onAudioReady: (callback: IAudioReadyCallback) => void;
186
+ onError: (callback: IErrorCallback) => void;
187
+ onStatusChange: (callback: IStatusChangeCallback) => void;
188
+ }
@@ -41,7 +41,8 @@ const withForegroundService: ConfigPlugin<{
41
41
 
42
42
  const serviceElement = {
43
43
  $: {
44
- 'android:name': 'system.MediaNotificationManager$NotificationService',
44
+ 'android:name':
45
+ 'com.swmansion.audioapi.system.MediaNotificationManager$NotificationService',
45
46
  'android:stopWithTask': 'true',
46
47
  'android:foregroundServiceType': SFTypes,
47
48
  },
@@ -27,15 +27,9 @@ const AudioManagerModule = {
27
27
  setAudioSessionOptions(
28
28
  category: string,
29
29
  mode: string,
30
- options: Array<string>,
31
- active: boolean
30
+ options: Array<string>
32
31
  ): void {
33
- NativeAudioManagerModule.setAudioSessionOptions(
34
- category,
35
- mode,
36
- options,
37
- active
38
- );
32
+ NativeAudioManagerModule.setAudioSessionOptions(category, mode, options);
39
33
  },
40
34
  getDevicePreferredSampleRate(): number {
41
35
  return NativeAudioManagerModule.getDevicePreferredSampleRate();
@@ -43,6 +37,9 @@ const AudioManagerModule = {
43
37
  observeAudioInterruptions(enabled: boolean): void {
44
38
  NativeAudioManagerModule.observeAudioInterruptions(enabled);
45
39
  },
40
+ observeVolumeChanges(enabled: boolean): void {
41
+ NativeAudioManagerModule.observeVolumeChanges(enabled);
42
+ },
46
43
  };
47
44
 
48
45
  export { eventEmitter, AudioManagerModule };
@@ -1,22 +1,13 @@
1
1
  import {
2
2
  SessionOptions,
3
3
  LockScreenInfo,
4
- RemoteControlEventName,
5
- InterruptionEventName,
6
- RemoteControlEmptyEventType,
7
- RemoteControlEventType,
8
- OnInterruptionEventType,
9
- OnRouteChangeEventType,
4
+ RemoteEventName,
5
+ RemoteEventCallback,
6
+ RemoteCommandName,
10
7
  } from './types';
11
8
  import { AudioManagerModule, eventEmitter } from '../specs';
12
9
  import { EmitterSubscription } from 'react-native';
13
10
 
14
- type AudioManagerEventType =
15
- | RemoteControlEmptyEventType
16
- | RemoteControlEventType
17
- | OnInterruptionEventType
18
- | OnRouteChangeEventType;
19
-
20
11
  class AudioManager {
21
12
  setLockScreenInfo(info: LockScreenInfo) {
22
13
  AudioManagerModule.setLockScreenInfo(info);
@@ -30,8 +21,7 @@ class AudioManager {
30
21
  AudioManagerModule.setAudioSessionOptions(
31
22
  options.iosCategory ?? '',
32
23
  options.iosMode ?? '',
33
- options.iosOptions ?? [],
34
- options.active ?? true
24
+ options.iosOptions ?? []
35
25
  );
36
26
  }
37
27
 
@@ -43,105 +33,38 @@ class AudioManager {
43
33
  AudioManagerModule.observeAudioInterruptions(enabled);
44
34
  }
45
35
 
46
- enableRemoteCommand(
47
- name: RemoteControlEventName | InterruptionEventName,
48
- enabled: boolean,
49
- callback?: (event: AudioManagerEventType) => void
50
- ): EmitterSubscription | null {
51
- AudioManagerModule.enableRemoteCommand(name, enabled);
52
-
53
- let subscription = null;
54
-
55
- if (enabled && callback) {
56
- switch (name) {
57
- case 'play':
58
- subscription = eventEmitter.addListener('onRemotePlay', callback);
59
- break;
60
-
61
- case 'pause':
62
- subscription = eventEmitter.addListener('onRemotePause', callback);
63
- break;
64
-
65
- case 'stop':
66
- subscription = eventEmitter.addListener('onRemoteStop', callback);
67
- break;
68
-
69
- case 'togglePlayPause':
70
- subscription = eventEmitter.addListener(
71
- 'onRemoteTogglePlayPause',
72
- callback
73
- );
74
- break;
75
-
76
- case 'changePlaybackRate':
77
- subscription = eventEmitter.addListener(
78
- 'onRemoteChangePlaybackRate',
79
- callback
80
- );
81
- break;
82
-
83
- case 'nextTrack':
84
- subscription = eventEmitter.addListener(
85
- 'onRemoteNextTrack',
86
- callback
87
- );
88
- break;
89
-
90
- case 'previousTrack':
91
- subscription = eventEmitter.addListener(
92
- 'onRemotePreviousTrack',
93
- callback
94
- );
95
- break;
96
-
97
- case 'skipForward':
98
- subscription = eventEmitter.addListener(
99
- 'onRemoteSkipForward',
100
- callback
101
- );
102
- break;
103
-
104
- case 'skipBackward':
105
- subscription = eventEmitter.addListener(
106
- 'onRemoteSkipBackward',
107
- callback
108
- );
109
- break;
110
-
111
- case 'seekForward':
112
- subscription = eventEmitter.addListener(
113
- 'onRemoteSeekForward',
114
- callback
115
- );
116
- break;
36
+ observeVolumeChanges(enabled: boolean) {
37
+ AudioManagerModule.observeVolumeChanges(enabled);
38
+ }
117
39
 
118
- case 'seekBackward':
119
- subscription = eventEmitter.addListener(
120
- 'onRemoteSeekBackward',
121
- callback
122
- );
123
- break;
40
+ enableRemoteCommand<Name extends RemoteCommandName>(name: Name): void {
41
+ AudioManagerModule.enableRemoteCommand(name, true);
42
+ }
124
43
 
125
- case 'changePlaybackPosition':
126
- subscription = eventEmitter.addListener(
127
- 'onRemoteChangePlaybackPosition',
128
- callback
129
- );
130
- break;
44
+ enableRemoteEvent<Name extends RemoteEventName>(
45
+ name: Name,
46
+ callback?: RemoteEventCallback<Name>
47
+ ): EmitterSubscription | null {
48
+ let subscription = null;
49
+ if (!callback) {
50
+ return null;
51
+ }
52
+ switch (name) {
53
+ case 'interruption':
54
+ subscription = eventEmitter.addListener('onInterruption', callback);
55
+ break;
131
56
 
132
- case 'interruption':
133
- subscription = eventEmitter.addListener('onInterruption', callback);
134
- break;
57
+ case 'routeChange':
58
+ subscription = eventEmitter.addListener('onRouteChange', callback);
59
+ break;
135
60
 
136
- case 'routeChange':
137
- subscription = eventEmitter.addListener('onRouteChange', callback);
138
- break;
61
+ case 'volumeChange':
62
+ subscription = eventEmitter.addListener('onVolumeChange', callback);
63
+ break;
139
64
 
140
- default:
141
- console.error('Unsupported RemoteControl action:', name);
142
- }
65
+ default:
66
+ console.error('Unsupported RemoteControl action:', name);
143
67
  }
144
-
145
68
  return subscription;
146
69
  }
147
70
  }
@@ -31,7 +31,6 @@ export interface SessionOptions {
31
31
  iosMode?: IOSMode;
32
32
  iosOptions?: IOSOption[];
33
33
  iosCategory?: IOSCategory;
34
- active?: boolean;
35
34
  }
36
35
 
37
36
  export type MediaState = 'state_playing' | 'state_paused';
@@ -52,33 +51,44 @@ export interface LockScreenInfo extends BaseLockScreenInfo {
52
51
  elapsedTime?: number;
53
52
  }
54
53
 
55
- export type RemoteControlEventName =
56
- | 'play'
57
- | 'pause'
58
- | 'stop'
59
- | 'togglePlayPause'
60
- | 'changePlaybackRate'
61
- | 'nextTrack'
62
- | 'previousTrack'
63
- | 'skipForward'
64
- | 'skipBackward'
65
- | 'seekForward'
66
- | 'seekBackward'
67
- | 'changePlaybackPosition';
54
+ interface RemoteEmptyType {}
68
55
 
69
- export type InterruptionEventName = 'interruption' | 'routeChange';
70
-
71
- export interface RemoteControlEmptyEventType {}
72
-
73
- export interface RemoteControlEventType {
56
+ interface RemoteControlEventType {
74
57
  value: number;
75
58
  }
76
59
 
77
- export interface OnInterruptionEventType {
60
+ interface OnInterruptionEventType {
78
61
  type: 'ended' | 'began';
79
62
  shouldResume: boolean;
80
63
  }
81
64
 
82
- export interface OnRouteChangeEventType {
65
+ interface OnRouteChangeEventType {
83
66
  reason: string;
84
67
  }
68
+
69
+ interface RemoteCommands {
70
+ play: RemoteEmptyType;
71
+ pause: RemoteEmptyType;
72
+ stop: RemoteEmptyType;
73
+ togglePlayPause: RemoteEmptyType;
74
+ changePlaybackRate: RemoteEmptyType;
75
+ nextTrack: RemoteEmptyType;
76
+ previousTrack: RemoteEmptyType;
77
+ skipForward: RemoteEmptyType;
78
+ skipBackward: RemoteEmptyType;
79
+ seekForward: RemoteEmptyType;
80
+ seekBackward: RemoteEmptyType;
81
+ changePlaybackPosition: RemoteEmptyType;
82
+ }
83
+
84
+ interface RemoteEvents {
85
+ volumeChange: RemoteControlEventType;
86
+ interruption: OnInterruptionEventType;
87
+ routeChange: OnRouteChangeEventType;
88
+ }
89
+
90
+ export type RemoteCommandName = keyof RemoteCommands;
91
+ export type RemoteEventName = keyof RemoteEvents;
92
+ export type RemoteEventCallback<Name extends RemoteEventName> = (
93
+ event: RemoteEvents[Name]
94
+ ) => void;
package/src/types.ts CHANGED
@@ -35,8 +35,21 @@ export interface OfflineAudioContextOptions {
35
35
  sampleRate: number;
36
36
  }
37
37
 
38
+ export interface AudioRecorderOptions {
39
+ sampleRate: number;
40
+ bufferLengthInSamples: number;
41
+ }
42
+
38
43
  export type WindowType = 'blackman' | 'hann';
39
44
 
40
45
  export interface AudioBufferSourceNodeOptions {
41
46
  pitchCorrection: boolean;
42
47
  }
48
+
49
+ export type AudioRecorderStatus =
50
+ | 'idle'
51
+ | 'initializing'
52
+ | 'ready'
53
+ | 'running'
54
+ | 'stopping'
55
+ | 'error';