react-native-audio-api 0.11.2 → 0.11.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 (89) hide show
  1. package/android/src/main/java/com/swmansion/audioapi/AudioAPIModule.kt +9 -0
  2. package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionManager.kt +2 -0
  3. package/android/src/oldarch/NativeAudioAPIModuleSpec.java +4 -0
  4. package/common/cpp/audioapi/HostObjects/inputs/AudioRecorderHostObject.cpp +2 -1
  5. package/common/cpp/audioapi/core/sources/StreamerNode.h +6 -0
  6. package/common/cpp/audioapi/jsi/JsiUtils.cpp +21 -0
  7. package/common/cpp/audioapi/jsi/JsiUtils.h +17 -0
  8. package/ios/audioapi/ios/AudioAPIModule.mm +9 -0
  9. package/ios/audioapi/ios/system/AudioEngine.mm +3 -1
  10. package/ios/audioapi/ios/system/AudioSessionManager.h +3 -0
  11. package/ios/audioapi/ios/system/AudioSessionManager.mm +38 -2
  12. package/lib/commonjs/api.js +8 -8
  13. package/lib/commonjs/api.js.map +1 -1
  14. package/lib/commonjs/core/AudioDecoder.js +2 -2
  15. package/lib/commonjs/core/AudioDecoder.js.map +1 -1
  16. package/lib/commonjs/core/AudioRecorder.js +1 -1
  17. package/lib/commonjs/core/AudioRecorder.js.map +1 -1
  18. package/lib/commonjs/hooks/index.js +21 -0
  19. package/lib/commonjs/hooks/index.js.map +1 -0
  20. package/lib/commonjs/hooks/useAudioInput.js +70 -0
  21. package/lib/commonjs/hooks/useAudioInput.js.map +1 -0
  22. package/lib/commonjs/hooks/useSystemVolume.js +4 -5
  23. package/lib/commonjs/hooks/useSystemVolume.js.map +1 -1
  24. package/lib/commonjs/index.js +11 -0
  25. package/lib/commonjs/index.js.map +1 -1
  26. package/lib/commonjs/specs/NativeAudioAPIModule.js.map +1 -1
  27. package/lib/commonjs/specs/NativeAudioAPIModule.web.js +1 -0
  28. package/lib/commonjs/specs/NativeAudioAPIModule.web.js.map +1 -1
  29. package/lib/commonjs/system/AudioManager.js +3 -0
  30. package/lib/commonjs/system/AudioManager.js.map +1 -1
  31. package/lib/commonjs/web-system/AudioManager.js +1 -0
  32. package/lib/commonjs/web-system/AudioManager.js.map +1 -1
  33. package/lib/module/api.js +2 -3
  34. package/lib/module/api.js.map +1 -1
  35. package/lib/module/core/AudioDecoder.js +2 -2
  36. package/lib/module/core/AudioDecoder.js.map +1 -1
  37. package/lib/module/core/AudioRecorder.js +1 -1
  38. package/lib/module/core/AudioRecorder.js.map +1 -1
  39. package/lib/module/hooks/index.js +5 -0
  40. package/lib/module/hooks/index.js.map +1 -0
  41. package/lib/module/hooks/useAudioInput.js +66 -0
  42. package/lib/module/hooks/useAudioInput.js.map +1 -0
  43. package/lib/module/hooks/useSystemVolume.js +1 -1
  44. package/lib/module/hooks/useSystemVolume.js.map +1 -1
  45. package/lib/module/index.js +5 -0
  46. package/lib/module/index.js.map +1 -1
  47. package/lib/module/specs/NativeAudioAPIModule.js.map +1 -1
  48. package/lib/module/specs/NativeAudioAPIModule.web.js +1 -0
  49. package/lib/module/specs/NativeAudioAPIModule.web.js.map +1 -1
  50. package/lib/module/system/AudioManager.js +3 -0
  51. package/lib/module/system/AudioManager.js.map +1 -1
  52. package/lib/module/web-system/AudioManager.js +1 -0
  53. package/lib/module/web-system/AudioManager.js.map +1 -1
  54. package/lib/typescript/api.d.ts +2 -3
  55. package/lib/typescript/api.d.ts.map +1 -1
  56. package/lib/typescript/core/AudioDecoder.d.ts.map +1 -1
  57. package/lib/typescript/events/types.d.ts +6 -4
  58. package/lib/typescript/events/types.d.ts.map +1 -1
  59. package/lib/typescript/hooks/index.d.ts +3 -0
  60. package/lib/typescript/hooks/index.d.ts.map +1 -0
  61. package/lib/typescript/hooks/useAudioInput.d.ts +28 -0
  62. package/lib/typescript/hooks/useAudioInput.d.ts.map +1 -0
  63. package/lib/typescript/hooks/useSystemVolume.d.ts.map +1 -1
  64. package/lib/typescript/index.d.ts +1 -0
  65. package/lib/typescript/index.d.ts.map +1 -1
  66. package/lib/typescript/specs/NativeAudioAPIModule.d.ts +2 -1
  67. package/lib/typescript/specs/NativeAudioAPIModule.d.ts.map +1 -1
  68. package/lib/typescript/specs/NativeAudioAPIModule.web.d.ts +1 -0
  69. package/lib/typescript/specs/NativeAudioAPIModule.web.d.ts.map +1 -1
  70. package/lib/typescript/system/AudioManager.d.ts +1 -0
  71. package/lib/typescript/system/AudioManager.d.ts.map +1 -1
  72. package/lib/typescript/system/types.d.ts +3 -1
  73. package/lib/typescript/system/types.d.ts.map +1 -1
  74. package/lib/typescript/web-system/AudioManager.d.ts +1 -0
  75. package/lib/typescript/web-system/AudioManager.d.ts.map +1 -1
  76. package/package.json +1 -1
  77. package/src/api.ts +5 -4
  78. package/src/core/AudioDecoder.ts +2 -2
  79. package/src/core/AudioRecorder.ts +1 -1
  80. package/src/events/types.ts +16 -12
  81. package/src/hooks/index.ts +2 -0
  82. package/src/hooks/useAudioInput.ts +93 -0
  83. package/src/hooks/useSystemVolume.ts +3 -2
  84. package/src/index.ts +5 -0
  85. package/src/specs/NativeAudioAPIModule.ts +2 -1
  86. package/src/specs/NativeAudioAPIModule.web.ts +2 -0
  87. package/src/system/AudioManager.ts +4 -0
  88. package/src/system/types.ts +3 -1
  89. package/src/web-system/AudioManager.ts +1 -0
package/src/api.ts CHANGED
@@ -20,6 +20,7 @@ export { default as DelayNode } from './core/DelayNode';
20
20
  export { default as GainNode } from './core/GainNode';
21
21
  export { default as OfflineAudioContext } from './core/OfflineAudioContext';
22
22
  export { default as OscillatorNode } from './core/OscillatorNode';
23
+ export { default as PeriodicWave } from './core/PeriodicWave';
23
24
  export { default as RecorderAdapterNode } from './core/RecorderAdapterNode';
24
25
  export { default as StereoPannerNode } from './core/StereoPannerNode';
25
26
  export { default as StreamerNode } from './core/StreamerNode';
@@ -27,8 +28,6 @@ export { default as WaveShaperNode } from './core/WaveShaperNode';
27
28
  export { default as WorkletNode } from './core/WorkletNode';
28
29
  export { default as WorkletProcessingNode } from './core/WorkletProcessingNode';
29
30
  export { default as WorkletSourceNode } from './core/WorkletSourceNode';
30
-
31
- export { default as useSystemVolume } from './hooks/useSystemVolume';
32
31
  export { default as AudioManager } from './system';
33
32
 
34
33
  export * from './errors';
@@ -37,8 +36,10 @@ export * from './types';
37
36
  export { default as FilePreset } from './utils/filePresets';
38
37
 
39
38
  // Notification System
40
- export { PlaybackNotificationManager } from './system/notification';
41
- export { RecordingNotificationManager } from './system/notification';
39
+ export {
40
+ PlaybackNotificationManager,
41
+ RecordingNotificationManager,
42
+ } from './system/notification';
42
43
 
43
44
  export {
44
45
  NotificationManager,
@@ -1,5 +1,6 @@
1
1
  import { Image } from 'react-native';
2
2
 
3
+ import { AudioApiError } from '../errors';
3
4
  import { IAudioDecoder } from '../interfaces';
4
5
  import { DecodeDataInput } from '../types';
5
6
  import {
@@ -8,7 +9,6 @@ import {
8
9
  isRemoteSource,
9
10
  } from '../utils/paths';
10
11
  import AudioBuffer from './AudioBuffer';
11
- import { AudioApiError } from '../errors';
12
12
 
13
13
  class AudioDecoder {
14
14
  private static instance: AudioDecoder | null = null;
@@ -62,7 +62,7 @@ class AudioDecoder {
62
62
  return new AudioBuffer(buffer);
63
63
  }
64
64
 
65
- if (!(typeof input === 'string')) {
65
+ if (!(typeof stringSource === 'string')) {
66
66
  throw new TypeError('Input must be a module, uri or ArrayBuffer');
67
67
  }
68
68
 
@@ -26,7 +26,7 @@ function withDefaultOptions(
26
26
  return {
27
27
  directory: FileDirectory.Cache,
28
28
  subDirectory: 'AudioAPI',
29
- fileNamePrefix: 'recording_',
29
+ fileNamePrefix: 'recording',
30
30
  channelCount: 2,
31
31
  format: FileFormat.M4A,
32
32
  batchDurationSeconds: 0,
@@ -7,21 +7,25 @@ export interface EventTypeWithValue {
7
7
  value: number;
8
8
  }
9
9
 
10
- interface OnInterruptionEventType {
11
- type: 'ended' | 'began';
10
+ export type InterruptionType = 'began' | 'ended';
11
+
12
+ export interface OnInterruptionEventType {
13
+ type: InterruptionType;
12
14
  shouldResume: boolean;
13
15
  }
14
16
 
15
- interface OnRouteChangeEventType {
16
- reason:
17
- | 'Unknown'
18
- | 'Override'
19
- | 'CategoryChange'
20
- | 'WakeFromSleep'
21
- | 'NewDeviceAvailable'
22
- | 'OldDeviceUnavailable'
23
- | 'ConfigurationChange'
24
- | 'NoSuitableRouteForCategory';
17
+ export type RouteChangeReason =
18
+ | 'Unknown'
19
+ | 'Override'
20
+ | 'CategoryChange'
21
+ | 'WakeFromSleep'
22
+ | 'NewDeviceAvailable'
23
+ | 'OldDeviceUnavailable'
24
+ | 'ConfigurationChange'
25
+ | 'NoSuitableRouteForCategory';
26
+
27
+ export interface OnRouteChangeEventType {
28
+ reason: RouteChangeReason;
25
29
  }
26
30
 
27
31
  export interface OnRecorderErrorEventType {
@@ -0,0 +1,2 @@
1
+ export { default as useAudioInput } from './useAudioInput';
2
+ export { default as useSystemVolume } from './useSystemVolume';
@@ -0,0 +1,93 @@
1
+ import { useCallback, useEffect, useMemo, useState } from 'react';
2
+
3
+ import { AudioManager } from '../api';
4
+ import { OnRouteChangeEventType, RouteChangeReason } from '../events/types';
5
+ import {
6
+ AudioDeviceInfo,
7
+ AudioDeviceList,
8
+ AudioDevicesInfo,
9
+ } from '../system/types';
10
+
11
+ const meaningfulReasons: RouteChangeReason[] = [
12
+ 'NewDeviceAvailable',
13
+ 'OldDeviceUnavailable',
14
+ // e.g. system picks a different device as current one is not suitable for the new configuration
15
+ 'CategoryChange',
16
+ 'ConfigurationChange',
17
+ ];
18
+
19
+ /**
20
+ * A hook that provides basic information and selection capabilities for audio
21
+ * input devices on the system. (iOS only currently). The hook will
22
+ * automatically listen for configuration changes and updates its state. If you
23
+ * need more granular control, consider using the AudioManager API directly.
24
+ *
25
+ * @returns An object containing audio input information and selection
26
+ * capabilities
27
+ */
28
+ export default function useAudioInput() {
29
+ const [availableInputs, setAvailableInputs] = useState<AudioDeviceList>([]);
30
+ const [currentInput, setCurrentInput] = useState<string | null>(null);
31
+
32
+ const onSelectInput = useCallback(async (device: AudioDeviceInfo) => {
33
+ const success = await AudioManager.setInputDevice(device.id);
34
+
35
+ if (success) {
36
+ setCurrentInput(device.id);
37
+ }
38
+
39
+ const devicesInfo: AudioDevicesInfo = await AudioManager.getDevicesInfo();
40
+ setAvailableInputs(devicesInfo.availableInputs);
41
+ }, []);
42
+
43
+ useEffect(() => {
44
+ async function fetchAvailableInputs() {
45
+ const audioDevices = await AudioManager.getDevicesInfo();
46
+ const currentDeviceId = audioDevices.currentInputs.length
47
+ ? audioDevices.currentInputs[0].id
48
+ : null;
49
+
50
+ setAvailableInputs(audioDevices.availableInputs);
51
+ setCurrentInput(currentDeviceId);
52
+ }
53
+
54
+ async function handleRouteChange(event: OnRouteChangeEventType) {
55
+ if (!meaningfulReasons.includes(event.reason)) {
56
+ return;
57
+ }
58
+
59
+ await fetchAvailableInputs();
60
+ }
61
+
62
+ const sub = AudioManager.addSystemEventListener(
63
+ 'routeChange',
64
+ handleRouteChange
65
+ );
66
+
67
+ fetchAvailableInputs();
68
+ return () => {
69
+ sub?.remove();
70
+ };
71
+ }, []);
72
+
73
+ return useMemo(
74
+ () => ({
75
+ /**
76
+ * The list of available audio input devices under current device
77
+ * configuration.
78
+ */
79
+ availableInputs,
80
+ /**
81
+ * The currently selected audio input device, or null if none is yet
82
+ * decided by the system.
83
+ */
84
+ currentInput: availableInputs.find((d) => d.id === currentInput) || null,
85
+ /**
86
+ * Selects the given device as the current input. Returns true if
87
+ * successful, throws otherwise.
88
+ */
89
+ onSelectInput,
90
+ }),
91
+ [availableInputs, currentInput, onSelectInput]
92
+ );
93
+ }
@@ -1,5 +1,6 @@
1
1
  import { useEffect, useState } from 'react';
2
- import AudioManager from '../system/AudioManager';
2
+
3
+ import { AudioManager } from '../api';
3
4
 
4
5
  export default function useSystemVolume() {
5
6
  const [volume, setVolume] = useState(0);
@@ -12,9 +13,9 @@ export default function useSystemVolume() {
12
13
  setVolume(parseFloat(e.value.toFixed(2)));
13
14
  }
14
15
  );
16
+
15
17
  return () => {
16
18
  listener?.remove();
17
-
18
19
  AudioManager.observeVolumeChanges(false);
19
20
  };
20
21
  }, []);
package/src/index.ts CHANGED
@@ -1 +1,6 @@
1
1
  export * from './api';
2
+
3
+ // Note: hooks are (and always should!) rely only on imports from './api'
4
+ // to be able to use them both in RN and Web environments.
5
+ // Thus they can/have to be exported here.
6
+ export * from './hooks';
@@ -34,6 +34,7 @@ interface Spec extends TurboModule {
34
34
 
35
35
  // Audio devices
36
36
  getDevicesInfo(): Promise<AudioDevicesInfo>;
37
+ setInputDevice(deviceId: string): Promise<boolean>;
37
38
 
38
39
  // Notification system
39
40
  showNotification(
@@ -45,6 +46,6 @@ interface Spec extends TurboModule {
45
46
  isNotificationActive(key: string): Promise<boolean>;
46
47
  }
47
48
 
48
- const NativeAudioAPIModule = TurboModuleRegistry.get<Spec>('AudioAPIModule');
49
+ const NativeAudioAPIModule = TurboModuleRegistry.get<Spec>('AudioAPIModule')!;
49
50
 
50
51
  export { NativeAudioAPIModule };
@@ -35,6 +35,7 @@ interface Spec extends TurboModule {
35
35
 
36
36
  // Audio devices
37
37
  getDevicesInfo(): Promise<AudioDevicesInfo>;
38
+ setInputDevice(deviceId: string): Promise<boolean>;
38
39
 
39
40
  // New notification system
40
41
  showNotification(
@@ -74,6 +75,7 @@ const NativeAudioAPIModule: Spec = {
74
75
  currentInputs: [],
75
76
  currentOutputs: [],
76
77
  }),
78
+ setInputDevice: mockAsync(true),
77
79
  showNotification: mockAsync({ success: true }),
78
80
  hideNotification: mockAsync({ success: true }),
79
81
  isNotificationActive: mockAsync(false),
@@ -94,6 +94,10 @@ class AudioManager implements IAudioManager {
94
94
  async getDevicesInfo(): Promise<AudioDevicesInfo> {
95
95
  return NativeAudioAPIModule.getDevicesInfo();
96
96
  }
97
+
98
+ async setInputDevice(deviceId: string): Promise<boolean> {
99
+ return NativeAudioAPIModule.setInputDevice(deviceId);
100
+ }
97
101
  }
98
102
 
99
103
  export default new AudioManager();
@@ -24,8 +24,8 @@ export type IOSOption =
24
24
  | 'duckOthers'
25
25
  | 'allowAirPlay'
26
26
  | 'mixWithOthers'
27
- | 'allowBluetooth'
28
27
  | 'defaultToSpeaker'
28
+ | 'allowBluetoothHFP'
29
29
  | 'allowBluetoothA2DP'
30
30
  | 'overrideMutedMicrophoneInterruption'
31
31
  | 'interruptSpokenAudioAndMixWithOthers';
@@ -40,6 +40,7 @@ export interface SessionOptions {
40
40
  export type PermissionStatus = 'Undetermined' | 'Denied' | 'Granted';
41
41
 
42
42
  export interface AudioDeviceInfo {
43
+ id: string;
43
44
  name: string;
44
45
  category: string;
45
46
  }
@@ -70,4 +71,5 @@ export interface IAudioManager {
70
71
  requestNotificationPermissions(): Promise<PermissionStatus>;
71
72
  checkNotificationPermissions(): Promise<PermissionStatus>;
72
73
  getDevicesInfo(): Promise<AudioDevicesInfo>;
74
+ setInputDevice(deviceId: string): Promise<boolean>;
73
75
  }
@@ -22,6 +22,7 @@ class AudioManager implements IAudioManager {
22
22
  checkRecordingPermissions = mockAsync('Granted' as PermissionStatus);
23
23
  requestNotificationPermissions = mockAsync('Granted' as PermissionStatus);
24
24
  checkNotificationPermissions = mockAsync('Granted' as PermissionStatus);
25
+ setInputDevice = mockAsync(true);
25
26
  getDevicesInfo = mockAsync({
26
27
  availableInputs: [],
27
28
  availableOutputs: [],