react-native-audio-api 0.6.1-rc.1 → 0.6.1-rc.10

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 (159) hide show
  1. package/README.md +6 -11
  2. package/android/src/main/cpp/audioapi/android/core/AudioPlayer.cpp +13 -8
  3. package/android/src/main/cpp/audioapi/android/core/AudioPlayer.h +3 -2
  4. package/android/src/main/java/com/swmansion/audioapi/AudioAPIModule.kt +27 -10
  5. package/android/src/main/java/com/swmansion/audioapi/system/LockScreenManager.kt +12 -3
  6. package/android/src/main/java/com/swmansion/audioapi/system/MediaNotificationManager.kt +2 -2
  7. package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionCallback.kt +4 -6
  8. package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionManager.kt +1 -1
  9. package/android/src/main/res/drawable/skip_backward_10.xml +9 -0
  10. package/android/src/main/res/drawable/skip_forward_10.xml +9 -0
  11. package/android/src/oldarch/NativeAudioAPIModuleSpec.java +68 -64
  12. package/common/cpp/audioapi/AudioAPIModuleInstaller.h +2 -1
  13. package/common/cpp/audioapi/HostObjects/AudioBufferQueueSourceNodeHostObject.h +94 -0
  14. package/common/cpp/audioapi/HostObjects/AudioContextHostObject.h +7 -7
  15. package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.h +9 -0
  16. package/common/cpp/audioapi/core/AudioContext.cpp +29 -4
  17. package/common/cpp/audioapi/core/AudioContext.h +2 -1
  18. package/common/cpp/audioapi/core/BaseAudioContext.cpp +12 -0
  19. package/common/cpp/audioapi/core/BaseAudioContext.h +4 -3
  20. package/common/cpp/audioapi/core/sources/AudioBuffer.h +1 -0
  21. package/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.cpp +236 -0
  22. package/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.h +72 -0
  23. package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.h +1 -1
  24. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +2 -2
  25. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +3 -4
  26. package/common/cpp/audioapi/events/AudioEventHandlerRegistry.h +2 -1
  27. package/ios/audioapi/ios/AudioAPIModule.mm +23 -11
  28. package/ios/audioapi/ios/core/IOSAudioPlayer.h +3 -2
  29. package/ios/audioapi/ios/core/IOSAudioPlayer.mm +21 -10
  30. package/ios/audioapi/ios/core/NativeAudioPlayer.h +4 -0
  31. package/ios/audioapi/ios/core/NativeAudioPlayer.m +15 -0
  32. package/ios/audioapi/ios/system/AudioEngine.h +1 -0
  33. package/ios/audioapi/ios/system/AudioEngine.mm +11 -1
  34. package/ios/audioapi/ios/system/AudioSessionManager.mm +1 -1
  35. package/ios/audioapi/ios/system/LockScreenManager.mm +13 -1
  36. package/ios/audioapi/ios/system/NotificationManager.mm +1 -1
  37. package/lib/commonjs/api.js +7 -0
  38. package/lib/commonjs/api.js.map +1 -1
  39. package/lib/commonjs/core/AudioBufferQueueSourceNode.js +46 -0
  40. package/lib/commonjs/core/AudioBufferQueueSourceNode.js.map +1 -0
  41. package/lib/commonjs/core/AudioContext.js +2 -2
  42. package/lib/commonjs/core/AudioContext.js.map +1 -1
  43. package/lib/commonjs/core/AudioNode.js +5 -1
  44. package/lib/commonjs/core/AudioNode.js.map +1 -1
  45. package/lib/commonjs/core/AudioScheduledSourceNode.js.map +1 -1
  46. package/lib/commonjs/core/BaseAudioContext.js +4 -0
  47. package/lib/commonjs/core/BaseAudioContext.js.map +1 -1
  48. package/lib/commonjs/hooks/useSytemVolume.js +1 -1
  49. package/lib/commonjs/hooks/useSytemVolume.js.map +1 -1
  50. package/lib/commonjs/plugin/withAudioAPI.js +15 -14
  51. package/lib/commonjs/plugin/withAudioAPI.js.map +1 -1
  52. package/lib/commonjs/specs/NativeAudioAPIModule.js.map +1 -1
  53. package/lib/commonjs/system/AudioManager.js +12 -10
  54. package/lib/commonjs/system/AudioManager.js.map +1 -1
  55. package/lib/commonjs/web-core/AudioBufferSourceNode.js +4 -4
  56. package/lib/commonjs/web-core/AudioBufferSourceNode.js.map +1 -1
  57. package/lib/commonjs/web-core/AudioContext.js +5 -3
  58. package/lib/commonjs/web-core/AudioContext.js.map +1 -1
  59. package/lib/commonjs/web-core/AudioNode.js +8 -2
  60. package/lib/commonjs/web-core/AudioNode.js.map +1 -1
  61. package/lib/commonjs/web-core/AudioParam.js +2 -1
  62. package/lib/commonjs/web-core/AudioParam.js.map +1 -1
  63. package/lib/commonjs/web-core/BiquadFilterNode.js +4 -4
  64. package/lib/commonjs/web-core/BiquadFilterNode.js.map +1 -1
  65. package/lib/commonjs/web-core/GainNode.js +1 -1
  66. package/lib/commonjs/web-core/GainNode.js.map +1 -1
  67. package/lib/commonjs/web-core/OscillatorNode.js +2 -2
  68. package/lib/commonjs/web-core/OscillatorNode.js.map +1 -1
  69. package/lib/commonjs/web-core/StereoPannerNode.js +1 -1
  70. package/lib/commonjs/web-core/StereoPannerNode.js.map +1 -1
  71. package/lib/module/api.js +1 -0
  72. package/lib/module/api.js.map +1 -1
  73. package/lib/module/core/AudioBufferQueueSourceNode.js +40 -0
  74. package/lib/module/core/AudioBufferQueueSourceNode.js.map +1 -0
  75. package/lib/module/core/AudioContext.js +2 -2
  76. package/lib/module/core/AudioContext.js.map +1 -1
  77. package/lib/module/core/AudioNode.js +5 -1
  78. package/lib/module/core/AudioNode.js.map +1 -1
  79. package/lib/module/core/AudioScheduledSourceNode.js.map +1 -1
  80. package/lib/module/core/BaseAudioContext.js +4 -0
  81. package/lib/module/core/BaseAudioContext.js.map +1 -1
  82. package/lib/module/hooks/useSytemVolume.js +1 -1
  83. package/lib/module/hooks/useSytemVolume.js.map +1 -1
  84. package/lib/module/plugin/withAudioAPI.js +15 -14
  85. package/lib/module/plugin/withAudioAPI.js.map +1 -1
  86. package/lib/module/specs/NativeAudioAPIModule.js.map +1 -1
  87. package/lib/module/system/AudioManager.js +12 -10
  88. package/lib/module/system/AudioManager.js.map +1 -1
  89. package/lib/module/web-core/AudioBufferSourceNode.js +4 -4
  90. package/lib/module/web-core/AudioBufferSourceNode.js.map +1 -1
  91. package/lib/module/web-core/AudioContext.js +5 -3
  92. package/lib/module/web-core/AudioContext.js.map +1 -1
  93. package/lib/module/web-core/AudioNode.js +7 -2
  94. package/lib/module/web-core/AudioNode.js.map +1 -1
  95. package/lib/module/web-core/AudioParam.js +2 -1
  96. package/lib/module/web-core/AudioParam.js.map +1 -1
  97. package/lib/module/web-core/BiquadFilterNode.js +4 -4
  98. package/lib/module/web-core/BiquadFilterNode.js.map +1 -1
  99. package/lib/module/web-core/GainNode.js +1 -1
  100. package/lib/module/web-core/GainNode.js.map +1 -1
  101. package/lib/module/web-core/OscillatorNode.js +2 -2
  102. package/lib/module/web-core/OscillatorNode.js.map +1 -1
  103. package/lib/module/web-core/StereoPannerNode.js +1 -1
  104. package/lib/module/web-core/StereoPannerNode.js.map +1 -1
  105. package/lib/typescript/api.d.ts +2 -1
  106. package/lib/typescript/api.d.ts.map +1 -1
  107. package/lib/typescript/core/AudioBufferQueueSourceNode.d.ts +16 -0
  108. package/lib/typescript/core/AudioBufferQueueSourceNode.d.ts.map +1 -0
  109. package/lib/typescript/core/AudioContext.d.ts.map +1 -1
  110. package/lib/typescript/core/AudioNode.d.ts +1 -1
  111. package/lib/typescript/core/AudioNode.d.ts.map +1 -1
  112. package/lib/typescript/core/AudioScheduledSourceNode.d.ts +4 -3
  113. package/lib/typescript/core/AudioScheduledSourceNode.d.ts.map +1 -1
  114. package/lib/typescript/core/BaseAudioContext.d.ts +2 -0
  115. package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
  116. package/lib/typescript/events/types.d.ts +18 -9
  117. package/lib/typescript/events/types.d.ts.map +1 -1
  118. package/lib/typescript/hooks/useSytemVolume.d.ts.map +1 -1
  119. package/lib/typescript/interfaces.d.ts +9 -0
  120. package/lib/typescript/interfaces.d.ts.map +1 -1
  121. package/lib/typescript/plugin/withAudioAPI.d.ts +7 -6
  122. package/lib/typescript/plugin/withAudioAPI.d.ts.map +1 -1
  123. package/lib/typescript/specs/NativeAudioAPIModule.d.ts +3 -2
  124. package/lib/typescript/specs/NativeAudioAPIModule.d.ts.map +1 -1
  125. package/lib/typescript/system/AudioManager.d.ts +6 -4
  126. package/lib/typescript/system/AudioManager.d.ts.map +1 -1
  127. package/lib/typescript/types.d.ts +2 -1
  128. package/lib/typescript/types.d.ts.map +1 -1
  129. package/lib/typescript/web-core/AudioBufferSourceNode.d.ts.map +1 -1
  130. package/lib/typescript/web-core/AudioContext.d.ts +1 -1
  131. package/lib/typescript/web-core/AudioContext.d.ts.map +1 -1
  132. package/lib/typescript/web-core/AudioNode.d.ts +2 -1
  133. package/lib/typescript/web-core/AudioNode.d.ts.map +1 -1
  134. package/lib/typescript/web-core/AudioParam.d.ts +4 -2
  135. package/lib/typescript/web-core/AudioParam.d.ts.map +1 -1
  136. package/package.json +2 -1
  137. package/src/api.ts +5 -1
  138. package/src/core/AudioBufferQueueSourceNode.ts +71 -0
  139. package/src/core/AudioContext.ts +7 -2
  140. package/src/core/AudioNode.ts +6 -2
  141. package/src/core/AudioScheduledSourceNode.ts +3 -3
  142. package/src/core/BaseAudioContext.ts +8 -0
  143. package/src/events/types.ts +29 -9
  144. package/src/hooks/useSytemVolume.ts +6 -3
  145. package/src/interfaces.ts +18 -0
  146. package/src/plugin/withAudioAPI.ts +36 -29
  147. package/src/specs/NativeAudioAPIModule.ts +14 -6
  148. package/src/system/AudioManager.ts +21 -16
  149. package/src/types.ts +2 -1
  150. package/src/web-core/AudioBufferSourceNode.tsx +9 -4
  151. package/src/web-core/AudioContext.tsx +7 -3
  152. package/src/web-core/AudioNode.tsx +10 -3
  153. package/src/web-core/AudioParam.tsx +5 -2
  154. package/src/web-core/BiquadFilterNode.tsx +4 -4
  155. package/src/web-core/GainNode.tsx +1 -1
  156. package/src/web-core/OscillatorNode.tsx +2 -2
  157. package/src/web-core/StereoPannerNode.tsx +1 -1
  158. package/android/src/main/res/drawable/skip_backward_5.xml +0 -9
  159. package/android/src/main/res/drawable/skip_forward_5.xml +0 -9
@@ -6,7 +6,11 @@ import { NotSupportedError } from '../errors';
6
6
 
7
7
  export default class AudioContext extends BaseAudioContext {
8
8
  constructor(options?: AudioContextOptions) {
9
- if (options && (options.sampleRate < 8000 || options.sampleRate > 96000)) {
9
+ if (
10
+ options &&
11
+ options.sampleRate &&
12
+ (options.sampleRate < 8000 || options.sampleRate > 96000)
13
+ ) {
10
14
  throw new NotSupportedError(
11
15
  `The provided sampleRate is not supported: ${options.sampleRate}`
12
16
  );
@@ -14,7 +18,8 @@ export default class AudioContext extends BaseAudioContext {
14
18
 
15
19
  super(
16
20
  global.createAudioContext(
17
- options?.sampleRate || AudioManager.getDevicePreferredSampleRate()
21
+ options?.sampleRate || AudioManager.getDevicePreferredSampleRate(),
22
+ options?.initSuspended || false
18
23
  )
19
24
  );
20
25
  }
@@ -39,7 +39,11 @@ export default class AudioNode {
39
39
  return destination;
40
40
  }
41
41
 
42
- public disconnect(destination?: AudioNode): void {
43
- this.node.disconnect(destination?.node);
42
+ public disconnect(destination?: AudioNode | AudioParam): void {
43
+ if (destination instanceof AudioParam) {
44
+ this.node.disconnect(destination.audioParam);
45
+ } else {
46
+ this.node.disconnect(destination?.node);
47
+ }
44
48
  }
45
49
  }
@@ -1,12 +1,12 @@
1
1
  import { IAudioScheduledSourceNode } from '../interfaces';
2
2
  import AudioNode from './AudioNode';
3
3
  import { InvalidStateError, RangeError } from '../errors';
4
- import { EventTypeWithValueAndState } from '../events/types';
4
+ import { OnEndedEventType } from '../events/types';
5
5
  import { AudioEventEmitter } from '../events';
6
6
 
7
7
  export default class AudioScheduledSourceNode extends AudioNode {
8
8
  protected hasBeenStarted: boolean = false;
9
- private readonly audioEventEmitter = new AudioEventEmitter(
9
+ protected readonly audioEventEmitter = new AudioEventEmitter(
10
10
  global.AudioEventEmitter
11
11
  );
12
12
 
@@ -42,7 +42,7 @@ export default class AudioScheduledSourceNode extends AudioNode {
42
42
  }
43
43
 
44
44
  // eslint-disable-next-line accessor-pairs
45
- public set onended(callback: (event: EventTypeWithValueAndState) => void) {
45
+ public set onended(callback: (event: OnEndedEventType) => void) {
46
46
  const subscription = this.audioEventEmitter.addAudioEventListener(
47
47
  'ended',
48
48
  callback
@@ -13,6 +13,7 @@ import AudioBufferSourceNode from './AudioBufferSourceNode';
13
13
  import AudioBuffer from './AudioBuffer';
14
14
  import PeriodicWave from './PeriodicWave';
15
15
  import AnalyserNode from './AnalyserNode';
16
+ import AudioBufferQueueSourceNode from './AudioBufferQueueSourceNode';
16
17
  import { InvalidAccessError, NotSupportedError } from '../errors';
17
18
 
18
19
  export default class BaseAudioContext {
@@ -61,6 +62,13 @@ export default class BaseAudioContext {
61
62
  );
62
63
  }
63
64
 
65
+ createBufferQueueSource(): AudioBufferQueueSourceNode {
66
+ return new AudioBufferQueueSourceNode(
67
+ this,
68
+ this.context.createBufferQueueSource()
69
+ );
70
+ }
71
+
64
72
  createBuffer(
65
73
  numOfChannels: number,
66
74
  length: number,
@@ -6,9 +6,15 @@ export interface EventTypeWithValue {
6
6
  value: number;
7
7
  }
8
8
 
9
- export interface EventTypeWithValueAndState {
9
+ export interface OnEndedEventType {
10
10
  value: number;
11
11
  state: 'stopped' | 'ended';
12
+ bufferId: number | undefined;
13
+ }
14
+
15
+ export interface OnPositionChangedEventType {
16
+ value: number;
17
+ bufferId: number;
12
18
  }
13
19
 
14
20
  interface OnInterruptionEventType {
@@ -17,10 +23,18 @@ interface OnInterruptionEventType {
17
23
  }
18
24
 
19
25
  interface OnRouteChangeEventType {
20
- reason: string;
26
+ reason:
27
+ | 'Unknown'
28
+ | 'Override'
29
+ | 'CategoryChange'
30
+ | 'WakeFromSleep'
31
+ | 'NewDeviceAvailable'
32
+ | 'OldDeviceUnavailable'
33
+ | 'ConfigurationChange'
34
+ | 'NoSuitableRouteForCategory';
21
35
  }
22
36
 
23
- interface SystemEvents {
37
+ interface RemoteCommandEvents {
24
38
  remotePlay: EventEmptyType;
25
39
  remotePause: EventEmptyType;
26
40
  remoteStop: EventEmptyType;
@@ -28,15 +42,18 @@ interface SystemEvents {
28
42
  remoteChangePlaybackRate: EventTypeWithValue;
29
43
  remoteNextTrack: EventEmptyType;
30
44
  remotePreviousTrack: EventEmptyType;
31
- remoteSkipForward: EventEmptyType;
32
- remoteSkipBackward: EventEmptyType;
33
- remoteSeekForward: EventTypeWithValue;
34
- remoteSeekBackward: EventTypeWithValue;
45
+ remoteSkipForward: EventTypeWithValue;
46
+ remoteSkipBackward: EventTypeWithValue;
47
+ remoteSeekForward: EventEmptyType;
48
+ remoteSeekBackward: EventEmptyType;
35
49
  remoteChangePlaybackPosition: EventTypeWithValue;
50
+ }
51
+
52
+ type SystemEvents = RemoteCommandEvents & {
36
53
  volumeChange: EventTypeWithValue;
37
54
  interruption: OnInterruptionEventType;
38
55
  routeChange: OnRouteChangeEventType;
39
- }
56
+ };
40
57
 
41
58
  export interface OnAudioReadyEventType {
42
59
  buffer: AudioBuffer;
@@ -45,14 +62,17 @@ export interface OnAudioReadyEventType {
45
62
  }
46
63
 
47
64
  interface AudioAPIEvents {
48
- ended: EventTypeWithValueAndState;
65
+ ended: OnEndedEventType;
49
66
  audioReady: OnAudioReadyEventType;
67
+ positionChanged: OnPositionChangedEventType;
50
68
  audioError: EventEmptyType; // to change
51
69
  systemStateChanged: EventEmptyType; // to change
52
70
  }
53
71
 
54
72
  type AudioEvents = SystemEvents & AudioAPIEvents;
55
73
 
74
+ export type RemoteCommandEventName = keyof RemoteCommandEvents;
75
+
56
76
  export type SystemEventName = keyof SystemEvents;
57
77
  export type SystemEventCallback<Name extends SystemEventName> = (
58
78
  event: SystemEvents[Name]
@@ -6,9 +6,12 @@ export default function useSystemVolume() {
6
6
 
7
7
  useEffect(() => {
8
8
  AudioManager.observeVolumeChanges(true);
9
- const listener = AudioManager.enableSystemEvent('volumeChange', (e) => {
10
- setVolume(parseFloat(e.value.toFixed(2)));
11
- });
9
+ const listener = AudioManager.addSystemEventListener(
10
+ 'volumeChange',
11
+ (e) => {
12
+ setVolume(parseFloat(e.value.toFixed(2)));
13
+ }
14
+ );
12
15
  return () => {
13
16
  listener?.remove();
14
17
 
package/src/interfaces.ts CHANGED
@@ -19,6 +19,7 @@ export interface IBaseAudioContext {
19
19
  createStereoPanner(): IStereoPannerNode;
20
20
  createBiquadFilter: () => IBiquadFilterNode;
21
21
  createBufferSource: (pitchCorrection: boolean) => IAudioBufferSourceNode;
22
+ createBufferQueueSource: () => IAudioBufferQueueSourceNode;
22
23
  createBuffer: (
23
24
  channels: number,
24
25
  length: number,
@@ -109,6 +110,23 @@ export interface IAudioBufferSourceNode extends IAudioScheduledSourceNode {
109
110
  start: (when?: number, offset?: number, duration?: number) => void;
110
111
  }
111
112
 
113
+ export interface IAudioBufferQueueSourceNode extends IAudioScheduledSourceNode {
114
+ detune: IAudioParam;
115
+ playbackRate: IAudioParam;
116
+
117
+ enqueueBuffer: (
118
+ audioBuffer: IAudioBuffer,
119
+ bufferId: number,
120
+ isLastBuffer: boolean
121
+ ) => void;
122
+ start: (when?: number, offset?: number) => void;
123
+
124
+ // passing subscriptionId(uint_64 in cpp, string in js) to the cpp
125
+ onPositionChanged: string;
126
+ // set how often the onPositionChanged event is called
127
+ onPositionChangedInterval: number;
128
+ }
129
+
112
130
  export interface IAudioBuffer {
113
131
  readonly length: number;
114
132
  readonly duration: number;
@@ -5,9 +5,28 @@ import {
5
5
  withInfoPlist,
6
6
  withAndroidManifest,
7
7
  } from '@expo/config-plugins';
8
-
9
8
  const pkg = require('react-native-audio-api/package.json');
10
9
 
10
+ interface Options {
11
+ iosBackgroundMode: boolean;
12
+ androidForegroundService: boolean;
13
+ androidFSPermissions: string[];
14
+ androidFSTypes: string[];
15
+ }
16
+
17
+ const withDefaultOptions = (options: Partial<Options>): Options => {
18
+ return {
19
+ iosBackgroundMode: true,
20
+ androidForegroundService: true,
21
+ androidFSPermissions: [
22
+ 'android.permission.FOREGROUND_SERVICE',
23
+ 'android.permission.WAKE_LOCK',
24
+ ],
25
+ androidFSTypes: ['mediaPlayback'],
26
+ ...options,
27
+ };
28
+ };
29
+
11
30
  const withBackgroundAudio: ConfigPlugin = (config) => {
12
31
  return withInfoPlist(config, (iosConfig) => {
13
32
  iosConfig.modResults.UIBackgroundModes = [
@@ -20,18 +39,20 @@ const withBackgroundAudio: ConfigPlugin = (config) => {
20
39
  });
21
40
  };
22
41
 
23
- const withAndroidPermissions: ConfigPlugin<{
24
- androidFSPermissions: string[];
25
- }> = (config, { androidFSPermissions }) => {
42
+ const withAndroidPermissions: ConfigPlugin<Options> = (
43
+ config,
44
+ { androidFSPermissions }: Options
45
+ ) => {
26
46
  return AndroidConfig.Permissions.withPermissions(
27
47
  config,
28
48
  androidFSPermissions
29
49
  );
30
50
  };
31
51
 
32
- const withForegroundService: ConfigPlugin<{
33
- androidFSTypes: string[];
34
- }> = (config, { androidFSTypes }) => {
52
+ const withForegroundService: ConfigPlugin<Options> = (
53
+ config,
54
+ { androidFSTypes }: Options
55
+ ) => {
35
56
  return withAndroidManifest(config, (mod) => {
36
57
  const manifest = mod.modResults;
37
58
  const mainApplication =
@@ -59,30 +80,16 @@ const withForegroundService: ConfigPlugin<{
59
80
  });
60
81
  };
61
82
 
62
- const withAudioAPI: ConfigPlugin<{
63
- iosBackgroundMode?: boolean;
64
- androidForegroundService?: boolean;
65
- androidFSPermissions?: string[];
66
- androidFSTypes?: string[];
67
- }> = (
68
- config,
69
- {
70
- iosBackgroundMode = true,
71
- androidForegroundService = true,
72
- androidFSPermissions = [],
73
- androidFSTypes = [],
74
- }
75
- ) => {
76
- if (iosBackgroundMode) {
83
+ const withAudioAPI: ConfigPlugin<Options> = (config, optionsIn) => {
84
+ const options = withDefaultOptions(optionsIn ?? {});
85
+
86
+ if (options.iosBackgroundMode) {
77
87
  config = withBackgroundAudio(config);
78
88
  }
79
- if (androidForegroundService) {
80
- config = withAndroidPermissions(config, {
81
- androidFSPermissions,
82
- });
83
- config = withForegroundService(config, {
84
- androidFSTypes,
85
- });
89
+
90
+ if (options.androidForegroundService) {
91
+ config = withAndroidPermissions(config, options);
92
+ config = withForegroundService(config, options);
86
93
  }
87
94
 
88
95
  return config;
@@ -5,20 +5,28 @@ import { PermissionStatus } from '../system/types';
5
5
 
6
6
  interface Spec extends TurboModule {
7
7
  install(): boolean;
8
+ getDevicePreferredSampleRate(): number;
8
9
 
9
- setLockScreenInfo(info: {
10
- [key: string]: string | boolean | number | undefined;
11
- }): void;
12
- resetLockScreenInfo(): void;
13
- enableRemoteCommand(name: string, enabled: boolean): void;
10
+ // AVAudioSession management
11
+ setAudioSessionActivity(enabled: boolean): Promise<boolean>;
14
12
  setAudioSessionOptions(
15
13
  category: string,
16
14
  mode: string,
17
15
  options: Array<string>
18
16
  ): void;
19
- getDevicePreferredSampleRate(): number;
17
+
18
+ // Lock Screen Info
19
+ setLockScreenInfo(info: {
20
+ [key: string]: string | boolean | number | undefined;
21
+ }): void;
22
+ resetLockScreenInfo(): void;
23
+
24
+ // Remote commands, system events and interruptions
25
+ enableRemoteCommand(name: string, enabled: boolean): void;
20
26
  observeAudioInterruptions(enabled: boolean): void;
21
27
  observeVolumeChanges(enabled: boolean): void;
28
+
29
+ // Permissions
22
30
  requestRecordingPermissions(): Promise<PermissionStatus>;
23
31
  checkRecordingPermissions(): Promise<PermissionStatus>;
24
32
  }
@@ -1,5 +1,9 @@
1
1
  import { SessionOptions, LockScreenInfo, PermissionStatus } from './types';
2
- import { SystemEventName, SystemEventCallback } from '../events/types';
2
+ import {
3
+ SystemEventName,
4
+ SystemEventCallback,
5
+ RemoteCommandEventName,
6
+ } from '../events/types';
3
7
  import { NativeAudioAPIModule } from '../specs';
4
8
  import { AudioEventEmitter, AudioEventSubscription } from '../events';
5
9
 
@@ -19,12 +23,12 @@ class AudioManager {
19
23
  this.audioEventEmitter = new AudioEventEmitter(global.AudioEventEmitter);
20
24
  }
21
25
 
22
- setLockScreenInfo(info: LockScreenInfo) {
23
- NativeAudioAPIModule!.setLockScreenInfo(info);
26
+ getDevicePreferredSampleRate(): number {
27
+ return NativeAudioAPIModule!.getDevicePreferredSampleRate();
24
28
  }
25
29
 
26
- resetLockScreenInfo() {
27
- NativeAudioAPIModule!.resetLockScreenInfo();
30
+ setAudioSessionActivity(enabled: boolean): Promise<boolean> {
31
+ return NativeAudioAPIModule!.setAudioSessionActivity(enabled);
28
32
  }
29
33
 
30
34
  setAudioSessionOptions(options: SessionOptions) {
@@ -35,8 +39,12 @@ class AudioManager {
35
39
  );
36
40
  }
37
41
 
38
- getDevicePreferredSampleRate(): number {
39
- return NativeAudioAPIModule!.getDevicePreferredSampleRate();
42
+ setLockScreenInfo(info: LockScreenInfo) {
43
+ NativeAudioAPIModule!.setLockScreenInfo(info);
44
+ }
45
+
46
+ resetLockScreenInfo() {
47
+ NativeAudioAPIModule!.resetLockScreenInfo();
40
48
  }
41
49
 
42
50
  observeAudioInterruptions(enabled: boolean) {
@@ -47,17 +55,14 @@ class AudioManager {
47
55
  NativeAudioAPIModule!.observeVolumeChanges(enabled);
48
56
  }
49
57
 
50
- enableSystemEvent<Name extends SystemEventName>(
51
- name: Name,
52
- callback?: SystemEventCallback<Name>,
53
- enabled = true
54
- ): AudioEventSubscription | null {
58
+ enableRemoteCommand(name: RemoteCommandEventName, enabled: boolean) {
55
59
  NativeAudioAPIModule!.enableRemoteCommand(name, enabled);
60
+ }
56
61
 
57
- if (!enabled || !callback) {
58
- return null;
59
- }
60
-
62
+ addSystemEventListener<Name extends SystemEventName>(
63
+ name: Name,
64
+ callback: SystemEventCallback<Name>
65
+ ): AudioEventSubscription {
61
66
  return this.audioEventEmitter.addAudioEventListener(name, callback);
62
67
  }
63
68
 
package/src/types.ts CHANGED
@@ -26,7 +26,8 @@ export interface PeriodicWaveConstraints {
26
26
  }
27
27
 
28
28
  export interface AudioContextOptions {
29
- sampleRate: number;
29
+ sampleRate?: number;
30
+ initSuspended?: boolean;
30
31
  }
31
32
 
32
33
  export interface OfflineAudioContextOptions {
@@ -210,7 +210,8 @@ export default class AudioBufferSourceNode<
210
210
  -1200,
211
211
  1200,
212
212
  0
213
- )
213
+ ),
214
+ context
214
215
  );
215
216
 
216
217
  this.playbackRate = new AudioParam(
@@ -221,11 +222,15 @@ export default class AudioBufferSourceNode<
221
222
  0,
222
223
  Infinity,
223
224
  1
224
- )
225
+ ),
226
+ context
225
227
  );
226
228
  } else {
227
- this.detune = new AudioParam((node as DefaultSource).detune);
228
- this.playbackRate = new AudioParam((node as DefaultSource).playbackRate);
229
+ this.detune = new AudioParam((node as DefaultSource).detune, context);
230
+ this.playbackRate = new AudioParam(
231
+ (node as DefaultSource).playbackRate,
232
+ context
233
+ );
229
234
  }
230
235
  }
231
236
 
@@ -24,14 +24,18 @@ export default class AudioContext implements BaseAudioContext {
24
24
  readonly destination: AudioDestinationNode;
25
25
  readonly sampleRate: number;
26
26
 
27
- constructor(options?: AudioContextOptions) {
28
- if (options && (options.sampleRate < 8000 || options.sampleRate > 96000)) {
27
+ constructor(options?: AudioContextOptions, _initSuspended: boolean = false) {
28
+ if (
29
+ options &&
30
+ options.sampleRate &&
31
+ (options.sampleRate < 8000 || options.sampleRate > 96000)
32
+ ) {
29
33
  throw new NotSupportedError(
30
34
  `The provided sampleRate is not supported: ${options.sampleRate}`
31
35
  );
32
36
  }
33
37
 
34
- this.context = new window.AudioContext(options);
38
+ this.context = new window.AudioContext({ sampleRate: options?.sampleRate });
35
39
 
36
40
  this.sampleRate = this.context.sampleRate;
37
41
  this.destination = new AudioDestinationNode(this, this.context.destination);
@@ -1,5 +1,6 @@
1
1
  import BaseAudioContext from './BaseAudioContext';
2
2
  import { ChannelCountMode, ChannelInterpretation } from '../types';
3
+ import AudioParam from './AudioParam';
3
4
 
4
5
  export default class AudioNode {
5
6
  readonly context: BaseAudioContext;
@@ -21,12 +22,18 @@ export default class AudioNode {
21
22
  this.channelInterpretation = this.node.channelInterpretation;
22
23
  }
23
24
 
24
- public connect(destination: AudioNode): AudioNode {
25
+ public connect(destination: AudioNode | AudioParam): AudioNode | AudioParam {
25
26
  if (this.context !== destination.context) {
26
- throw new Error('The AudioNodes are from different BaseAudioContexts');
27
+ throw new Error(
28
+ 'Source and destination are from different BaseAudioContexts'
29
+ );
27
30
  }
28
31
 
29
- this.node.connect(destination.node);
32
+ if (destination instanceof AudioParam) {
33
+ this.node.connect(destination.param);
34
+ } else {
35
+ this.node.connect(destination.node);
36
+ }
30
37
 
31
38
  return destination;
32
39
  }
@@ -1,17 +1,20 @@
1
1
  import { RangeError, InvalidStateError } from '../errors';
2
+ import BaseAudioContext from './BaseAudioContext';
2
3
 
3
4
  export default class AudioParam {
4
5
  readonly defaultValue: number;
5
6
  readonly minValue: number;
6
7
  readonly maxValue: number;
8
+ readonly context: BaseAudioContext;
7
9
 
8
- private readonly param: globalThis.AudioParam;
10
+ readonly param: globalThis.AudioParam;
9
11
 
10
- constructor(param: globalThis.AudioParam) {
12
+ constructor(param: globalThis.AudioParam, context: BaseAudioContext) {
11
13
  this.param = param;
12
14
  this.defaultValue = param.defaultValue;
13
15
  this.minValue = param.minValue;
14
16
  this.maxValue = param.maxValue;
17
+ this.context = context;
15
18
  }
16
19
 
17
20
  public get value(): number {
@@ -15,10 +15,10 @@ export default class BiquadFilterNode extends AudioNode {
15
15
  biquadFilter: globalThis.BiquadFilterNode
16
16
  ) {
17
17
  super(context, biquadFilter);
18
- this.frequency = new AudioParam(biquadFilter.frequency);
19
- this.detune = new AudioParam(biquadFilter.detune);
20
- this.Q = new AudioParam(biquadFilter.Q);
21
- this.gain = new AudioParam(biquadFilter.gain);
18
+ this.frequency = new AudioParam(biquadFilter.frequency, context);
19
+ this.detune = new AudioParam(biquadFilter.detune, context);
20
+ this.Q = new AudioParam(biquadFilter.Q, context);
21
+ this.gain = new AudioParam(biquadFilter.gain, context);
22
22
  }
23
23
 
24
24
  public get type(): BiquadFilterType {
@@ -7,6 +7,6 @@ export default class GainNode extends AudioNode {
7
7
 
8
8
  constructor(context: BaseAudioContext, gain: globalThis.GainNode) {
9
9
  super(context, gain);
10
- this.gain = new AudioParam(gain.gain);
10
+ this.gain = new AudioParam(gain.gain, context);
11
11
  }
12
12
  }
@@ -12,8 +12,8 @@ export default class OscillatorNode extends AudioScheduledSourceNode {
12
12
  constructor(context: BaseAudioContext, node: globalThis.OscillatorNode) {
13
13
  super(context, node);
14
14
 
15
- this.detune = new AudioParam(node.detune);
16
- this.frequency = new AudioParam(node.frequency);
15
+ this.detune = new AudioParam(node.detune, context);
16
+ this.frequency = new AudioParam(node.frequency, context);
17
17
  }
18
18
 
19
19
  public get type(): OscillatorType {
@@ -7,6 +7,6 @@ export default class StereoPannerNode extends AudioNode {
7
7
 
8
8
  constructor(context: BaseAudioContext, pan: globalThis.StereoPannerNode) {
9
9
  super(context, pan);
10
- this.pan = new AudioParam(pan.pan);
10
+ this.pan = new AudioParam(pan.pan, context);
11
11
  }
12
12
  }
@@ -1,9 +0,0 @@
1
- <vector xmlns:android="http://schemas.android.com/apk/res/android"
2
- android:width="24dp"
3
- android:height="24dp"
4
- android:viewportWidth="24.0"
5
- android:viewportHeight="24.0">
6
- <path
7
- android:fillColor="#FFFFFFFF"
8
- android:pathData="M12,5L12,1L7,6l5,5L12,7c3.3,0 6,2.7 6,6s-2.7,6 -6,6 -6,-2.7 -6,-6L4,13c0,4.4 3.6,8 8,8s8,-3.6 8,-8 -3.6,-8 -8,-8zM10.7,13.9l0.2,-2.2h2.4v0.7h-1.7l-0.1,0.9s0.1,0 0.1,-0.1 0.1,0 0.1,-0.1 0.1,0 0.2,0h0.2c0.2,0 0.4,0 0.5,0.1s0.3,0.2 0.4,0.3 0.2,0.3 0.3,0.5 0.1,0.4 0.1,0.6c0,0.2 0,0.4 -0.1,0.5s-0.1,0.3 -0.3,0.5 -0.3,0.2 -0.4,0.3 -0.4,0.1 -0.6,0.1c-0.2,0 -0.4,0 -0.5,-0.1s-0.3,-0.1 -0.5,-0.2 -0.2,-0.2 -0.3,-0.4 -0.1,-0.3 -0.1,-0.5h0.8c0,0.2 0.1,0.3 0.2,0.4s0.2,0.1 0.4,0.1c0.1,0 0.2,0 0.3,-0.1l0.2,-0.2s0.1,-0.2 0.1,-0.3v-0.6l-0.1,-0.2 -0.2,-0.2s-0.2,-0.1 -0.3,-0.1h-0.2s-0.1,0 -0.2,0.1 -0.1,0 -0.1,0.1 -0.1,0.1 -0.1,0.1h-0.7z"/>
9
- </vector>
@@ -1,9 +0,0 @@
1
- <vector xmlns:android="http://schemas.android.com/apk/res/android"
2
- android:width="24dp"
3
- android:height="24dp"
4
- android:viewportWidth="24.0"
5
- android:viewportHeight="24.0">
6
- <path
7
- android:fillColor="#FFFFFFFF"
8
- android:pathData="M4,13c0,4.4 3.6,8 8,8s8,-3.6 8,-8h-2c0,3.3 -2.7,6 -6,6s-6,-2.7 -6,-6 2.7,-6 6,-6v4l5,-5 -5,-5v4c-4.4,0 -8,3.6 -8,8zM10.7,13.9l0.2,-2.2h2.4v0.7h-1.7l-0.1,0.9s0.1,0 0.1,-0.1 0.1,0 0.1,-0.1 0.1,0 0.2,0h0.2c0.2,0 0.4,0 0.5,0.1s0.3,0.2 0.4,0.3 0.2,0.3 0.3,0.5 0.1,0.4 0.1,0.6c0,0.2 0,0.4 -0.1,0.5s-0.1,0.3 -0.3,0.5 -0.3,0.2 -0.5,0.3 -0.4,0.1 -0.6,0.1c-0.2,0 -0.4,0 -0.5,-0.1s-0.3,-0.1 -0.5,-0.2 -0.2,-0.2 -0.3,-0.4 -0.1,-0.3 -0.1,-0.5h0.8c0,0.2 0.1,0.3 0.2,0.4s0.2,0.1 0.4,0.1c0.1,0 0.2,0 0.3,-0.1l0.2,-0.2s0.1,-0.2 0.1,-0.3v-0.6l-0.1,-0.2 -0.2,-0.2s-0.2,-0.1 -0.3,-0.1h-0.2s-0.1,0 -0.2,0.1 -0.1,0 -0.1,0.1 -0.1,0.1 -0.1,0.1h-0.6z"/>
9
- </vector>