react-native-audio-api 0.11.0-nightly-b30bac9-20260114 → 0.11.0

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 (173) hide show
  1. package/android/src/main/cpp/audioapi/android/core/AndroidAudioRecorder.cpp +3 -10
  2. package/android/src/main/cpp/audioapi/android/core/AudioPlayer.cpp +0 -4
  3. package/android/src/main/java/com/swmansion/audioapi/AudioAPIModule.kt +4 -83
  4. package/android/src/main/java/com/swmansion/audioapi/system/CentralizedForegroundService.kt +14 -29
  5. package/android/src/main/java/com/swmansion/audioapi/system/ForegroundServiceManager.kt +10 -9
  6. package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionManager.kt +10 -51
  7. package/android/src/main/java/com/swmansion/audioapi/system/notification/BaseNotification.kt +6 -14
  8. package/android/src/main/java/com/swmansion/audioapi/system/notification/NotificationRegistry.kt +79 -60
  9. package/android/src/main/java/com/swmansion/audioapi/system/notification/PlaybackNotification.kt +249 -411
  10. package/android/src/main/java/com/swmansion/audioapi/system/notification/PlaybackNotificationReceiver.kt +8 -3
  11. package/android/src/main/java/com/swmansion/audioapi/system/notification/RecordingNotification.kt +240 -222
  12. package/android/src/main/java/com/swmansion/audioapi/system/notification/RecordingNotificationReceiver.kt +11 -22
  13. package/android/src/main/java/com/swmansion/audioapi/system/notification/state/RecordingNotificationState.kt +24 -0
  14. package/android/src/main/res/layout/btn_round_ripple.xml +9 -0
  15. package/android/src/main/res/layout/notification_collapsed.xml +45 -0
  16. package/android/src/main/res/layout/notification_expanded.xml +44 -0
  17. package/android/src/oldarch/NativeAudioAPIModuleSpec.java +1 -13
  18. package/common/cpp/audioapi/core/utils/AudioFileWriter.cpp +1 -1
  19. package/ios/audioapi/ios/AudioAPIModule.mm +5 -48
  20. package/ios/audioapi/ios/system/notification/BaseNotification.h +0 -7
  21. package/ios/audioapi/ios/system/notification/NotificationRegistry.h +5 -25
  22. package/ios/audioapi/ios/system/notification/NotificationRegistry.mm +19 -64
  23. package/ios/audioapi/ios/system/notification/PlaybackNotification.mm +4 -15
  24. package/lib/commonjs/AudioAPIModule/AudioAPIModule.js +2 -1
  25. package/lib/commonjs/AudioAPIModule/AudioAPIModule.js.map +1 -1
  26. package/lib/commonjs/api.js +1 -29
  27. package/lib/commonjs/api.js.map +1 -1
  28. package/lib/commonjs/core/AudioDecoder.js +42 -16
  29. package/lib/commonjs/core/AudioDecoder.js.map +1 -1
  30. package/lib/commonjs/core/AudioRecorder.js +2 -1
  31. package/lib/commonjs/core/AudioRecorder.js.map +1 -1
  32. package/lib/commonjs/core/AudioStretcher.js +2 -1
  33. package/lib/commonjs/core/AudioStretcher.js.map +1 -1
  34. package/lib/commonjs/core/BaseAudioContext.js +2 -5
  35. package/lib/commonjs/core/BaseAudioContext.js.map +1 -1
  36. package/lib/commonjs/errors/AudioApiError.js +14 -0
  37. package/lib/commonjs/errors/AudioApiError.js.map +1 -0
  38. package/lib/commonjs/errors/index.js +7 -0
  39. package/lib/commonjs/errors/index.js.map +1 -1
  40. package/lib/commonjs/specs/NativeAudioAPIModule.js.map +1 -1
  41. package/lib/commonjs/specs/NativeAudioAPIModule.web.js +0 -9
  42. package/lib/commonjs/specs/NativeAudioAPIModule.web.js.map +1 -1
  43. package/lib/commonjs/system/notification/PlaybackNotificationManager.js +40 -85
  44. package/lib/commonjs/system/notification/PlaybackNotificationManager.js.map +1 -1
  45. package/lib/commonjs/system/notification/RecordingNotificationManager.ios.js +51 -0
  46. package/lib/commonjs/system/notification/RecordingNotificationManager.ios.js.map +1 -0
  47. package/lib/commonjs/system/notification/RecordingNotificationManager.js +30 -144
  48. package/lib/commonjs/system/notification/RecordingNotificationManager.js.map +1 -1
  49. package/lib/commonjs/system/notification/index.js +1 -9
  50. package/lib/commonjs/system/notification/index.js.map +1 -1
  51. package/lib/commonjs/utils/index.js +3 -2
  52. package/lib/commonjs/utils/index.js.map +1 -1
  53. package/lib/commonjs/utils/paths.js +18 -0
  54. package/lib/commonjs/utils/paths.js.map +1 -0
  55. package/lib/commonjs/web-core/AudioContext.js +20 -11
  56. package/lib/commonjs/web-core/AudioContext.js.map +1 -1
  57. package/lib/commonjs/web-system/notification/PlaybackNotificationManager.js +0 -1
  58. package/lib/commonjs/web-system/notification/PlaybackNotificationManager.js.map +1 -1
  59. package/lib/commonjs/web-system/notification/RecordingNotificationManager.js +1 -6
  60. package/lib/commonjs/web-system/notification/RecordingNotificationManager.js.map +1 -1
  61. package/lib/module/AudioAPIModule/AudioAPIModule.js +2 -1
  62. package/lib/module/AudioAPIModule/AudioAPIModule.js.map +1 -1
  63. package/lib/module/api.js +3 -2
  64. package/lib/module/api.js.map +1 -1
  65. package/lib/module/core/AudioDecoder.js +42 -16
  66. package/lib/module/core/AudioDecoder.js.map +1 -1
  67. package/lib/module/core/AudioRecorder.js +3 -1
  68. package/lib/module/core/AudioRecorder.js.map +1 -1
  69. package/lib/module/core/AudioStretcher.js +2 -1
  70. package/lib/module/core/AudioStretcher.js.map +1 -1
  71. package/lib/module/core/BaseAudioContext.js +2 -5
  72. package/lib/module/core/BaseAudioContext.js.map +1 -1
  73. package/lib/module/errors/AudioApiError.js +10 -0
  74. package/lib/module/errors/AudioApiError.js.map +1 -0
  75. package/lib/module/errors/index.js +1 -0
  76. package/lib/module/errors/index.js.map +1 -1
  77. package/lib/module/specs/NativeAudioAPIModule.js.map +1 -1
  78. package/lib/module/specs/NativeAudioAPIModule.web.js +0 -9
  79. package/lib/module/specs/NativeAudioAPIModule.web.js.map +1 -1
  80. package/lib/module/system/notification/PlaybackNotificationManager.js +40 -85
  81. package/lib/module/system/notification/PlaybackNotificationManager.js.map +1 -1
  82. package/lib/module/system/notification/RecordingNotificationManager.ios.js +47 -0
  83. package/lib/module/system/notification/RecordingNotificationManager.ios.js.map +1 -0
  84. package/lib/module/system/notification/RecordingNotificationManager.js +30 -144
  85. package/lib/module/system/notification/RecordingNotificationManager.js.map +1 -1
  86. package/lib/module/system/notification/index.js +1 -2
  87. package/lib/module/system/notification/index.js.map +1 -1
  88. package/lib/module/utils/index.js +3 -2
  89. package/lib/module/utils/index.js.map +1 -1
  90. package/lib/module/utils/paths.js +12 -0
  91. package/lib/module/utils/paths.js.map +1 -0
  92. package/lib/module/web-core/AudioContext.js +20 -11
  93. package/lib/module/web-core/AudioContext.js.map +1 -1
  94. package/lib/module/web-system/notification/PlaybackNotificationManager.js +0 -1
  95. package/lib/module/web-system/notification/PlaybackNotificationManager.js.map +1 -1
  96. package/lib/module/web-system/notification/RecordingNotificationManager.js +1 -6
  97. package/lib/module/web-system/notification/RecordingNotificationManager.js.map +1 -1
  98. package/lib/typescript/AudioAPIModule/AudioAPIModule.d.ts.map +1 -1
  99. package/lib/typescript/api.d.ts +3 -2
  100. package/lib/typescript/api.d.ts.map +1 -1
  101. package/lib/typescript/core/AudioDecoder.d.ts +2 -1
  102. package/lib/typescript/core/AudioDecoder.d.ts.map +1 -1
  103. package/lib/typescript/core/AudioRecorder.d.ts.map +1 -1
  104. package/lib/typescript/core/AudioStretcher.d.ts.map +1 -1
  105. package/lib/typescript/core/BaseAudioContext.d.ts +2 -2
  106. package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
  107. package/lib/typescript/errors/AudioApiError.d.ts +5 -0
  108. package/lib/typescript/errors/AudioApiError.d.ts.map +1 -0
  109. package/lib/typescript/errors/index.d.ts +1 -0
  110. package/lib/typescript/errors/index.d.ts.map +1 -1
  111. package/lib/typescript/interfaces.d.ts +1 -1
  112. package/lib/typescript/interfaces.d.ts.map +1 -1
  113. package/lib/typescript/specs/NativeAudioAPIModule.d.ts +2 -5
  114. package/lib/typescript/specs/NativeAudioAPIModule.d.ts.map +1 -1
  115. package/lib/typescript/specs/NativeAudioAPIModule.web.d.ts +1 -4
  116. package/lib/typescript/specs/NativeAudioAPIModule.web.d.ts.map +1 -1
  117. package/lib/typescript/system/notification/PlaybackNotificationManager.d.ts +32 -9
  118. package/lib/typescript/system/notification/PlaybackNotificationManager.d.ts.map +1 -1
  119. package/lib/typescript/system/notification/RecordingNotificationManager.d.ts +26 -13
  120. package/lib/typescript/system/notification/RecordingNotificationManager.d.ts.map +1 -1
  121. package/lib/typescript/system/notification/RecordingNotificationManager.ios.d.ts +36 -0
  122. package/lib/typescript/system/notification/RecordingNotificationManager.ios.d.ts.map +1 -0
  123. package/lib/typescript/system/notification/index.d.ts +0 -1
  124. package/lib/typescript/system/notification/index.d.ts.map +1 -1
  125. package/lib/typescript/system/notification/types.d.ts +12 -22
  126. package/lib/typescript/system/notification/types.d.ts.map +1 -1
  127. package/lib/typescript/types.d.ts +1 -0
  128. package/lib/typescript/types.d.ts.map +1 -1
  129. package/lib/typescript/utils/index.d.ts.map +1 -1
  130. package/lib/typescript/utils/paths.d.ts +4 -0
  131. package/lib/typescript/utils/paths.d.ts.map +1 -0
  132. package/lib/typescript/web-core/AudioContext.d.ts +8 -9
  133. package/lib/typescript/web-core/AudioContext.d.ts.map +1 -1
  134. package/lib/typescript/web-core/BaseAudioContext.d.ts +6 -7
  135. package/lib/typescript/web-core/BaseAudioContext.d.ts.map +1 -1
  136. package/lib/typescript/web-system/notification/PlaybackNotificationManager.d.ts +1 -2
  137. package/lib/typescript/web-system/notification/PlaybackNotificationManager.d.ts.map +1 -1
  138. package/lib/typescript/web-system/notification/RecordingNotificationManager.d.ts +2 -7
  139. package/lib/typescript/web-system/notification/RecordingNotificationManager.d.ts.map +1 -1
  140. package/package.json +1 -1
  141. package/src/AudioAPIModule/AudioAPIModule.ts +2 -1
  142. package/src/api.ts +2 -8
  143. package/src/core/AudioDecoder.ts +91 -21
  144. package/src/core/AudioRecorder.ts +2 -1
  145. package/src/core/AudioStretcher.ts +2 -1
  146. package/src/core/BaseAudioContext.ts +4 -6
  147. package/src/errors/AudioApiError.ts +8 -0
  148. package/src/errors/index.ts +1 -0
  149. package/src/interfaces.ts +1 -1
  150. package/src/specs/NativeAudioAPIModule.ts +5 -15
  151. package/src/specs/NativeAudioAPIModule.web.ts +1 -12
  152. package/src/system/notification/PlaybackNotificationManager.ts +42 -117
  153. package/src/system/notification/RecordingNotificationManager.ios.ts +65 -0
  154. package/src/system/notification/RecordingNotificationManager.ts +33 -183
  155. package/src/system/notification/index.ts +0 -1
  156. package/src/system/notification/types.ts +15 -37
  157. package/src/types.ts +2 -0
  158. package/src/utils/index.ts +3 -2
  159. package/src/utils/paths.ts +11 -0
  160. package/src/web-core/AudioContext.tsx +34 -19
  161. package/src/web-core/BaseAudioContext.tsx +9 -7
  162. package/src/web-system/notification/PlaybackNotificationManager.ts +1 -7
  163. package/src/web-system/notification/RecordingNotificationManager.ts +1 -16
  164. package/android/src/main/java/com/swmansion/audioapi/core/NativeAudioPlayer.kt +0 -26
  165. package/android/src/main/java/com/swmansion/audioapi/core/NativeAudioRecorder.kt +0 -26
  166. package/android/src/main/java/com/swmansion/audioapi/system/notification/SimpleNotification.kt +0 -119
  167. package/lib/commonjs/system/notification/SimpleNotificationManager.js +0 -125
  168. package/lib/commonjs/system/notification/SimpleNotificationManager.js.map +0 -1
  169. package/lib/module/system/notification/SimpleNotificationManager.js +0 -121
  170. package/lib/module/system/notification/SimpleNotificationManager.js.map +0 -1
  171. package/lib/typescript/system/notification/SimpleNotificationManager.d.ts +0 -21
  172. package/lib/typescript/system/notification/SimpleNotificationManager.d.ts.map +0 -1
  173. package/src/system/notification/SimpleNotificationManager.ts +0 -175
@@ -1,5 +1,14 @@
1
+ import { Image } from 'react-native';
2
+
1
3
  import { IAudioDecoder } from '../interfaces';
4
+ import { DecodeDataInput } from '../types';
5
+ import {
6
+ isBase64Source,
7
+ isDataBlobString,
8
+ isRemoteSource,
9
+ } from '../utils/paths';
2
10
  import AudioBuffer from './AudioBuffer';
11
+ import { AudioApiError } from '../errors';
3
12
 
4
13
  class AudioDecoder {
5
14
  private static instance: AudioDecoder | null = null;
@@ -9,35 +18,91 @@ class AudioDecoder {
9
18
  this.decoder = global.createAudioDecoder();
10
19
  }
11
20
 
21
+ private async decodeAudioDataImplementation(
22
+ input: DecodeDataInput,
23
+ sampleRate?: number,
24
+ fetchOptions?: RequestInit
25
+ ): Promise<AudioBuffer | null | undefined> {
26
+ if (input instanceof ArrayBuffer) {
27
+ const buffer = await this.decoder.decodeWithMemoryBlock(
28
+ new Uint8Array(input),
29
+ sampleRate ?? 0
30
+ );
31
+ return new AudioBuffer(buffer);
32
+ }
33
+
34
+ const stringSource =
35
+ typeof input === 'number' ? Image.resolveAssetSource(input).uri : input;
36
+
37
+ // input is data:audio/...;base64,...
38
+ if (isBase64Source(stringSource)) {
39
+ throw new AudioApiError(
40
+ 'Base64 source decoding is not currently supported, to decode raw PCM base64 strings use decodePCMInBase64 method.'
41
+ );
42
+ }
43
+
44
+ // input is blob:...
45
+ if (isDataBlobString(stringSource)) {
46
+ throw new AudioApiError(
47
+ 'Data Blob string decoding is not currently supported.'
48
+ );
49
+ }
50
+
51
+ // input is http(s)://...
52
+ if (isRemoteSource(stringSource)) {
53
+ const arrayBuffer = await fetch(stringSource, fetchOptions).then((res) =>
54
+ res.arrayBuffer()
55
+ );
56
+
57
+ const buffer = await this.decoder.decodeWithMemoryBlock(
58
+ new Uint8Array(arrayBuffer),
59
+ sampleRate ?? 0
60
+ );
61
+
62
+ return new AudioBuffer(buffer);
63
+ }
64
+
65
+ if (!(typeof input === 'string')) {
66
+ throw new TypeError('Input must be a module, uri or ArrayBuffer');
67
+ }
68
+
69
+ // Local file path
70
+ const filePath = stringSource.startsWith('file://')
71
+ ? stringSource.replace('file://', '')
72
+ : stringSource;
73
+
74
+ const buffer = await this.decoder.decodeWithFilePath(
75
+ filePath,
76
+ sampleRate ?? 0
77
+ );
78
+
79
+ return new AudioBuffer(buffer);
80
+ }
81
+
12
82
  public static getInstance(): AudioDecoder {
13
83
  if (!AudioDecoder.instance) {
14
84
  AudioDecoder.instance = new AudioDecoder();
15
85
  }
86
+
16
87
  return AudioDecoder.instance;
17
88
  }
18
89
 
19
90
  public async decodeAudioDataInstance(
20
- input: string | ArrayBuffer,
21
- sampleRate?: number
91
+ input: DecodeDataInput,
92
+ sampleRate?: number,
93
+ fetchOptions?: RequestInit
22
94
  ): Promise<AudioBuffer> {
23
- let buffer;
24
- if (typeof input === 'string') {
25
- // Remove the file:// prefix if it exists
26
- if (input.startsWith('file://')) {
27
- input = input.replace('file://', '');
28
- }
29
- buffer = await this.decoder.decodeWithFilePath(input, sampleRate ?? 0);
30
- } else if (input instanceof ArrayBuffer) {
31
- buffer = await this.decoder.decodeWithMemoryBlock(
32
- new Uint8Array(input),
33
- sampleRate ?? 0
34
- );
35
- }
95
+ const audioBuffer = await this.decodeAudioDataImplementation(
96
+ input,
97
+ sampleRate,
98
+ fetchOptions
99
+ );
36
100
 
37
- if (!buffer) {
38
- throw new Error('Unsupported input type or failed to decode audio');
101
+ if (!audioBuffer) {
102
+ throw new AudioApiError('Failed to decode audio data.');
39
103
  }
40
- return new AudioBuffer(buffer);
104
+
105
+ return audioBuffer;
41
106
  }
42
107
 
43
108
  public async decodePCMInBase64Instance(
@@ -57,10 +122,15 @@ class AudioDecoder {
57
122
  }
58
123
 
59
124
  export async function decodeAudioData(
60
- input: string | ArrayBuffer,
61
- sampleRate?: number
125
+ input: DecodeDataInput,
126
+ sampleRate?: number,
127
+ fetchOptions?: RequestInit
62
128
  ): Promise<AudioBuffer> {
63
- return AudioDecoder.getInstance().decodeAudioDataInstance(input, sampleRate);
129
+ return AudioDecoder.getInstance().decodeAudioDataInstance(
130
+ input,
131
+ sampleRate,
132
+ fetchOptions
133
+ );
64
134
  }
65
135
 
66
136
  export async function decodePCMInBase64(
@@ -15,6 +15,7 @@ import {
15
15
  import FilePreset from '../utils/filePresets';
16
16
  import AudioBuffer from './AudioBuffer';
17
17
  import RecorderAdapterNode from './RecorderAdapterNode';
18
+ import { AudioApiError } from '../errors';
18
19
 
19
20
  // Enforces default options, making sure that all properties are defined
20
21
  // for the contract with native code.
@@ -107,7 +108,7 @@ export default class AudioRecorder {
107
108
  */
108
109
  connect(node: RecorderAdapterNode): void {
109
110
  if (node.wasConnected) {
110
- throw new Error(
111
+ throw new AudioApiError(
111
112
  'RecorderAdapterNode cannot be connected more than once. Refer to the documentation for more details.'
112
113
  );
113
114
  }
@@ -1,5 +1,6 @@
1
1
  import { IAudioStretcher } from '../interfaces';
2
2
  import AudioBuffer from './AudioBuffer';
3
+ import { AudioApiError } from '../errors';
3
4
 
4
5
  class AudioStretcher {
5
6
  private static instance: AudioStretcher | null = null;
@@ -26,7 +27,7 @@ class AudioStretcher {
26
27
  );
27
28
 
28
29
  if (!buffer) {
29
- throw new Error('Failed to change playback speed');
30
+ throw new AudioApiError('Failed to change playback speed');
30
31
  }
31
32
  return new AudioBuffer(buffer);
32
33
  }
@@ -10,6 +10,7 @@ import {
10
10
  AudioWorkletRuntime,
11
11
  ContextState,
12
12
  ConvolverNodeOptions,
13
+ DecodeDataInput,
13
14
  IIRFilterNodeOptions,
14
15
  PeriodicWaveConstraints,
15
16
  } from '../types';
@@ -56,13 +57,10 @@ export default class BaseAudioContext {
56
57
  }
57
58
 
58
59
  public async decodeAudioData(
59
- input: string | ArrayBuffer,
60
- sampleRate?: number
60
+ input: DecodeDataInput,
61
+ fetchOptions?: RequestInit
61
62
  ): Promise<AudioBuffer> {
62
- if (!(typeof input === 'string' || input instanceof ArrayBuffer)) {
63
- throw new TypeError('Input must be a string or ArrayBuffer');
64
- }
65
- return await decodeAudioData(input, sampleRate ?? this.sampleRate);
63
+ return await decodeAudioData(input, this.sampleRate, fetchOptions);
66
64
  }
67
65
 
68
66
  public async decodePCMInBase64(
@@ -0,0 +1,8 @@
1
+ class AudioApiError extends Error {
2
+ constructor(message: string) {
3
+ super(message);
4
+ this.name = 'AudioApiError';
5
+ }
6
+ }
7
+
8
+ export default AudioApiError;
@@ -3,3 +3,4 @@ export { default as InvalidAccessError } from './InvalidAccessError';
3
3
  export { default as InvalidStateError } from './InvalidStateError';
4
4
  export { default as RangeError } from './RangeError';
5
5
  export { default as NotSupportedError } from './NotSupportedError';
6
+ export { default as AudioApiError } from './AudioApiError';
package/src/interfaces.ts CHANGED
@@ -8,9 +8,9 @@ import type {
8
8
  ContextState,
9
9
  FileInfo,
10
10
  OscillatorType,
11
+ OverSampleType,
11
12
  Result,
12
13
  WindowType,
13
- OverSampleType,
14
14
  } from './types';
15
15
 
16
16
  // IMPORTANT: use only IClass, because it is a part of contract between cpp host object and js layer
@@ -1,11 +1,9 @@
1
1
  'use strict';
2
-
3
- import { TurboModuleRegistry, TurboModule } from 'react-native';
2
+ import type { TurboModule } from 'react-native';
3
+ import { TurboModuleRegistry } from 'react-native';
4
4
  import { AudioDevicesInfo, PermissionStatus } from '../system/types';
5
5
 
6
- type OptionsMap = {
7
- [key: string]: string | boolean | number | undefined;
8
- };
6
+ type OptionsMap = { [key: string]: string | boolean | number | undefined };
9
7
  type NotificationOpResponse = { success: boolean; error?: string };
10
8
  type NotificationType = 'playback' | 'recording' | 'simple';
11
9
 
@@ -37,21 +35,13 @@ interface Spec extends TurboModule {
37
35
  // Audio devices
38
36
  getDevicesInfo(): Promise<AudioDevicesInfo>;
39
37
 
40
- // New notification system
41
- registerNotification(
42
- type: NotificationType,
43
- key: string
44
- ): Promise<NotificationOpResponse>;
38
+ // Notification system
45
39
  showNotification(
46
- key: string,
47
- options: OptionsMap
48
- ): Promise<NotificationOpResponse>;
49
- updateNotification(
40
+ type: NotificationType,
50
41
  key: string,
51
42
  options: OptionsMap
52
43
  ): Promise<NotificationOpResponse>;
53
44
  hideNotification(key: string): Promise<NotificationOpResponse>;
54
- unregisterNotification(key: string): Promise<NotificationOpResponse>;
55
45
  isNotificationActive(key: string): Promise<boolean>;
56
46
  }
57
47
 
@@ -37,20 +37,12 @@ interface Spec extends TurboModule {
37
37
  getDevicesInfo(): Promise<AudioDevicesInfo>;
38
38
 
39
39
  // New notification system
40
- registerNotification(
41
- type: NotificationType,
42
- key: string
43
- ): Promise<NotificationOpResponse>;
44
40
  showNotification(
45
- key: string,
46
- options: OptionsMap
47
- ): Promise<NotificationOpResponse>;
48
- updateNotification(
41
+ type: NotificationType,
49
42
  key: string,
50
43
  options: OptionsMap
51
44
  ): Promise<NotificationOpResponse>;
52
45
  hideNotification(key: string): Promise<NotificationOpResponse>;
53
- unregisterNotification(key: string): Promise<NotificationOpResponse>;
54
46
  isNotificationActive(key: string): Promise<boolean>;
55
47
  }
56
48
 
@@ -82,11 +74,8 @@ const NativeAudioAPIModule: Spec = {
82
74
  currentInputs: [],
83
75
  currentOutputs: [],
84
76
  }),
85
- registerNotification: mockAsync({ success: true }),
86
77
  showNotification: mockAsync({ success: true }),
87
- updateNotification: mockAsync({ success: true }),
88
78
  hideNotification: mockAsync({ success: true }),
89
- unregisterNotification: mockAsync({ success: true }),
90
79
  isNotificationActive: mockAsync(false),
91
80
  };
92
81
 
@@ -7,101 +7,50 @@ import type {
7
7
  PlaybackNotificationEventName,
8
8
  PlaybackNotificationInfo,
9
9
  } from './types';
10
+ import { AudioApiError } from '../../errors';
10
11
 
11
- /// Manager for media playback notifications with controls and MediaSession integration.
12
12
  class PlaybackNotificationManager
13
13
  implements
14
- NotificationManager<
15
- PlaybackNotificationInfo,
16
- PlaybackNotificationInfo,
17
- PlaybackNotificationEventName
18
- >
14
+ NotificationManager<PlaybackNotificationInfo, PlaybackNotificationEventName>
19
15
  {
20
16
  private notificationKey = 'playback';
21
- private isRegistered_ = false;
22
- private isShown_ = false;
23
17
  private audioEventEmitter: AudioEventEmitter;
24
18
 
25
19
  constructor() {
26
20
  this.audioEventEmitter = new AudioEventEmitter(global.AudioEventEmitter);
27
21
  }
28
22
 
29
- /// Register the playback notification (must be called before showing).
30
- async register(): Promise<void> {
31
- if (this.isRegistered_) {
32
- console.warn('PlaybackNotification is already registered');
33
- return;
34
- }
35
-
36
- if (!NativeAudioAPIModule) {
37
- throw new Error('NativeAudioAPIModule is not available');
38
- }
39
-
40
- const result = await NativeAudioAPIModule.registerNotification(
41
- 'playback',
42
- this.notificationKey
43
- );
44
-
45
- if (result.error) {
46
- throw new Error(result.error);
47
- }
48
-
49
- this.isRegistered_ = true;
50
- }
51
-
52
- /// Show the notification with initial metadata.
23
+ /**
24
+ * Show the notification with metadata or update if already visible.
25
+ * Automatically creates the notification on first call.
26
+ *
27
+ * @param info - The info to be displayed.
28
+ * @returns Promise that resolves after creating notification.
29
+ */
53
30
  async show(info: PlaybackNotificationInfo): Promise<void> {
54
- if (!this.isRegistered_) {
55
- throw new Error(
56
- 'PlaybackNotification must be registered before showing. Call register() first.'
57
- );
58
- }
59
-
60
31
  if (!NativeAudioAPIModule) {
61
- throw new Error('NativeAudioAPIModule is not available');
32
+ throw new AudioApiError('NativeAudioAPIModule is not available');
62
33
  }
63
34
 
64
35
  const result = await NativeAudioAPIModule.showNotification(
36
+ 'playback',
65
37
  this.notificationKey,
66
38
  info as Record<string, string | number | boolean | undefined>
67
39
  );
68
40
 
69
41
  if (result.error) {
70
- throw new Error(result.error);
71
- }
72
-
73
- this.isShown_ = true;
74
- }
75
-
76
- /// Update the notification with new metadata or state.
77
- async update(info: PlaybackNotificationInfo): Promise<void> {
78
- if (!this.isShown_) {
79
- console.warn('PlaybackNotification is not shown. Call show() first.');
80
- return;
81
- }
82
-
83
- if (!NativeAudioAPIModule) {
84
- throw new Error('NativeAudioAPIModule is not available');
85
- }
86
-
87
- const result = await NativeAudioAPIModule.updateNotification(
88
- this.notificationKey,
89
- info as Record<string, string | number | boolean | undefined>
90
- );
91
-
92
- if (result.error) {
93
- throw new Error(result.error);
42
+ throw new AudioApiError(result.error);
94
43
  }
95
44
  }
96
45
 
97
- /// Hide the notification (can be shown again later).
46
+ /**
47
+ * Hide the notification.
48
+ *
49
+ * @returns Promise that resolves after hiding notification.
50
+ */
98
51
  async hide(): Promise<void> {
99
- if (!this.isShown_) {
100
- return;
101
- }
102
-
103
52
  if (!NativeAudioAPIModule) {
104
- throw new Error('NativeAudioAPIModule is not available');
53
+ throw new AudioApiError('NativeAudioAPIModule is not available');
105
54
  }
106
55
 
107
56
  const result = await NativeAudioAPIModule.hideNotification(
@@ -109,63 +58,42 @@ class PlaybackNotificationManager
109
58
  );
110
59
 
111
60
  if (result.error) {
112
- throw new Error(result.error);
113
- }
114
-
115
- this.isShown_ = false;
116
- }
117
-
118
- /// Unregister the notification (must register again to use).
119
- async unregister(): Promise<void> {
120
- if (!this.isRegistered_) {
121
- return;
122
- }
123
-
124
- if (this.isShown_) {
125
- await this.hide();
126
- }
127
-
128
- if (!NativeAudioAPIModule) {
129
- throw new Error('NativeAudioAPIModule is not available');
130
- }
131
-
132
- const result = await NativeAudioAPIModule.unregisterNotification(
133
- this.notificationKey
134
- );
135
-
136
- if (result.error) {
137
- throw new Error(result.error);
61
+ throw new AudioApiError(result.error);
138
62
  }
139
-
140
- this.isRegistered_ = false;
141
63
  }
142
64
 
143
- /// Enable or disable a specific playback control.
65
+ /**
66
+ * Enable or disable a specific playback control.
67
+ *
68
+ * @param control - The control to enable or disable on the notification.
69
+ * @param enabled - Whether to enable (true) or disable (false) the control.
70
+ * @returns Promise that resolves after showing modified notification.
71
+ */
144
72
  async enableControl(
145
73
  control: PlaybackControlName,
146
74
  enabled: boolean
147
75
  ): Promise<void> {
148
- if (!this.isRegistered_) {
149
- console.warn('PlaybackNotification is not registered');
150
- return;
151
- }
152
-
153
76
  if (!NativeAudioAPIModule) {
154
- throw new Error('NativeAudioAPIModule is not available');
77
+ throw new AudioApiError('NativeAudioAPIModule is not available');
155
78
  }
156
79
 
157
80
  const params = { control, enabled };
158
- const result = await NativeAudioAPIModule.updateNotification(
81
+ const result = await NativeAudioAPIModule.showNotification(
82
+ 'playback',
159
83
  this.notificationKey,
160
84
  params as Record<string, string | number | boolean | undefined>
161
85
  );
162
86
 
163
87
  if (result.error) {
164
- throw new Error(result.error);
88
+ throw new AudioApiError(result.error);
165
89
  }
166
90
  }
167
91
 
168
- /// Check if the notification is currently active.
92
+ /**
93
+ * Check if the notification is currently active.
94
+ *
95
+ * @returns Promise that resolves to whether notification is active.
96
+ */
169
97
  async isActive(): Promise<boolean> {
170
98
  if (!NativeAudioAPIModule) {
171
99
  return false;
@@ -176,22 +104,19 @@ class PlaybackNotificationManager
176
104
  );
177
105
  }
178
106
 
179
- isRegistered(): boolean {
180
- return this.isRegistered_;
181
- }
182
-
183
- /// Add an event listener for notification actions.
107
+ /**
108
+ * Add an event listener for notification actions.
109
+ *
110
+ * @param eventName - The event name to listen for.
111
+ * @param callback - The callback to invoke on event.
112
+ * @returns Class that represents the subscription.
113
+ */
184
114
  addEventListener<T extends PlaybackNotificationEventName>(
185
115
  eventName: T,
186
116
  callback: (event: NotificationEvents[T]) => void
187
117
  ): AudioEventSubscription {
188
118
  return this.audioEventEmitter.addAudioEventListener(eventName, callback);
189
119
  }
190
-
191
- /** Remove an event listener. */
192
- removeEventListener(subscription: AudioEventSubscription): void {
193
- subscription.remove();
194
- }
195
120
  }
196
121
 
197
122
  export default new PlaybackNotificationManager();
@@ -0,0 +1,65 @@
1
+ import { AudioEventEmitter, AudioEventSubscription } from '../../events';
2
+ import type {
3
+ NotificationManager,
4
+ RecordingNotificationEvent,
5
+ RecordingNotificationEventName,
6
+ RecordingNotificationInfo,
7
+ } from './types';
8
+
9
+ class RecordingNotificationManager
10
+ implements
11
+ NotificationManager<
12
+ RecordingNotificationInfo,
13
+ RecordingNotificationEventName
14
+ >
15
+ {
16
+ private audioEventEmitter: AudioEventEmitter;
17
+
18
+ constructor() {
19
+ this.audioEventEmitter = new AudioEventEmitter(global.AudioEventEmitter);
20
+ console.warn(
21
+ 'RecordingNotificationManager is not implemented on iOS. Any calls to it will be no-ops.'
22
+ );
23
+ }
24
+
25
+ /**
26
+ * Show the notification with metadata or update if already visible.
27
+ *
28
+ * @param info - The info to be displayed.
29
+ * @returns Promise that resolves after creating notification.
30
+ */
31
+ async show(_info: RecordingNotificationInfo): Promise<void> {}
32
+
33
+ /**
34
+ * Hide the notification.
35
+ *
36
+ * @returns Promise that resolves after hiding notification.
37
+ */
38
+ async hide(): Promise<void> {}
39
+
40
+ /**
41
+ * Check if the notification is currently active.
42
+ *
43
+ * @returns Promise that resolves to whether notification is active.
44
+ */
45
+ // eslint-disable-next-line @typescript-eslint/require-await
46
+ async isActive(): Promise<boolean> {
47
+ return false;
48
+ }
49
+
50
+ /**
51
+ * Add an event listener for notification actions.
52
+ *
53
+ * @param eventName - The event name to listen for.
54
+ * @param callback - The callback to invoke on event.
55
+ * @returns Promise that resolves to whether notification is active.
56
+ */
57
+ addEventListener<T extends RecordingNotificationEventName>(
58
+ eventName: T,
59
+ callback: (event: RecordingNotificationEvent[T]) => void
60
+ ): AudioEventSubscription {
61
+ return this.audioEventEmitter.addAudioEventListener(eventName, callback);
62
+ }
63
+ }
64
+
65
+ export default new RecordingNotificationManager();